第一个问题可能不太重要,因此我将先尝试回答第二个问题。
一旦你有一个数字,如果你知道它来自于floor x,你就无法知道x是否是2^1024的有效表示,或者它是否是无穷大。你可以假设超出double范围的任何值都是无效的,并且是由无穷大、负无穷大、NaN或类似值产生的。使用RealFloat中的函数之一/多个(如isNaN、isInfinite等)非常容易检查您的值是否有效。
你也可以使用这样的东西:data Number a = N a | PosInf | NegInf。然后你可以写:
instance RealFrac a => RealFrac (Number a) where
...
floor (N n) = floor n
floor PosInf = error "Floor of positive infinity"
floor NegInf = error "Floor of negative infinity"
..
哪种方法最好主要取决于您的用例。
也许对于 floor(1/0)
来说将其视为错误可能是正确的。但该值本身就是垃圾数据。处理垃圾数据还是错误更好呢?
但是为什么是 2^1024
?我查看了 GHC.Float
的源代码:
properFraction (F# x#)
= case decodeFloat_Int# x# of
(# m#, n# #) ->
let m = I# m#
n = I# n#
in
if n >= 0
then (fromIntegral m * (2 ^ n), 0.0)
else let i = if m >= 0 then m `shiftR` negate n
else negate (negate m `shiftR` negate n)
f = m - (i `shiftL` negate n)
in (fromIntegral i, encodeFloat (fromIntegral f) n)
floor x = case properFraction x of
(n,r) -> if r < 0.0 then n - 1 else n
请注意,
decodeFloat_Int#
返回尾数和指数。根据
维基百科的说法:
正无穷和负无穷的表示方法是:正无穷的符号= 0,负无穷的符号= 1。偏置指数=全部是1位。分数=全部是0位。
对于
Float
,这意味着底数为2 ^ 23,因为基数中有23位,并且指数为105(为什么是105?我实际上不知道。我认为它应该是255-127 = 128,但似乎实际上是128-23)。
floor
的值为
fromIntegral m *(2 ^ n)
或
base *(2 ^ exponent)== 2 ^ 23 * 2 ^ 105 == 2 ^ 128 。 对于double,该值为1024。
2^1024 :: Integer
,但我不知道为什么会是那个数字。 - WesRealFrac
类中的任何成员吗? - dfeuerFloat
和Double
的properFraction
的第一个实现(据我所知),但我忘记了测试无穷大的情况。随后的重新实现也重复了这个错误。 - augustss