哈斯克尔的大数字变为负数

CYC*_*CYC 4 haskell

(product (take 9 [1000,999..])) `div` (product (map (\j-> product [1..j]) (map (\j->length(j)) (group [2,2,2,2,2,2,2,2,2]))))
Run Code Online (Sandbox Code Playgroud)

上面的代码格式为X divY,带X=product (take 9 [1000,999..])&Y=(product (map (\j-> product [1..j]) (map (\j->length(j)) (group [2,2,2,2,2,2,2,2,2]))))

如果我将代码复制并粘贴到ghci中,它会给我-12740133310672一个答案,但如果我X & Y单独计算,我会得到964541486381834014456320000 & 362880,然后将它们分开给我2658017764500203964000作为答案.

我认为这种不连贯可能是因为数字太大,但由于计算机可以单独正确地计算X和Y,为什么它不能将它们组合起来呢?

lef*_*out 10

Prelude Data.List> let x = product $ take 9 [1000,999..]

Prelude Data.List> x
964541486381834014456320000
Prelude Data.List> :t x
x :: (Enum a, Num a) => a
Run Code Online (Sandbox Code Playgroud)

观察x具有通用数字的类型:您只使用适用于任何数字类型的操作来计算它.当您在GHCi中评估这样的数字时,它默认为"最安全"的具体类型,即Integer任意精度类型,对大数字没有问题.但是,您可以使用任何其他数字类型强制执行计算:

Prelude Data.List> x :: Integer
964541486381834014456320000
Prelude Data.List> x :: Float
9.645414e26
Prelude Data.List> x :: Double
9.645414863818342e26
Prelude Data.List> x :: Int
-4623139575776374784
Run Code Online (Sandbox Code Playgroud)

浮点版本不准确但仍然接近,而Int(机器大小的固定精度数字)只是溢出并给出完全伪造.

通常这不会打扰你,因为默认情况下使用安全Integer类型进行大量计算.

也就是说,除非别的东西阻止它.

Prelude Data.List> let y = product (map (\j-> product [1..j]) $ map length (group [2,2,2,2,2,2,2,2,2]))

Prelude Data.List> y
362880
Prelude Data.List> :t y
y :: Int
Run Code Online (Sandbox Code Playgroud)

不同的是x,类型y已经是具体的:它必须Int,因为那是结果类型length.(基本原理是:一个非常大的列表,无论如何都无法测量其长度Int.)无论如何都无法适应内存.)

现在,div像Haskell中的大多数数字函数一样,要求参数和结果具有相同的类型.因此,x`div`y将整体计算为Int代替Integer,包括x.而且正如我们所见,计算xInt假.

OTOH,如果你362880用作文字,那么就没有了length.它只是一个通用数字,x因此GHCi将再次默认为安全Integer,即你得到

Prelude Data.List> x `div` 362880
2658017764500203964000
Run Code Online (Sandbox Code Playgroud)

如果您只允许转换,则可以获得相同的结果y:

Prelude Data.List> x `div` fromIntegral y
2658017764500203964000
Run Code Online (Sandbox Code Playgroud)