我正在使用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;
最佳答案
出于效率原因,dart2js将Dart数字编译为JS数字。但是,JS只提供一种数字类型: double 。此外,JS中的位操作始终被截断为32位。
在许多情况下(例如密码学),更容易处理无符号的32位,因此dart2js会编译位操作,以便其结果为无符号的32位数字。
选择(带符号或无符号)都不是完美的。最初dart2js编译为带符号的32位,仅在我们过于频繁地跳闸时才进行更改。如您的代码所示,这并不能解决问题,只是将其转移到不同的(希望是不那么频繁的)用例上。
不兼容的数字语义是dart2js中的一个长期存在的错误,但是解决它会花费时间并且有可能减慢生成的代码的速度。在短期内,Dart开发人员(编译为JS)需要了解此限制并加以解决。