簡體   English   中英

Haskell:如何為 (BigFloat e) 定義二進制實例?

[英]Haskell: How to define Binary instance for (BigFloat e)?

如何為 Data.Number.BigFloat 定義二進制實例?

我通過以下方式為 LongDouble 定義了一個實例:

instance Binary LongDouble where
    put d = put (decodeFloat d)
    get   = do
        x <- get
        y <- get
        return $! encodeFloat x y

但是嘗試以下方法不起作用:

instance Binary (BigFloat e) where
    put d = put (decodeFloat d )
    get   = do
        x <- get
        y <- get
        return $! encodeFloat x y

GHC 給出此錯誤消息:

/home/usr/Documents/src/Lib.hs:27:18: error:
    • No instance for (Epsilon e) arising from a use of ‘decodeFloat’
      Possible fix:
        add (Epsilon e) to the context of the instance declaration
    • In the first argument of ‘put’, namely ‘(decodeFloat d)’
      In the expression: put (decodeFloat d)
      In an equation for ‘put’: put d = put (decodeFloat d)
   |
27 |     put d = put (decodeFloat d )
   |                  ^^^^^^^^^^^^^

/home/usr/Documents/src/Lib.hs:31:19: error:
    • No instance for (Epsilon e) arising from a use of ‘encodeFloat’
      Possible fix:
        add (Epsilon e) to the context of the instance declaration
    • In the second argument of ‘($!)’, namely ‘encodeFloat x y’
      In a stmt of a 'do' block: return $! encodeFloat x y
      In the expression:
        do x <- get
           y <- get
           return $! encodeFloat x y
   |
31 |         return $! encodeFloat x y

如果我為 e 提供特定類型,例如 Prec500,我會收到以下消息:

• Illegal instance declaration for ‘Binary (BigFloat Prec500)’
    (All instance types must be of the form (T a1 ... an)
     where a1 ... an are *distinct type variables*,
     and each type variable appears at most once in the instance head.
     Use FlexibleInstances if you want to disable this.)
• In the instance declaration for ‘Binary (BigFloat Prec500)’

並且使用 FlexibleInstances 編譯,但不會產生正確編碼的數字。

以下內容也可以編譯,但也不能正確編碼:

instance Epsilon e => Binary (BigFloat e) where
    put d = put (decodeFloat d )
    get   = do
        x <- get
        y <- get
        return $! encodeFloat x y

這個BigFloat似乎做得不是很好。 問題出在這里:

> floatDigits (0 :: BigFloat Prec500)
-9223372036854775808

(正確答案應該是 500。)我承認我不完全理解為什么會這樣。 但從源頭來看,計算floatDigits的方式是獲取精度的對數——但log是發生在Double s 上的事情,而Double沒有足夠的精度來表示1e-500 因此,這種計算數字計數的方法似乎從一開始就注定要失敗。

為什么我說我不完全理解? 好吧,我在源代碼中看到以下內容:

floatDigits (BF m _) =
    floor $ logBase base $ recip $ fromRational $ precision m

根據我的閱讀, fromRational應該產生0:: Double 但如果這是真的,最終值將是0 ,而不是minBound

> floor $ logBase 10 $ recip $ (0 :: Double) :: Int
0

因此,也許正在進行一些狡猾的重寫或其他事情。

無論如何,這種類型的正確實現應該以不同的方式工作——例如,通過比Epsilon提供更多信息的 class 可以將精度報告為基數和指數。 (另一個可能的想法是讓floatRadix返回recip precision ,而floatDigits返回1 ,但是如果精度不是整數的倒數,這會發生一些奇怪的事情。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM