3

我正在使用 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。如果我(instance >> 1) ^ (-(instance & 1))在 Chrome 的 JavaScript 控制台中运行,我会得到预期的结果-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;
4

2 回答 2

6

出于效率原因,dart2js 将 Dart 编号编译为 JS 编号。然而,JS 只提供一种数字类型:双精度数。此外,JS 中的位操作总是被截断为 32 位。

在许多情况下(如密码学),处理无符号 32 位更容易,因此 dart2js 编译位操作,使其结果是无符号 32 位数字。

两种选择(签名或未签名)都不是完美的。最初 dart2js 编译为带符号的 32 位,只有当我们过于频繁地绊倒它时才会更改。正如您的代码所示,这并不能消除问题,只是将其转移到不同的(希望不那么频繁)用例。

不兼容的数字语义一直是 dart2js 中的一个长期错误,但修复它需要时间并且可能会减慢生成的代码。在短期内,Dart 开发人员(编译为 JS)需要了解这个限制并解决它。

于 2013-07-02T19:24:12.843 回答
3

看起来我找到了输出正确结果的等效代码。dart vm 和 dart2js 的单元测试都通过了,我现在将使用它。

int _decodeZigZag(int instance) => ((instance & 1) == 1 ? -(instance >> 1) - 1 : (instance >> 1));

Dart2Js 这次没有增加班次。我仍然会对这种行为的原因感兴趣。

于 2013-07-02T18:50:10.220 回答