【问题标题】:Why does xor truncate number values?为什么 xor 会截断数值?
【发布时间】:2011-12-22 06:02:07
【问题描述】:

或者...如何在不得到整数结果的情况下进行 XOR 加倍?

我正在使用 Actionscript 3.0 并发现以下内容:

var a:Number = 3.000000004;
var b:Number = 29.999999999;
trace ("a: " + a); //3.000000004
trace ("b: " + b); //29.999999999
a ^= b;
b ^= a;
a ^= b;
trace ("a: " + a); //29
trace ("b: " + b); //3

显然,XOR 操作将我的数字转换为整数。我对此有点惊讶,并不完全理解其背后的原因。但我确实知道其他按位运算也会将 Number 更改为 int,所以我并不感到惊讶。

尽管如此,有没有办法在不将它们截断为整数的情况下对双精度数(又名数字)进行异或运算?我最初使用上面的 XOR 来优化性能(这些数字开关在数组中执行了数百万次)。我假设如果我跳过临时变量,我会看到速度增加。唉,如果把 Number 数据改成 int,那就白费了。

只是想知道是否有解决方案,或者在这种情况下我是否需要放弃 XOR。

(ps,我暂时无法查看这个帖子,但在此期间感谢任何建议、知识等)

(pps,如果你好奇,这是我尽可能加快速度的方法)

public static function reversePairs(values:Vector.<Number>):void {
    //1, 2, 3, 4, 5, 6 -> 5, 6, 3, 4, 1, 2
    var l:int = values.length;
    var n:int = l * 0.5;
    n -= n % 2;
    for (var a:int = 0; a < n; a++) {
        var b:int = (l - a) - 2 * ((a + 1) % 2);
        //we cannot use xor because it truncates the decimal value
        //values[a] ^= values[b];
        //values[b] ^= values[a];
        //values[a] ^= values[b];
        //we MUST use a temporary variable instead
        var c:Number = values[b];
        values[b] = values[a];
        values[a] = c;
    }
}

【问题讨论】:

  • 你为什么要异或双打??
  • 我需要切换它们的值。 XOR 适用于引用(因为您正在交换内存地址)。但是对于原语来说,行为显然是不同的。希望所提供的附加代码能够使我的目的显而易见。

标签: actionscript-3 optimization bit-manipulation


【解决方案1】:

xor-swap 操作不是优化。这是一种悲观。

很难想到任何架构会是一个好主意(每个步骤有四个步骤,具体取决于前一个步骤的完成情况,甚至假设读取-修改-写入内存到内存是原子的......一个真正可怕的实现交换)。

在内存中的两个值之间进行交换的最佳方式通常是双重读取,然后是双重写入:

reg1 = mem1; reg2 = mem2;
mem1 = reg2; mem2 = reg1;

这些对中的每一个也可以并行执行(两次读取是独立的,两次写入也是独立的),因此操作可以分两步完成。 大多数优化编译器都能够识别惯用的三步交换

{ type temp = x; x = y; y = t; }

为此生成两步交换代码,这是硬件的最佳方式。

也就是说,可以通过使用就地减法-=而不是就地异或^=来获得浮点与错误的异或交换代码“等效”的东西。

然而,只有在没有出现准确性问题的情况下,这才是真正的交流。

【讨论】:

  • 啊!很高兴知道这一点。显然我正在调试模式下测试我的代码,所以我知道编译器不会优化我的临时变量交换。如果我运行发布构建编译器,也许会。现在,我将尝试按照您的描述进行操作。
  • 更改内存地址读/写让我花了大约 100 毫秒。取决于 CPU 的感觉。
  • 如果您在测试速度,永远不要永远使用调试编译器甚至调试播放器,差异可能是十倍,而且通常在相当不直观的地方。跨度>
  • 是的,我开始意识到这一点。特别是查看人们在网上进行的其他测试,他们的结果显然是错误的(例如 Vector 不如 Array 快,尽管这是 Vector 的全部意义)。唯一的解释是他们的调试结果并不代表发布版本的性能。不幸的是,这意味着我必须为非调试编译实现自己的调试消息——这是一个小而不受欢迎的任务。
【解决方案2】:

^= 是按位运算,而不是整数运算本身(参见 Adobe's docs)。想象不存在 ints 这样的东西是有帮助的。

实际上需要更多个临时变量来异或一个数字与小数,这不会解决速度问题。

虽然我不能提供任何东西来重写交换,但我可以建议你永远不要(ever!)在 for 循环中声明 var,除非你必须这样做。尔格:

var b:int;
var c:Number;
for (var a:int = 0; a < n; a++) {
  b = (l - a) - 2 * ((a + 1) & 1);
  c = values[b];
  values[b] = values[a];
  values[a] = c;
}

另外请注意,我使用 1 将模数更改为 an additive mask,应该会更快。

除此之外,允许 Vector 类进行排序可能很有用,write a custom sort method 供您特定使用。

【讨论】:

  • 据我了解,在 ActionScript 中声明变量的位置无关紧要。所有变量声明都被编译为好像它们是在功能块的顶部声明的。放置纯粹是一个装饰性的决定,以帮助代码可读性。为此,我在使用它们的块中声明了变量。谢谢你的建议!
  • 顺便说一句,用按位更改模数并将原本需要 7 秒的过程减少了约 400 密耳。再次感谢!
  • 进一步说明:为了彻底,我尝试将变量声明移出循环。实际上,我这样做失去了一点速度。肯定很奇怪。同样,我正在编译一个调试 .swf,所以也许这与它有关?
  • 好吧,只是在非调试版本中测试它。 . .您可以安装多个 Flash Player。即使你失去了速度,也要养成将 vars 放在循环之外的习惯;对于您的具体情况,可能无关紧要(int 是一个内部结构,Number 只是复制一个内存位置。但是,如果您每次都必须创建一个 new 对象,那将会有所改进循环。)
  • 好的,所以我使用常规编译器并将结果打印到屏幕上再次测试。无论出于何种原因,我始终通过在循环中而不是在外部声明变量来获得更快的速度。但是,它是 ~18400 和 ~18500 之间的差异,所以这是一个分钟点。这很奇怪。我想我可以比较生成的字节码...
猜你喜欢
  • 1970-01-01
  • 2015-09-12
  • 2013-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多