Dan Heller created THRIFT-2933:
----------------------------------
Summary: For Compact protocol, thrift node library v0.9.2 doubles
encoded big endian in node [decoded little-endian in python]
Key: THRIFT-2933
URL: https://issues.apache.org/jira/browse/THRIFT-2933
Project: Thrift
Issue Type: Bug
Components: Node.js - Library
Affects Versions: 0.9.2
Reporter: Dan Heller
I've noticed that with Thrift v0.9.2, using the Compact protocol, I can't
encode doubles in node and decode them in python. It looks like in python,
we're decoding little-endian for compact and big-endian for binary, and in
node, writing big-endian in all cases (therefore, Binary works fine). I've
attached a test program to show this behavior. I have not found the thrift
binary spec, so I'm not sure which side is wrong.
{code}
[~/thrift-double]$ thrift --version
Thrift version 0.9.2
[~/thrift-double]$ grep -i thrift package.json
"thrift": "0.9.2"
"compile": "thrift --gen js:node --gen py test.thrift"
[~/thrift-double]$ pip show thrift
---
Name: thrift
Version: 0.9.2
Location: /Library/Python/2.7/site-packages
Requires:
[~/thrift-double]$ npm run compile
> [email protected] compile /Users/dh/thrift-double
> thrift --gen js:node --gen py test.thrift
[~/thrift-double]$ node test.js binary | python test.py binary
Trying to send { intField: 100, doubleField: 99.88 }
Reading with binary protocol.
Got test object: TestType(intField=100, doubleField=99.88)
[~/thrift-double]$ node test.js compact | python test.py compact
Trying to send { intField: 100, doubleField: 99.88 }
Reading with compact protocol.
Got test object: TestType(intField=100, doubleField=-2.24248483894553e-38)
[~/thrift-double]$
{code}
I notice the following snippets.
* TBinaryProtocol.py: network format (big-endian)
{code}
def readDouble(self):
buff = self.trans.readAll(8)
val, = unpack('!d', buff)
return val
{code}
* TCompactProtocol.py: little-endian
{code}
def readDouble(self):
buff = self.trans.readAll(8)
val, = unpack('<d', buff)
return val
{code}
* binary.js: my best IEEE floating point days are behind me but this looks
big-endian. In any case it's used for both compact and binary.
{code}
exports.writeDouble = function(buff, v) {
var m, e, c;
buff[0] = (v < 0 ? 0x80 : 0x00);
v = Math.abs(v);
if (v !== v) {
// NaN, use QNaN IEEE format
m = 2251799813685248;
e = 2047;
} else if (v === Infinity) {
m = 0;
e = 2047;
} else {
e = Math.floor(Math.log(v) / Math.LN2);
c = Math.pow(2, -e);
if (v * c < 1) {
e--;
c *= 2;
}
if (e + 1023 >= 2047)
{
// Overflow
m = 0;
e = 2047;
}
else if (e + 1023 >= 1)
{
// Normalized - term order matters, as Math.pow(2, 52-e) and
v*Math.pow(2, 52) can overflow
m = (v*c-1) * POW_52;
e += 1023;
}
else
{
// Denormalized - also catches the '0' case, somewhat by chance
m = (v * POW_1022) * POW_52;
e = 0;
}
}
buff[1] = (e << 4) & 0xf0;
buff[0] |= (e >> 4) & 0x7f;
buff[7] = m & 0xff;
m = Math.floor(m / POW_8);
buff[6] = m & 0xff;
m = Math.floor(m / POW_8);
buff[5] = m & 0xff;
m = Math.floor(m / POW_8);
buff[4] = m & 0xff;
m >>= 8;
buff[3] = m & 0xff;
m >>= 8;
buff[2] = m & 0xff;
m >>= 8;
buff[1] |= m & 0x0f;
return buff;
};
{code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)