[CSHARP-1969] BsonExtensionMethods.ToJson() lost precision with floating pointer numbers Created: 24/Apr/17  Updated: 29/Sep/20  Resolved: 29/Sep/20

Status: Closed
Project: C# Driver
Component/s: BSON
Affects Version/s: 2.4.3
Fix Version/s: None

Type: Task Priority: Major - P3
Reporter: qaqz111 Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: Bug, double, float, json, question
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

.NetFX



 Description   

BsonDocument.Parse("{\"price\":8.84}").ToJson()

output:

"{ \"price\" : 8.8399999999999999 }"



 Comments   
Comment by qaqz111 [ 24/Apr/17 ]

Thanks for the explanation.

Yes I did know the binary representation of floating numbers can not represent exactly the literal value of a number, what confused me is that this issue is new introduced in newer version driver.

Then I checked github and saw the commit and the previous related issue CSHARP-1731.

According to your words I understand now that the driver is preferred to serialize the exact binary data of a double.
That's correct I think, though the text form output is ugly to read.

Previously I was preferring the consistency of input literal value and output json text, but I think I'm going to change a way to treat the data processing now.

Comment by Robert Stam [ 24/Apr/17 ]

Double and float numbers in C# are binary, and they are unable to represent many decimal numbers accurately. This is not specifically related to the C# MongoDB Driver, it is inherent in the binary representation of double and float numbers.

When you use a constant like "8.84" in your code the compiler converts it to the nearest possible equivalent binary double or float. When you later convert that back to a decimal number (by calling ToString) the binary double or float is converted back to decimal. Depending on the requested precision of the ToString conversion, the binary value might be rounded back to 8.84, but if you use a high enough precision you will see that the closest binary equivalent of 8.84 is not exactly 8.84.

To see this in action try this code, which does not use the C# driver at all:

var x = 8.84D;
Console.WriteLine(x.ToString("G17"));

Output is:

8.8399999999999999

Comment by qaqz111 [ 24/Apr/17 ]

Another code snippet:

Tuple.Create(8.84).ToJson()

output:

"[8.8399999999999999]"

This is treated as double.

And, the same issue with float:

Tuple.Create(8.84F).ToJson()

output:

"[8.8400001525878906]"

Generated at Wed Feb 07 21:41:14 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.