[英]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.