並べ替えの要件を満たすには、次のことを行う必要があります。
- ビッグエンディアン表現を使用
- 符号ビットが 0 の場合は、1 に反転します。実際のビットを確認します。元の数値を 0 と比較すると、負のゼロなどの特殊なケースでは異なる結果が得られます。
- 符号ビットが 1 の場合、すべてのビットを反転する
Python 3 コード:
import struct
def invert(x):
return bytes(c ^ 255 for c in x)
def tobin(x):
binx = struct.pack('>d', x)
if binx > b'\x80': #negative
return invert(binx)
else:
return struct.pack('>d', -x)
data = [float('-inf'), -100.0, -2.0, -.9, -.1, -0.0,
0.0, .1, .9, 2.0, 100.0, float('inf'), float('nan')]
print(sorted(data, key=tobin))
#[-inf, -100.0, -2.0, -0.9, -0.1, -0.0, 0.0, 0.1, 0.9, 2.0, 100.0, inf, nan]
Python 2 では、次のように変更invert
します。
def invert(x):
return "".join(chr(ord(c) ^ 255) for c in x)
For reference, here is the equivalent node.js which already implements a Big Endian serialization function through the 'Buffer' class:
function serialize(n) {
var buffer = new Buffer(8);
var l = buffer.length;
buffer.writeDoubleBE(n, 0);
if (buffer[0] < 0x80) {
buffer[0] ^= 0x80;
} else {
for (var i = 0; i < l; i++)
buffer[i] ^= 0xff;
}
return buffer
}
function deserialize(buffer) {
var l = buffer.length;
// 0x80 is the most significant byte of the representation of
// the first positive number(Number.MIN_VALUE)
if (buffer[0] >= 0x80) {
buffer[0] ^= 0x80;
} else {
for (var i = 0; i < l; i++)
buffer[i] ^= 0xff;
}
return buffer.readDoubleBE(0);
}