截断到Word类型

Dan*_*íaz 12 haskell

下面的代码在类型Double中将一些类型截断为一个Word16(虽然我怀疑任何其他单词类型的行为类似,但我必须为示例选择一个).

truncate1 :: Double -> Word16
truncate1 = fromIntegral . (truncate :: Double -> Int)
Run Code Online (Sandbox Code Playgroud)

正如你可以阅读的那样,我首先将其截断为Int,然后才将其转换为Word16.我直接截断这个函数的基准测试:

truncate2 :: Double -> Word16
truncate2 = truncate
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,第一个版本(通过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
Run Code Online (Sandbox Code Playgroud)

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

提前致谢.

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

C. *_*ann 13

首先,请注意该模块GHC.Word 包含以下 RULE编译指示:

"truncate/Double->Word16"
    forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)
Run Code Online (Sandbox Code Playgroud)

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

为什么这是一个优化呢?

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

因此,它似乎truncate1受益于一种专门的形式,而truncate2不是.

为什么truncate1更快?

GHC.Float,在RealFrac例如Double定义,我们有如下RULE编译:

"truncate/Double->Int"              truncate = double2Int
Run Code Online (Sandbox Code Playgroud)

double2Int我们想要的优化形式在哪里.将此与RULE前面提到的相比较- 显然没有专门用于转换Double为的原始操作Word16.

为什么不truncate2改写?

GHC用户指南:

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

表达式相匹配不是ETA-扩大,这是说,一个规则匹配上forall x. foo x将会匹配bar y = foo y,但没有bar = foo.

由于您的定义都写,自由点RULEDouble -> Int比赛,但RULE对于Double -> Word16没有.

  • 这提出了一个问题:为什么truncate/Double-Word16规则不是`truncate =(fromIntegral :: Int - > Word16).(truncate :: Double - > Int)`以便它适用于`truncate2`? (3认同)
  • @GeoffReedy这是一个有效的借口,那些是关于我曾经写过的第一个"规则",我甚至都不知道eta减少问题呢?(我看到`RULES`使用`forall x....`,我跟着这个例子.)我要重写它们以便它们点火和无条件,但是目前我无法验证因为`Typeable `改变打破了几个图书馆. (3认同)