我正在使用Dart对32位整数进行ZigZag编码。这是我正在使用的源代码:
int _encodeZigZag(int instance) => (instance << 1) ^ (instance >> 31);
int _decodeZigZag(int instance) => (instance >> 1) ^ (-(instance & 1));
代码在DartVM中按预期工作。
但是在dart2js中,_decodeZigZag
函数返回无效结果,如果我输入否定数字。例如-10
。 -10
已编码为19
,应解码回-10
,但会被解码为4294967286
。如果我在Chrome的JavaScript控制台中运行(instance >> 1) ^ (-(instance & 1))
,我会得到-10
的预期结果。对我来说,这意味着Javascript应该能够使用数字模型正确运行此操作。
但是Dart2Js会生成以下JavaScript,它与我在控制台中测试的代码看起来不同:
return ($.JSNumber_methods.$shr(instance, 1) ^ -(instance & 1)) >>> 0;
为什么Dart2Js将函数的右移0加到函数中?如果没有这种转变,结果将如预期的那样。
现在我想知道,这是Dart2Js编译器中的错误还是预期的结果?有没有办法强制Dart2Js输出正确的javascript代码?
或者我的Dart代码错了吗?
PS :还测试了将XOR分成其他操作,但Dart2Js仍在添加正确的移位:
final a = -(instance & 1);
final b = (instance >> 1);
return (a & -b) | (-a & b);
结果:
a = -(instance & 1);
b = $.JSNumber_methods.$shr(instance, 1);
return (a & -b | -a & b) >>> 0;
答案 0 :(得分:6)
出于效率原因,dart2js将Dart编号编译为JS编号。但是,JS只提供一种数字类型:双精度型。此外,JS中的位操作总是被截断为32位。
在许多情况下(如加密),处理无符号32位更容易,因此dart2js编译位操作,因此它们的结果是无符号的32位数。
两种选择(有符号或无符号)都不是完美的。最初dart2js编译为有符号的32位,并且只有在我们经常跳过它时才会被更改。正如您的代码所示,这不会消除问题,只是将其转移到不同的(希望不那么频繁)用例。
不合规的数字语义一直是dart2js中的一个长期存在的错误,但修复它会花费时间并可能减慢生成的代码。在短期内,Dart开发人员(编译为JS)需要了解这一限制并解决它。
答案 1 :(得分:3)
看起来我找到了输出正确结果的等效代码。 dart vm和dart2js的单元测试通过,我现在将使用它。
int _decodeZigZag(int instance) => ((instance & 1) == 1 ? -(instance >> 1) - 1 : (instance >> 1));
这次Dart2Js没有添加班次。我仍然会对这种行为的原因感兴趣。