截断到Word类型

时间:2013-02-11 20:56:55

标签: haskell

以下代码将类型Double中的一些类型Word16截断为一个{尽管我怀疑任何其他单词类型的行为类似,我必须为示例选择一个)。

truncate1 :: Double -> Word16
truncate1 = fromIntegral . (truncate :: Double -> Int)

正如您所读,我首先将其截断为Int,然后才将其转换为Word16。我再次对此函数进行基准测试直接截断:

truncate2 :: Double -> Word16
truncate2 = truncate

令我惊讶的是,第一个版本(首先通过Int类型)表现得更好。或者第二个更糟糕。根据标准输出:

benchmarking truncate/truncate1
mean: 25.42399 ns, lb -47.40484 ps, ub 67.87578 ns, ci 0.950
std dev: 145.5661 ns, lb 84.90195 ns, ub 244.2057 ns, ci 0.950
found 197 outliers among 100 samples (197.0%)
  97 (97.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 99.000%
variance is severely inflated by outliers

benchmarking truncate/truncate2
mean: 781.0604 ns, lb 509.3264 ns, ub 1.086767 us, ci 0.950
std dev: 1.436660 us, lb 1.218997 us, ub 1.592479 us, ci 0.950
found 177 outliers among 100 samples (177.0%)
  77 (77.0%) low severe
  100 (100.0%) high severe
variance introduced by outliers: 98.995%
variance is severely inflated by outliers

老实说,我刚开始使用Criterion,所以我不是专家,但我知道25.42399 ns的执行时间比781.0604 ns短。我怀疑某些专业化在这里起作用。 truncate2太慢了吗?既然如此,可以truncate进行改进吗?此外,任何人都知道更快的方式吗?我觉得做错了什么不适合我不习惯的类型。

提前致谢。

我正在使用GHC-7.4.2进行编译,启用了优化(-O2)。

1 个答案:

答案 0 :(得分:13)

首先,请注意模块GHC.Word includes the following RULE pragma:

"truncate/Double->Word16"
    forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)

这是一个简单的重写规则,可以准确执行truncate1提供的优化。所以我们需要考虑几个问题:

为什么这是一个优化呢?

因为truncate的默认实现是通用的,所以支持任何Integral实例。你看到的速度差异是这种普遍性的代价;在将一种基本类型截断为另一种基本类型的特定情况下,可用的方法要快得多。

所以似乎truncate1从特殊表单中受益,而truncate2则不是。

为什么truncate1更快?

In GHC.Float,其中定义了RealFrac的{​​{1}}实例,我们有以下Double pragma:

RULE

"truncate/Double->Int" truncate = double2Int 是我们想要的优化形式。将其与前面提到的double2Int进行比较 - 显然没有专门用于将RULE转换为Double的类似原始操作。

为什么没有Word16也被重写?

Quoth the GHC User's Guide:

  

GHC目前使用一种非常简单的语法匹配算法来匹配规则LHS和表达式。它寻求一种替代,使得LHS和表达在语法上等于模α转换。如果需要,模式(规则),但不是表达式,是eta扩展的。

匹配的表达式不是eta-expanded,也就是说truncate2上的规则匹配forall x. foo x匹配,而bar y = foo y中的不匹配

由于您的定义都是免费的,bar = foo RULE匹配,但Double -> Int的{​​{1}}不匹配。