以下代码截断了一些类型 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
)。
最佳答案
首先,注意模块 GHC.Word
includes the following RULE
语用:
"truncate/Double->Word16"
forall x. truncate (x :: Double) = (fromIntegral :: Int -> Word16) (truncate x)
这是一个简单的重写规则,可以精确地执行您的
truncate1
的优化。提供。所以我们有几个问题需要考虑:为什么这是一个优化?
因为
truncate
的默认实现是通用的,支持任何 Integral
实例。您看到的速度差异是这种普遍性的成本;在将一种原始类型截断为另一种的特定情况下,有更快的方法可用。所以看来
truncate1
受益于特殊形式,而 truncate2
不是。为什么是
truncate1
快点?In
GHC.Float
,其中 RealFrac
Double
的实例已定义,我们有以下 RULE
语用:"truncate/Double->Int" truncate = double2Int
在哪里
double2Int
是我们想要的优化形式。将此与 RULE
进行比较前面提到过——显然没有类似的原始操作专门用于转换 Double
至Word16
.为什么不
truncate2
也被重写?Quoth the GHC User's Guide:
GHC currently uses a very simple, syntactic, matching algorithm for matching a rule LHS with an expression. It seeks a substitution which makes the LHS and expression syntactically equal modulo alpha conversion. The pattern (rule), but not the expression, is eta-expanded if necessary.
被匹配的表达式不是 eta 扩展的,也就是说在
forall x. foo x
上匹配的规则将匹配 bar y = foo y
但不在 bar = foo
中.由于您的定义都是无意义的,
RULE
对于 Double -> Int
匹配,但 RULE
对于 Double -> Word16
才不是。
关于haskell - 截断为 Word 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14820699/