Haskell 整数;这里到底发生了什么?
Haskell Integers; What exactly is going on here?
最近对 Haskell 感到好奇,我开始阅读一些东西。 Integer
让我大吃一惊。
当我们说 Integer
可以任意大时,这是否意味着我认为的意思(即 Integer
的大小不受 OS)?
假设我有足够的可用 RAM 来容纳具有十亿位值的数字。 Haskell 可以使用那个号码吗?
任何人都可以向我描述一下幕后发生的事情使这成为可能吗?
Haskell 的 Integer
类型通俗地称为 bignum 类型。它的工作方式与您手动执行数学计算的方式大致相同:通过处理数字而不是固定精度的二进制字。
Bignum 库通常将数字存储为 数字集合。 算术的工作方式与您手动执行的方式相同;通过操纵数字。
Say I had enough RAM available to hold a number with a billion place values. Would Haskell be able to work with that number?
Prelude> length . show $ 10^1000000000
1000000001
当然,它确实占用了大量内存
但是你仔细想想——一个字节实际上最多可以存储256>100的数字,即你可以在每个字节中存储两个以上的十进制数字。因此,一个十亿位数的数字应该少于 500 MB 来存储......好吧,显然这里有一些开销需要乘法(同样当我 show
我正在生成一个低效的列表字符串时) 但没什么戏剧性的。
顺便说一句,进行这些计算的不是 Haskell/GHC,而是 GHC 使用的 GMP。
但是您可以自己轻松地在Haskell中实现这样的类型。例如。为简单起见,使用您建议的十进制数字列表†
newtype DecDigit = DD { getDecDig :: Int }
instance Num [DecDigit] where
fromInteger n | n < 10 = [DD $ fromInteger n]
| otherwise = let (cs,ls) = n`divMod`10
in DD $ fromInteger ls : fromInteger cs
n + [] = n
[] + n = n
(DD n₀ : n) + (DD m₀ : m)
| s₀<10 = DD s₀ : n+m
| otherwise = DD (s₀-10) : n+m+[DD 1]
where s₀ = n₀+m₀
...
乘法有点难,但基本上,正如 Robert Harvey 所说,这就像您用笔和纸计算一样。
†这样效率很低!实际实现将不使用十进制数字,而是充分利用机器大小的字(可能使用现代处理器的 128 位甚至 256 位原始操作)。
最近对 Haskell 感到好奇,我开始阅读一些东西。 Integer
让我大吃一惊。
当我们说 Integer
可以任意大时,这是否意味着我认为的意思(即 Integer
的大小不受 OS)?
假设我有足够的可用 RAM 来容纳具有十亿位值的数字。 Haskell 可以使用那个号码吗?
任何人都可以向我描述一下幕后发生的事情使这成为可能吗?
Haskell 的 Integer
类型通俗地称为 bignum 类型。它的工作方式与您手动执行数学计算的方式大致相同:通过处理数字而不是固定精度的二进制字。
Bignum 库通常将数字存储为 数字集合。 算术的工作方式与您手动执行的方式相同;通过操纵数字。
Say I had enough RAM available to hold a number with a billion place values. Would Haskell be able to work with that number?
Prelude> length . show $ 10^1000000000
1000000001
当然,它确实占用了大量内存
但是你仔细想想——一个字节实际上最多可以存储256>100的数字,即你可以在每个字节中存储两个以上的十进制数字。因此,一个十亿位数的数字应该少于 500 MB 来存储......好吧,显然这里有一些开销需要乘法(同样当我 show
我正在生成一个低效的列表字符串时) 但没什么戏剧性的。
顺便说一句,进行这些计算的不是 Haskell/GHC,而是 GHC 使用的 GMP。
但是您可以自己轻松地在Haskell中实现这样的类型。例如。为简单起见,使用您建议的十进制数字列表†
newtype DecDigit = DD { getDecDig :: Int }
instance Num [DecDigit] where
fromInteger n | n < 10 = [DD $ fromInteger n]
| otherwise = let (cs,ls) = n`divMod`10
in DD $ fromInteger ls : fromInteger cs
n + [] = n
[] + n = n
(DD n₀ : n) + (DD m₀ : m)
| s₀<10 = DD s₀ : n+m
| otherwise = DD (s₀-10) : n+m+[DD 1]
where s₀ = n₀+m₀
...
乘法有点难,但基本上,正如 Robert Harvey 所说,这就像您用笔和纸计算一样。
†这样效率很低!实际实现将不使用十进制数字,而是充分利用机器大小的字(可能使用现代处理器的 128 位甚至 256 位原始操作)。