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/lib/csharp/src/Protocol/TJSONProtocol.cs b/lib/csharp/src/Protocol/TJSONProtocol.cs
index 4081d6e..88d554e 100644
--- a/lib/csharp/src/Protocol/TJSONProtocol.cs
+++ b/lib/csharp/src/Protocol/TJSONProtocol.cs
@@ -505,7 +505,7 @@
         private void WriteJSONDouble(double num)
         {
             context.Write();
-            String str = num.ToString(CultureInfo.InvariantCulture);
+            String str = num.ToString("R", CultureInfo.InvariantCulture);
             bool special = false;
 
             switch (str[0])
diff --git a/lib/csharp/test/ThriftTest/TestClient.cs b/lib/csharp/test/ThriftTest/TestClient.cs
index c09a801..f0297d0 100644
--- a/lib/csharp/test/ThriftTest/TestClient.cs
+++ b/lib/csharp/test/ThriftTest/TestClient.cs
@@ -358,6 +358,14 @@
                 Console.WriteLine("*** FAILED ***");
                 returnCode |= ErrorBaseTypes;
             }
+            Console.Write("testDouble(-0.000341012439638598279)");
+            dub = client.testDouble(-0.000341012439638598279);
+            Console.WriteLine(" = " + dub);
+            if (-0.000341012439638598279 != dub)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+            }
 
             byte[] binOut = PrepareTestData(true);
             Console.Write("testBinary(" + BytesToHex(binOut) + ")");
diff --git a/lib/py/src/protocol/TJSONProtocol.py b/lib/py/src/protocol/TJSONProtocol.py
index 9e25f67..7807a6c 100644
--- a/lib/py/src/protocol/TJSONProtocol.py
+++ b/lib/py/src/protocol/TJSONProtocol.py
@@ -176,9 +176,9 @@
     self.context.write()
     self.trans.write(json.dumps(string, ensure_ascii=False))
 
-  def writeJSONNumber(self, number):
+  def writeJSONNumber(self, number, formatter='{}'):
     self.context.write()
-    jsNumber = str(number)
+    jsNumber = formatter.format(number)
     if self.context.escapeNum():
       jsNumber = "%s%s%s" % (QUOTE, jsNumber, QUOTE)
     self.trans.write(jsNumber)
@@ -467,7 +467,8 @@
     self.writeJSONNumber(i64)
 
   def writeDouble(self, dbl):
-    self.writeJSONNumber(dbl)
+    # 17 significant digits should be just enough for any double precision value.
+    self.writeJSONNumber(dbl, '{:.17g}')
 
   def writeString(self, string):
     self.writeJSONString(string)