`Integer` vs`Int64` vs`Word64`

时间:2012-01-15 20:15:20

标签: haskell integer

我有一些数据可以用无符号Integral类型表示,其最大值需要52位。仅AFAIK IntegerInt64Word64满足这些要求。

我能找到的有关这些类型的所有信息都是Integer已签名并且具有浮动的无限位大小,Int64Word64分别是固定的,有符号和无符号的。我不知道的是有关这些类型的实际实施的信息:

  1. 如果存储为Integer,52位值实际占用多少位?

  2. 我是否更正Int64Word64允许您存储64位数据,并为任何值正好权衡64位?

  3. 由于尺寸以外的任何其他原因,这些类型中的任何一种是否更具性能或优先性,例如:本机代码实现或直接处理器指令相关的优化?

  4. 以防万一:您建议将哪一个值存储在对性能极为敏感的应用程序中?

1 个答案:

答案 0 :(得分:22)

  

如果存储为Integer

,52位值实际占用多少位

这是依赖于实现的。使用GHC,适合机器字的值直接存储在Integer的构造函数中,因此如果您使用的是64位计算机,则它应占用与Int相同的空间量。这对应于S#的{​​{1}}构造函数:

Integer

较大的值(即data Integer = S# Int# | J# Int# ByteArray# 表示的值)与GMP一起存储。

  

我是否正确J#Int64允许您存储64位数据,并为任何值权重64位?

不完全 - 他们盒装Word64实际上是指向未评估的thunk或指向 info表的单字指针加上64位整数值的指针。 (有关详细信息,请参阅GHC commentary。)

如果你真的想要保证64位的东西,没有例外,那么你可以使用像Int64这样的未装箱的类型,但我强烈建议先进行分析;未装箱的值使用起来非常痛苦。例如,您不能使用未装箱的类型作为类型构造函数的参数,因此您不能拥有Int64#的列表。您还必须使用特定于未装箱整数的操作。当然,所有这些都是GHC特有的。

如果你想存储很多52位整数,你可能想要使用vectorrepa(基于向量,有自动并行等奇特的东西);它们将未装箱的值存储在引擎盖下,但让您以盒装形式使用它们。 (当然,您取出的每个单独的价值都将装箱。)

  

由于尺寸以外的任何其他原因,这些类型中的任何一种是否更具性能或优先性,例如本机代码实现或直接处理器指令相关的优化?

是;使用Int64#为每个操作都会产生一个分支,因为它必须区分机器字和bignum情况;当然,它必须处理溢出。固定大小的整数类型可以避免这种开销。

  

以防万一:您建议将哪一个值存储在对性能极其敏感的应用程序中?

如果您使用的是64位计算机:Integer,或者,如果必须,Int64

如果您正在使用32位计算机:可能Int64#,因为在32位Integer上使用FFI调用模拟可能没有高度优化的GHC函数,但是我d尝试两者并对其进行基准测试使用Int64,您将获得小整数的最佳性能,并且GMP经过大量优化,因此它可能会比您想象的更大。

您可以使用C预处理器(启用Integer)在编译时在Int64Integer之间进行选择;我认为让Cabal根据目标架构的字宽来控制{-# LANGUAGE CPP #-}会很容易。当然要注意它们不一样;您必须小心避免#define代码中的“溢出”,例如IntegerInt64的实例,但Bounded不是。最简单的方法是只针对单个字宽(从而输入类型)来提高性能,并使用较慢的性能来生活。

我建议您创建自己的Integer类型作为Int52封装器newtypeInt64封装器Word52 - 只需选择与您相匹配的数据更好,不应有性能影响;如果它只是任意位,我会选择Word64,因为Int64Int更常见。

您可以定义所有实例以自动处理包装(在GHCi中尝试Word以找出您要定义的实例),并提供仅在{{1下直接应用的“不安全”操作对于性能危急的情况,你知道不会有任何溢出。

然后,如果您不导出:info Int64构造函数,则可以在以后交换newtype的实现,而无需更改任何其余代码。不要担心单独类型的开销 - newtype的运行时表示与底层类型完全相同;它们只存在于编译时。