2

I am using NewtonSoft's JSON.NET assembly to load a .json file in a C# console application. I think I have done most of the work except I am finding that some negative float values are being rounded.

Here is relevant code; as you can see, I have tried both load and parse methods but same results.

string content;
using (StreamReader reader = new StreamReader("C:\\[Path]\brackett_full_room.json"))
{
  content = reader.ReadToEnd();
}

////  JObject rss = JObject.Load(reader);
JObject rss = JObject.Parse(content);

The original values are like:

"geometry" : {  "rings" : [   [   [  -9221300.3411999997, 4120326.8838  ],
    [  -9221300.2146000005,  4120327.992399998  ]...

But -9221300.3411999997 becomes something like -9221300.3412 in the rss variable and that is causing the coordinates to not work; the long positive values are fine.

Is there some way to keep precisions high enough (i.e. should have enough digits if parsed as double instead of float)?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
IrfanClemson
  • 1,699
  • 6
  • 33
  • 52
  • 2
    Instead of parsing to a JObject (which might use incorrect types for this case, dunno which is being chosen), create some classes that match the json object tree with correct typing (not sure if double or float or decimal in this case, possibly decimal?) and deserialize to that? –  Feb 23 '15 at 19:41
  • Thanks. If that happens then I would have to load into something other than JObject and maybe even do most of the work away from the JSON.NET assembly? – IrfanClemson Feb 23 '15 at 19:44
  • 1
    Your problem is a lack of precision in double floating point numbers. It's not a JSON.net problem it's a problem with the [double](https://msdn.microsoft.com/en-us/library/678hzkk9.aspx) type. – Matt Burland Feb 23 '15 at 19:44
  • Matt: I have no control over the input json file and novice users would be outputting that file to be consumed by the c# application. This may not be a json.net problem but I will have to somehow 'read' the data into the program and then massage the data. – IrfanClemson Feb 23 '15 at 19:47
  • Some useful links: [how do I choose between a Decimal and a Double](http://stackoverflow.com/questions/2545567/in-net-how-do-i-choose-between-a-decimal-and-a-double), [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – Matt Burland Feb 23 '15 at 19:48
  • 2
    json.net is making a bad decision on the type to use to store the value. Poo. The solution is to tell it by creating your object graph. Just create the types and use json.net to deserialize. Bam. No issues. Go, do it. –  Feb 23 '15 at 19:48
  • Side note: "that is causing the coordinates to not work" - float/double values are not precise - such small variation should not really impact anything. Make sure you handle floating point numbers correctly - i.e. you can't compare for "equality" in regular sense with `==` (which is essentially "bitwise identical" and not "represent basically the same value"). – Alexei Levenkov Feb 23 '15 at 19:49
  • Alexei: The values are being rejected in a SQL Server query because the spatial functions are complaining about some 'outer' rings not matching. Pretty sure even a fractional mismatch is causing the problem. – IrfanClemson Feb 23 '15 at 19:51
  • 1
    @Meengla: Then it really sounds like you have bigger problems than just some rounding. If your code relies on that level of precision when comparing floating point numbers, you should probably fix the SQL query. Comparing floating point number for equality is usually a dicey proposition at the best of times. – Matt Burland Feb 23 '15 at 19:53
  • Matt, I am not 100% sure but I think SQL Server's spatial function geometry::STPolyFromText is almost certainly looking for such precision; once I go past this rounding problem I will know more. – IrfanClemson Feb 23 '15 at 20:04

2 Answers2

6

Some code to Andrew's correct answer:

var settings = new JsonSerializerSettings();
settings.FloatParseHandling = FloatParseHandling.Decimal;
string json = @"{ ""rings"" : [  -9221300.3411999997, 4120326.8838  ] }";
var rss = JsonConvert.DeserializeObject(json, settings);
Ondrej Svejdar
  • 21,349
  • 5
  • 54
  • 89
  • 1
    A good quick and dirty solution, but I still think creating your own type to deserialize to (as @will suggested) is a cleaner solution. – Matt Burland Feb 23 '15 at 19:51
  • I have implemented this solution partly and should work but var all_Features = (JArray)rss["features"]; now gives an error: 'Error 1 Cannot apply indexing with [] to an expression of type 'object' – IrfanClemson Feb 23 '15 at 19:57
  • @Meengla - I see no "features" property in your json. Maybe you should update your question / fire a new one ? – Ondrej Svejdar Feb 24 '15 at 10:44
  • Ondrej, indeed, there was nothing like that in the question. First I had to get the full values. However, now, as per my comment above says, in next lines of code my all_Features variable doesn't work anymore--something to do with Deserialization done above. I have looked for a solution but can't find--I basically need to get the 'features' node – IrfanClemson Feb 24 '15 at 13:18
  • Ondrej: Never mind--I forgot to mention late last night I did find a way to make the All_Features variable to load correct data...by creating another Class. Sorry for mis-info. I just tested it and it works--fresh brain makes a difference ;) So all good now--I think! Thanks again!! – IrfanClemson Feb 24 '15 at 13:34
3

You need to use the Decimal type instead of a Double in order to keep that number of significant figures.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84