我想知道是否有可能了解 V8 究竟是如何优化和内联事物的。
我创建了三个简单的test functions它们都以度为单位计算 Angular 正弦值。我将它们全部放入闭包中,以便 V8 应该能够内联局部变量。
1. 使用预先计算的常数Math.PI / 180
,然后执行 Math.sin(x * constant)
.
我使用了这段代码:
var test1 = (function() {
var constant = Math.PI / 180; // only calculate the constant once
return function(x) {
return Math.sin(x * constant);
};
})();
2. 即时计算常数。
var test2 = (function() {
var pi = Math.PI; // so that the compiler knows pi cannot change
// and it can inline it (Math.PI could change
// at any time, but pi cannot)
return function(x) {
return Math.sin(x * pi / 180);
};
})();
3. 使用文字数字并即时计算常数。
var test3 = (function() {
return function(x) {
return Math.sin(x * 3.141592653589793 / 180);
};
})();
令人惊讶的是,结果如下:
test1 - 25,090,305 ops/sec
test2 - 16,919,787 ops/sec
test3 - 16,919,787 ops/sec
看起来像
pi
确实在 test2
中内联如test2
和 test3
导致每秒的操作量完全相同。另一方面,除法似乎没有优化(即预先计算),因为
test1
明显更快。最佳答案
对您的第一个问题的有根据的猜测:
严格来说,它不能恒定折叠 pi / 180
部分,因为你不做 pi / 180
在第二个和第三个函数中。你只需除(x * pi)
通过 180
(乘法优先)。
现在,你可能会问为什么它不改变操作的顺序来结束它可以优化的东西(这个过程称为重新关联,顺便说一句)......毕竟,结果是等价的(a * b / c = (a * b) / c
) .数学是这样说的,对吧?
好吧,数学是这样说的,但数学不使用浮点数。有了浮点数,事情就变得更复杂了。 x * pi
可能会被四舍五入,然后重新排序会导致不同的结果。错误可能很小,但编译器优化的主要规则仍然是:你不能改变程序的结果。最好在以不幸的方式编写的一些数学基准上执行次优,而不是在某些图形代码中偏离一个像素(是的,这可能很明显)。
关于javascript - V8 究竟如何优化/内联?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8029106/