Haskell 为什么无穷大没有抛出一些错误?

Haskell 为什么无穷大没有抛出一些错误?,haskell,floating-point,infinity,floor,Haskell,Floating Point,Infinity,Floor,我发现自己遇到了一个案例,执行了相当于floor$1/0 λ>1/0 无穷 据我所知,这是正常的行为,但当无限是地板'd或天花板'd时 λ>最低$1/0 1797693134862315907729305190789024733617976978942306572734300811577326758055009631327084773224075360211201138798713933576587897688144166224928474306394741243777678934248654

我发现自己遇到了一个案例,执行了相当于
floor$1/0

λ>1/0
无穷
据我所知,这是正常的行为,但当
无限
地板
'd或
天花板
'd时

λ>最低$1/0
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216
而不是失败,这个非常大的数字产生了为什么?


也许更重要的是,在应用另一个函数之前,我如何在不使用过滤器的情况下将其与非故障结果区分开来?

第一个问题可能并不那么重要,因此我将首先尝试回答第二个问题

一旦你有了一个数字,如果你知道它来自
floor x
,你就不知道
x
是否是
2^1024
的有效表示,或者它是否是无穷大。您可能会假设任何超出double范围的内容都是无效的,并且是由无穷大、负无穷大、NaN等生成的。使用
RealFloat
中的一个/多个函数(如
isNaN
isInfinite
等)检查您的值是否有效非常简单

您还可以使用类似于
数据编号a=na | 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"
  ..
哪种方法最好主要基于您的用例

也许
楼层(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
properFraction(F#x#)
=大小写为
(#m#,n##)->
设m=I#m#
n=I#n#
在里面
如果n>=0
然后(从积分m*(2^n),0.0)
否则让i=如果m>=0,则m`shiftR`否定n
else否定(否定m`shiftR`否定n)
f=m-(i`shiftL`否定n)
in(来自积分i,编码浮点(来自积分f)n)
地板x=外壳属性x
(n,r)->如果r<0.0,则n-1否则n
请注意,
decodeFloat_Int#
返回尾数和指数。根据:

正无穷和负无穷表示为:符号=0表示 正无穷大,1表示负无穷大。有偏指数=全部1 位。分数=所有0位


对于
Float
,这意味着基数为2^23,因为基数中有23位,指数为105(为什么是105?我真的不知道。我想应该是255-127=128,但实际上似乎是128-23)。
floor
的值是
from积分m*(2^n)
base*(2^index)==2^23*2^105==2^128
。对于double,这个值是1024。

这个数字似乎是
2^1024::Integer
,但我不知道为什么这个数字特别大。因为有人忘记了在
properFraction
@Wes的代码中测试无穷大。在IEEE 754标准中,无穷大由2^1023表示。这可能与此有关。@Jeffrey,“实数分数”不就是类中某个类型的任何成员吗
RealFrac
?@Jeffrey我不只是虚构发生了什么,我知道发生了什么。当Haskell第一次被定义时,IEEE-754浮点并不像现在这样占主导地位,所以没有关于无穷大或NaN的关注或思考。我为
Float
Double
编写了
properFraction
的第一个实现(据我所知),但我忘了测试无穷大。随后的重新实现重复了这个错误。这并不是真的相关,但为什么
properFraction
unbox它的参数,分解它,然后在实际使用它们之前再次装箱?我盯着那个代码,想知道它到底有什么意义。除此之外,
shiftR m(否定n)
?如果
negate n
较大,文档不保证该移位的结果。如果GHC将依赖于这种奇怪的、未记录的行为,为什么不使用明显不安全的转换呢?