Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Floating point imprecision #1166

Closed
jmlemetayer opened this issue Jul 17, 2018 · 3 comments
Closed

Floating point imprecision #1166

jmlemetayer opened this issue Jul 17, 2018 · 3 comments
Labels
kind: question solution: invalid the issue is not related to the library

Comments

@jmlemetayer
Copy link

Serializing floating point leads to imprecision.

Using this source code:

#include <iostream>

#include "json.hpp"

using json = nlohmann::json;

int main(void)
{
	json j;

	double a = 1.234;
	float b = 1.234;
	double c = b;
	float d = b;

	j["a"] = a;
	j["b"] = b;
	j["c"] = c;
	j["d"] = d;

	std::cout << std::setw(4) << j << std::endl;

	std::cout << "a=" << a <<std::endl;
	std::cout << "b=" << b <<std::endl;
	std::cout << "c=" << c <<std::endl;
	std::cout << "d=" << d <<std::endl;

	return 0;
}

Ouputs:

{
    "a": 1.234,
    "b": 1.2339999675750732,
    "c": 1.2339999675750732,
    "d": 1.2339999675750732
}
a=1.234
b=1.234
c=1.234
d=1.234

I was excepted every number to be equal to 1.234 as with the std::cout.

I am using g++ on Debian 9:

g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
@jaredgrubb
Copy link
Contributor

Float is a 32-bit representation, and with 32 bits, the two numbers "1.234" and "1.2339999675750732" have identical representations. Either way is "correct" to print a float. There is no imprecision here, just a representation that is "less pretty".

When cout outputs "c" as "1.234", it is actually lying and printing something less precise than it actually is. If you tell cout you want full precision, then you will get identical results to what nlohmann::json is doing. (add "std::cout.precision(17);" to your program).

>>> def float2hex(num):
...  return ''.join('%02x' % ord(c) for c in struct.pack('!f', num))
...
>>> def double2hex(num):
...  return ''.join('%02x' % ord(c) for c in struct.pack('!d', num))
...
>>> float2hex(1.2339999675750732)
'3f9df3b6'
>>> float2hex(1.234)
'3f9df3b6'
>>>
>>> double2hex(1.234)
'3ff3be76c8b43958'
>>> double2hex(1.2339999675750732)
'3ff3be76c0000000'

@jmlemetayer
Copy link
Author

jmlemetayer commented Jul 17, 2018

Wow very impressive response. Thanks for the explanation.

As I understood the background behind my issue, I close it.

@nlohmann nlohmann added solution: invalid the issue is not related to the library kind: question labels Jul 18, 2018
@nlohmann
Copy link
Owner

@jaredgrubb Thanks so much for the detailed response. I am currently overworking the documentation, and this definitely should go in there!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question solution: invalid the issue is not related to the library
Projects
None yet
Development

No branches or pull requests

3 participants