FJsonObject::GetIntegerField() loses precision

Hi,

Stumbled upon this today as I was reading Unix timestamps from a json input.

FJsonObject::GetIntegerField() invokes FMath::TruncToInt( float ) with an argument of type ‘double’. The implicit double → float conversion silently loses precision and screws up reading perfect int32 values.

Having FMath::TruncToInt( double ) would fix that. It’s absence might actually have negative implications outside FJsonObject as well.

Hi bstone,

I can see a potential issue with regards to what you are doing, but it is more related to limitations of the Float data type than the implicit Double-to-Float conversion. What are the results that you are seeing? Knowing what you are seeing will help me determine if my initial suspicion is correct.

Hello ,

Thanks for looking into that.

What I do is parsing a Json payload. Some fields contain integer numbers. I use FJsonObject::GetIntegerField() to retrieve those values. But instead of the values specified in the Json representation I get slightly other values, i.e. GetIntegerField() returns wrong results. For example if I have:

{ value: 1470252657 }

FJsonObject::GetIntegerField() for ‘value’ would return 1470252544, not the expected 1470252657.

As you can see I’m only dealing with integer values and don’t even access Float data or use it anywhere in that process.

Anyway, what I was pointing to is that not having FMath::TruncToInt( double ) is dangerous because “int32” values have 31 bit precision while “float” values have only 24 bit precision. Routing double values through FMath::TruncToInt( float ), which now happens silently without any warnings, loses 7 bits of precision for nothing. And FJsonObject::GetIntegerField() is a good example of why it is dangerous.

Hi bstone,

What you described is what I was referring to in my previous comment. I may not have adequately stated what I was thinking. What is happening here is not specifically a result of the implicit double to float conversion (which does lose some precision, but this would not normally be noticed when the fractional portion of the value is truncated). Instead, this is a result of the float type’s inability to accurately store integer values greater than 2^24. I believe that is what we were both getting at, but I expressed myself a bit poorly.

I have entered UE-34255 to have this investigated further.

,

Yes, that makes sense. Thanks for pushing it further.