JObject.Parse changes the ending of floating point values

var clientString = "{\"max\":1214.704958677686}";

JObject o = JObject.Parse(clientString);

var jsonString = o.ToString();

      


jsonString content:

{
  "max": 1214.7049586776859
}

      

this is both when rendering the object and when executing ToString (). Note that 686 was mysteriously expanded to 6859 (precision added). This is a problem for us because the numbers are not exactly the same and the hash function over the json does not match later.

+3


source to share


3 answers


The reason your value changes is due to the nature of floating point numbers in .NET. The method JObject.Parse(clientString)

at some point executes the following line:

double d;
double.TryParse("1214.704958677686", NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out d);

      

where d

represents the number you get in JObject

.

Since it d

is double and double is a floating point number, you did not get the expected value. Learn more about Binary Floating Point and .NET .



JSON.NET has an option to parse floating point numbers as decimal places and get the precision you want, but for that you need to create your own class corresponding to your json string and deserialize the json. Something like that:

public class MyClass
{
    [JsonProperty("max")]
    public decimal Max { get; set; }
}


var obj = JsonConvert.DeserializeObject<MyClass>(clientString, new JsonSerializerSettings
          {
              FloatParseHandling = FloatParseHandling.Decimal
          });

      

Using this code example, the property value max

will not be changed.

+3


source


@Ilija Dimov - JSON.NET parses JSON by default as double

. If you still want to use JObject

instead of creating a fully blown POCO for deserialization, you can use JsonTextReader

and set the parameter FloatParseHandling

:



var reader = new JsonTextReader(new StringReader(clientString));
reader.FloatParseHandling = FloatParseHandling.Decimal;

JObject obj = JObject.Load(reader);

Console.WriteLine(obj["max"].Value<decimal>()); // 1214.704958677686

      

+3


source


You can experiment with this behavior only by parsing into float, double and decimal:

Assert.AreEqual(1214.705f,float.Parse("1214.704958677686"));
Assert.AreEqual(1214.7049586776859, double.Parse("1214.704958677686"));
Assert.AreEqual(1214.704958677686, decimal.Parse("1214.704958677686"));

      

So json.net uses double as an intermediate type. You can change this by setting the FloatParseHandling parameter .

+1


source







All Articles