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.
source to share
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.
source to share
@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
source to share
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 .
source to share