简体   繁体   中英

Why does xor truncate number values?

Or... how do you XOR doubles without getting integer results?

I am using Actionscript 3.0 and found the following:

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

Clearly, the XOR operation is converting my Numbers into ints. I am a bit surprised by this and don't exactly understand the reason behind it. But I do know that other bitwise operations will also change Number into int, so I am not that surprised.

Be that as it may, is there a way to XOR doubles (aka Numbers) without having them get truncated to integers? I used the above XOR originally for performance optimization (these number switches are executed millions of times in an array). I assumed if I skipped the temporary variable, I would see a speed increase. Alas, if the Number data gets changed to int, it is all for naught.

Just wondering if there is a solution to this or if I need to give up on XOR in this case.

(ps, I won't be able to check this thread for a while, but appreciate any suggestions, knowledge, etc. in the meantime)

(pps, in case you are curious, this is the method I am trying to speed up if possible)

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;
    }
}

The xor-swap operation is not an optimization. It's a pessimization.

It's hard to think to any architecture in which that would be a good idea (four steps each one depending on the completion of the preceding one even assuming read-modify-write memory to memory as atomic... a truly horrible implementation of swap).

The best way to do an exchange between two values in memory is most often a double-read followed by a double-write:

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

each of those pairs can also be executed in parallel (the two reads are independent, and also the two writes are independent) so the operation can complete in two steps. Most optimizing compilers are able to recognize the idiomatic three-steps swap

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

to generate the two step exhange code for that it this is the best way for the hardware.

That said something "equivalent" for floating point to that bad xor-swap code can be obtained by using inplace subtraction -= instead of inplace xor ^= .

It is however a true exchange only if accuracy problems don't kick in.

^= is a bitwise operation, not an integer operation per se (cf., Adobe's docs ). It is helpful to imagine that there is no such thing as ints.

It would actually require a few more temporary variables to XOR a Number with a decimal, which won't solve the speed problem.

Though I cannot offer anything to rewrite the swap, I can suggest that you never ( ever! ) declare vars in a for-loop unless you have to. Ergo:

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;
}

Also note that I changed the modulus to an additive mask using 1, which should be faster.

Beyond that, it may be useful to allow the Vector class to do the sorting, and write a custom sort method for your specific use.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM