如何为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 yGHC给出了以下错误消息:
/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发布于 2022-08-21 22:13:36
这个BigFloat似乎做得不太好.问题在于:
> floatDigits (0 :: BigFloat Prec500)
-9223372036854775808(正确答案应该是500。)我承认我不完全理解为什么会发生这种情况,但从源头上看,floatDigits的计算方法是通过获取精度的日志--但是log是发生在Doubles上的事情,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更信息丰富的类,它可以将精度报告为基数和指数。(另一种可能的想法是让floatRadix返回recip precision和floatDigits返回1,但如果精度不是整数的倒数,这就有一些奇怪之处。)
https://stackoverflow.com/questions/73438297
复制相似问题