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

时间:2016-04-01 11:57:15

标签: 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]))))

以上代码的格式为X div Y,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,为什么它不能将它们组合起来呢?

2 个答案:

答案 0 :(得分: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

观察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

浮点版本不准确但仍然接近,而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

x不同,y的类型已经具体:必须Int,因为这是length的结果类型。 (理由是:一个如此大的列表,你无法用Int测量它的长度,无论如何都无法适应内存。)

现在,div与Haskell中的大多数数字函数一样,要求参数和结果具有相同的类型。因此,x`div`y整体计算为Int而不是Integer,包括x。正如我们所见,将x计算为Int会导致伪造。

OTOH,如果您使用362880作为文字,那么这与length无关。它只是一个通用数字,如x,因此GHCi将再次默认为安全Integer,即你得到

Prelude Data.List> x `div` 362880
2658017764500203964000

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

Prelude Data.List> x `div` fromIntegral y
2658017764500203964000

答案 1 :(得分:0)

使用Integer而不是Int有助于:

let r :: Integer ; r =  (product (take 9 [1000,999..])) `div` (product (map (\j-> product [1..j]) (map (\j->fromIntegral $ length(j)) (group [2,2,2,2,2,2,2,2,2]))))

得到我:2658017764500203964000

我不完全理解你的代码,但我认为如果你单独计算它们会得到较小的中间结果 - 所以Int不会溢出。

所以是的 - 不连贯是因为数字很大(Int的宽度有限,所以它只会溢出(负数)。如果你使用如此大的数字操作,你应该使用Integer,它有无限宽度。