THRIFT-3376 C# and Python JSON protocol double values lose precision
Client: C#, Python, C++, Ruby
Patch: Nobuaki Sukegawa <nsukeg@gmail.com>
This closes #643
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index 1ab4d21..2736ee8 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -106,6 +106,29 @@
}
}
+// Workaround for absense of C++11 "auto" keyword.
+template <typename T>
+bool print_eq(T expected, T actual) {
+ cout << "(" << actual << ")" << endl;
+ if (expected != actual) {
+ cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl;
+ return false;
+ }
+ return true;
+}
+
+#define BASETYPE_IDENTITY_TEST(func, value) \
+ cout << #func "(" << value << ") = "; \
+ try { \
+ if (!print_eq(value, testClient.func(value))) \
+ return_code |= ERR_BASETYPES; \
+ } catch (TTransportException&) { \
+ throw; \
+ } catch (exception & ex) { \
+ cout << "*** FAILED ***" << endl << ex.what() << endl; \
+ return_code |= ERR_BASETYPES; \
+ }
+
int main(int argc, char** argv) {
int ERR_BASETYPES = 1;
int ERR_STRUCTS = 2;
@@ -388,11 +411,47 @@
/**
* DOUBLE TEST
*/
- printf("testDouble(-5.2098523)");
- double dub = testClient.testDouble(-5.2098523);
- printf(" = %f\n", dub);
- if ((dub - (-5.2098523)) > 0.001) {
- printf("*** FAILED ***\n");
+ // Comparing double values with plain equality because Thrift handles full precision of double
+ BASETYPE_IDENTITY_TEST(testDouble, 0.0);
+ BASETYPE_IDENTITY_TEST(testDouble, -1.0);
+ BASETYPE_IDENTITY_TEST(testDouble, -5.2098523);
+ BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279);
+ BASETYPE_IDENTITY_TEST(testDouble, pow(2, 32));
+ BASETYPE_IDENTITY_TEST(testDouble, pow(2, 32) + 1);
+ BASETYPE_IDENTITY_TEST(testDouble, pow(2, 53) - 1);
+ BASETYPE_IDENTITY_TEST(testDouble, -pow(2, 32));
+ BASETYPE_IDENTITY_TEST(testDouble, -pow(2, 32) - 1);
+ BASETYPE_IDENTITY_TEST(testDouble, -pow(2, 53) + 1);
+
+ try {
+ double expected = pow(10, 307);
+ cout << "testDouble(" << expected << ") = ";
+ double actual = testClient.testDouble(expected);
+ cout << "(" << actual << ")" << endl;
+ if (expected - actual > pow(10, 292)) {
+ cout << "*** FAILED ***" << endl
+ << "Expected: " << expected << " but got: " << actual << endl;
+ }
+ } catch (TTransportException&) {
+ throw;
+ } catch (exception& ex) {
+ cout << "*** FAILED ***" << endl << ex.what() << endl;
+ return_code |= ERR_BASETYPES;
+ }
+
+ try {
+ double expected = pow(10, -292);
+ cout << "testDouble(" << expected << ") = ";
+ double actual = testClient.testDouble(expected);
+ cout << "(" << actual << ")" << endl;
+ if (expected - actual > pow(10, -307)) {
+ cout << "*** FAILED ***" << endl
+ << "Expected: " << expected << " but got: " << actual << endl;
+ }
+ } catch (TTransportException&) {
+ throw;
+ } catch (exception& ex) {
+ cout << "*** FAILED ***" << endl << ex.what() << endl;
return_code |= ERR_BASETYPES;
}
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
index 7e3daf2..3a74353 100755
--- a/test/py/TestClient.py
+++ b/test/py/TestClient.py
@@ -158,6 +158,7 @@
self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
self.assertEqual(self.client.testDouble(0), 0)
self.assertEqual(self.client.testDouble(-1), -1)
+ self.assertEqual(self.client.testDouble(-0.000341012439638598279), -0.000341012439638598279)
def testBinary(self):
if isinstance(self, JSONTest):
diff --git a/test/rb/integration/TestClient.rb b/test/rb/integration/TestClient.rb
index 8fd6336..6aec596 100755
--- a/test/rb/integration/TestClient.rb
+++ b/test/rb/integration/TestClient.rb
@@ -130,7 +130,7 @@
def test_double
p 'test_double'
- val = 3.14
+ val = 3.14159265358979323846
assert_equal(@client.testDouble(val), val)
assert_equal(@client.testDouble(-val), -val)
assert_kind_of(Float, @client.testDouble(val))