2

I use System.Text.Json to deserialize some stuff and then serialize it. The problem is that for example double value 99.6 is being deserialized and then serialized to 99.599999999999994.

What can I do about it?

Here's a reproduction in console app.

using System;
using System.Text.Json;

namespace ConsolePG3
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person { Value = 99.6 };

            var text = JsonSerializer.Serialize(person);
            Console.WriteLine(text);
            Console.ReadLine();
        }
    }
    class Person
    {
        public double Value { get; set; }
    }
}
  • 5
    If your application behaves significantly differently when using 99.59999999994 instead of 99.6 then you should be using `decimal`, not `double`. `99.6` can't be represented as a `double` _exactly_ so you end up with some insignificant imprecision. – D Stanley Nov 19 '20 at 14:32
  • I thought maybe `System.Text.Json` might have used `"R"` for round-tripping, which has a known bug (see [the docs](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#the-round-trip-r-format-specifier) and [Why is a round-trip conversion via a string not safe for a double?](https://stackoverflow.com/q/24299692/3744182)), but in fact I can't reproduce the problem, see https://dotnetfiddle.net/mZLKIP. Can you [edit] your question to share a [mcve]? – dbc Nov 19 '20 at 18:27
  • But I agree that switching to `decimal` will solve the problem, `decimal` is designed to (among other things) round-trip values from and to base 10 string representations without data loss. – dbc Nov 19 '20 at 18:29

1 Answers1

8

The important thing to get your head around here is that the double with value 99.6 does not exist, and never existed. You imagined it. It was rounded the moment you compiled it. It is simply not possible to represent the exact value 99.6 in floating-point arithmetic, due to how floating-point works. The serializer has correctly serialized the actual value that exists.

If you want to represent discreet values in the way that humans tend to think of them - use decimal instead of floating-point (float, double). It (decimal) is also limited in terms of precision (and it is not CPU-optimized), but the way it approximates is much more comparable to how humans approximate, and it will readily story the exact value for most common scenarios.

Frankly, the moment you are thinking about "the exact value": floating point is not a good choice.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900