JS集成器部门



在Javascript中,所有的数字都是double precision float,这只是内存表示或数值运算的问题?

例如,关于计算复杂性

15 / 3
14 / 3

这些操作会花费相同的计算资源吗?还是v8会优化整数划分情况?

(此处为V8开发人员。)

简短回答:这很复杂而且(正如axic所指出的)也不值得担心。

长答案:
首先,当您在源中对数字文本(如15 / 3)进行除法时,V8将在解析时不断地将其折叠,因此除法只执行一次,无论是否以任何方式优化都无关紧要。例如,如果您编写function f() { return 15/3; },那么它将被编译为function f() { return 5; }

下一个重要的观察结果是,判断除法是否会有整数结果的唯一方法是实际执行除法并查看结果。具体地说,如果一个引擎想要有这样的东西:

function implementation_of_/_operator(x, y) {
if (division_result_will_be_integer(x, y)) {
return integer_division(x, y);
else {
return floating_point_division(x, y);
}
}

那么它必须以某种方式实现division_result_will_be_integer,对此有两种选择:

function division_result_will_be_integer(x, y) {
if (!is_integer(x) || !is_integer(y)) return false;
return is_integer(floating_point_division(x, y));
}
// or:
function division_result_will_be_integer(x, y) {
if (!is_integer(x) || !is_integer(y)) return false;
(quotient, remainder) = integer_division_with_remainder(x, y);
return remainder == 0;
}

显然,表演一个除法只是为了决定之后要表演哪个附加的除法是愚蠢的,而且跳过整个舞蹈,总是直接进行浮点除法会更快。

第三个相关点是,整数除法的硬件指令可能相当慢。特别是,对于大除数和小除数,它往往比浮点除法指令慢。那么,你的问题假设是一个";优化";在实践中很可能会降低性能。

不管是整数域还是浮点域,除法运算总是相当昂贵的。在两个操作数都是整数的情况下,除法可以用与"0"的乘法来代替;乘法逆";除数的。然而,再次找到这个乘法逆需要除法,因此只有当你期望用相同的除数进行多次除法时,比如当除数是常数时,例如f(x) { return x / 3; },这种技术才能提高性能。此外,对整数进行运算意味着只能表示整数结果;如果有人在这个例子中调用f(14),那么用逆技术进行乘法运算会产生错误的结果
V8在优化代码中使用这种方法,如果(1)除数是常数,(2)在优化给定函数时,它以前看到的在这个特定除法中产生的所有结果都是整数。然后,这样的优化代码必须仍然包含一个检查,以验证所有未来的结果也是整数,即,它必须检查division_result * dividend === divisor,否则将退出浮点除法。

最后,还有一些对asm.js风格代码的特殊处理。如果您编写f(x, y) { return ((x | 0) / (y | 0) | 0); },那么V8将在该函数中使用整数除法指令。显然,|0操作意味着该函数将输入及其结果截断为32位整数,这对于您的用例来说可能是可接受的,也可能是不可接受的。这比简单的无忧function f(x, y) { return x / y; }更快还是更慢也取决于您的用例。

最新更新