Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-1047

Losing precision in conversion from float to BsonDouble

    XMLWordPrintableJSON

Details

    • Icon: Improvement Improvement
    • Resolution: Done
    • Icon: Minor - P4 Minor - P4
    • None
    • None
    • BSON
    • Fully Compatible

    Description

      We could improve the BsonDouble type converting values from a float type without losing precision like decimal types (decimal type in C# solves the losing precision converting some numeric values).

      Example:

      With the actual implementation, the function BsonTypeMapper.MapToBsonValue returns a BsonDouble with precision lost if the parameter passed is a float. See the following new test case:

      float value2 = 1.3f;
      BsonDouble secondBsonValue = (BsonDouble)BsonTypeMapper.MapToBsonValue(value2);
      BsonDouble expectedResult = 1.3d;
      Assert.AreSame(expectedResult, secondBsonValue);

      The test case result is:

      MongoDB.Bson.Tests.BsonTypeMapperTests.TestMapBsonDouble:

      Expected: same as <1.3>

      But was: <1.2999999523162842>

      Also the comparison is not entirely accurate. See the following code of a console test code:

      float value = 1.3f;
      var bsonValue = (BsonDouble)BsonTypeMapper.MapToBsonValue(value);
      bool result1 = (value == bsonValue);
      Console.WriteLine("Case 1: Original:

      {0}, converted: {1}. AreSame: {2}. ¿?¿", value, bsonValue, result1);
      var bsonDouble = (BsonDouble)BsonTypeMapper.MapToBsonValue(value, BsonType.Double);
      bool result2 = (value == bsonDouble);
      Console.WriteLine("Case 2: Original: {0}

      , converted:

      {1}. AreSame: {2}. ¿?¿ ", value, bsonDouble, result2);
      Console.ReadKey();

      Outputs:

      Case 1: Original: 1,3, converted: 1.2999999523162842. AreSame: True. ¿?¿
      Case 2: Original: 1,3, converted: 1.2999999523162842. AreSame: True. ¿?¿

      Proposed solution:

      Use the decimal type as an intermediate cast.

      This code converts values without losing precision.

      float f = 3.2f;
      double d = (double)(decimal)f;
      double d2 = (double)f; // Loss
      Console.WriteLine("Original float: {0} and converted double: {1}

      ", f, d);
      Console.WriteLine("Original float:

      {0}

      and converted double without intermediate decimal:

      {1}

      ", f, d2);

      Output:
      Original float: 3,2 and converted double: 3,2
      Original float: 3,2 and converted double without intermediate decimal: 3,2000000
      4768372

      I needed solve it and I have a valid implementation which passes the test cases and I’m able to pull request shortly.

      Attachments

        Activity

          People

            robert@mongodb.com Robert Stam
            MarkCBB Marc Cortada
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: