javascript 解决默认取整的坑(目前已知的最佳解决方案)
复现该问题
js在数字操作时总会取更高精度的结果,例如1234/10
结果就是123.4
,但是在c或者java中整数除以10的结果还是整数,小数部分被舍去,不仅如此 *
,%
等运算符也会出现这种结果,但我们有时候更希望舍去取整
使用Math标准库
Math标准库提供了Math.floor():向下取整Math.ceil():向上取整Math.round():四舍五入
这三种取整方法,效率也不错,但是在进行一些操作时,总感觉别扭,而且效率会偏低,查看了v8中Math部分的源码后发现需要进行非常多的操作后才能得到结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
TF_BUILTIN(MathFloor, MathBuiltinsAssembler) { TNode<Context> context = CAST(Parameter(Descriptor::kContext)); TNode<Object> x = CAST(Parameter(Descriptor::kX)); MathRoundingOperation(context, x, &CodeStubAssembler::Float64Floor); }
TNode<Float64T> CodeStubAssembler::Float64Floor(SloppyTNode<Float64T> x) { if (IsFloat64RoundDownSupported()) { return Float64RoundDown(x); } TNode<Float64T> one = Float64Constant(1.0); TNode<Float64T> zero = Float64Constant(0.0); TNode<Float64T> two_52 = Float64Constant(4503599627370496.0E0); TNode<Float64T> minus_two_52 = Float64Constant(-4503599627370496.0E0); VARIABLE(var_x, MachineRepresentation::kFloat64, x); Label return_x(this), return_minus_x(this); Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this); Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero, &if_xnotgreaterthanzero); BIND(&if_xgreaterthanzero); { GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x); var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52)); GotoIfNot(Float64GreaterThan(var_x.value(), x), &return_x); var_x.Bind(Float64Sub(var_x.value(), one)); Goto(&return_x); } BIND(&if_xnotgreaterthanzero); { GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x); GotoIfNot(Float64LessThan(x, zero), &return_x); TNode<Float64T> minus_x = Float64Neg(x); var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52)); GotoIfNot(Float64LessThan(var_x.value(), minus_x), &return_minus_x); var_x.Bind(Float64Add(var_x.value(), one)); Goto(&return_minus_x); } BIND(&return_minus_x); var_x.Bind(Float64Neg(var_x.value())); Goto(&return_x); BIND(&return_x); return TNode<Float64T>::UncheckedCast(var_x.value()); }
|
在进行Math.floor操作时会进行很多操作,复杂度较高,有很多层递归才能获得结果
使用按位运算符
按位运算符中的~
是将数字按位取反,位运算是js中计算较快的操作符,把浮点数两次按位取反后可以获得舍去取整的结果即Math.floor(5.6)==~~5.6)
这是目前已知的最快解决方法
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
var reverse = function (x) { let ans = 0; while (x !== 0) { ans = ans * 10 + ~~(x % 10); x = ~~(x / 10); } return (ans >= (2 ** 31) || ans <= -(2 ** 31)) ? 0 : ans; };
var reverse = function (x) { let ans = 0; while (x !== 0) { ans = ans * 10 + Math.floor(x % 10); x = Math.floor(x / 10); } return (ans >= (2 ** 31) || ans <= -(2 ** 31)) ? 0 : ans; };
|
以上两个函数获取的结果完全一样