我发现自己遇到了一种情况,正在执行等效的floor $ 1/0

λ> 1/0
Infinity

据我了解,这是正常行为,但是当Infinityfloor'd或ceiling'd

λ> floor $ 1/0
179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216

没有失败,而是产生了非常大的数目。 为什么?

也许更重要的是,如何在应用其他功能之前不使用过滤器的情况下将其与非错误结果区分开?

最佳答案

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

有了数字后,如果知道它来自floor x,就无法知道x2^1024的有效表示形式还是无穷大。您可能会假设超出double范围的任何内容都是无效的,并且是由无穷大,负无穷大,NaN等产生的。使用RealFloat中的一个/很多功能(例如isNaNisInfinite等)来检查您的值是否有效将非常简单。

您也可以使用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#返回尾数和指数。根据wikipedia:

正负无穷表示如下:sign = 0 for
正无穷大,负无穷大为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。

10-01 22:46