Skip to content

Conversation

@bloerwald
Copy link
Contributor

As described in #471, storing float values that need higher precision than the default 6 would be rounded. This was true for all but postgresql prepared statements. Those were only supporting up to double and were off by a bit (maxdigits10 vs digits10).

Now, all streams I could find (except those in prepared statements for specific non-float types) should be using full precision. An internal test that rolls random double values worked fine with various high random values.

I'm not sure how to unit test this without having database backends, so a test is missing. Best I could come up with is serializing with some known-high-precision number and checking the string to be identical?

@rbock
Copy link
Owner

rbock commented Feb 12, 2023

floats are odd floats :-)

26/94 Test #26: sqlpp11.core.serialize.In .............................................Subprocess aborted***Exception:   0.11 sec
[...]/sqlpp11/tests/core/serialize/compare.h 52
Expected: -->|tab_foo.omega IN(1.7,2.5,17,0)|<--
Received: -->|tab_foo.omega IN(1.70000004768371582031,2.5,17,0)|<--
terminate called after throwing an instance of 'std::runtime_error'
  what():  unexpected serialization result

@bloerwald
Copy link
Contributor Author

Argh, sorry, I tried to reproduce it yesterday but managed to check out the wrong branch m(

I agree that one probably doesn't want it to serialise to that, although it of course is correct, just ugly, even for numbers this low (slightly adapted from cppreference).

One can set the precision for the float types specifically rather than using long-double for all. This does improve the ugliness slightly: With 1.7 it still is 1.70000005 (float) 1.7 (double) and 1.69999999999999995559 (long double).

The easiest fix for the failing test is using a safe float like 1.25 instead of 1.7. The second easiest fix is using the ugly (but well defined) 1.70000004768371582031. Since users can be confused by that value (despite it being fine), the third option is using the specialised stream, which is adding a bit of overhead for visual effect only.

Do you have a preference?

@rbock
Copy link
Owner

rbock commented Feb 13, 2023

One can set the precision for the float types specifically rather than using long-double for all. This does improve the ugliness slightly: With 1.7 it still is 1.70000005 (float) 1.7 (double) and 1.69999999999999995559 (long double).

I like this one, with a serialize test for each to set expectations.

@bloerwald
Copy link
Contributor Author

I like this one, with a serialize test for each to set expectations.

Done. The test has the boilerplate to use the specific serializers as well, but commented out since it requires the dependencies, and I didn't want to add all the "if dependency is found" infrastructure which I don't see existing yet. I can offer to instead add it to some random respective connector-specific test?

Copy link
Owner

@rbock rbock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! This looks pretty thorough!
I added a couple of comments.
PTAL

I like this one best. Short. Sweet. Well documented for C++11.
And yes, std::decay does a bit more than necessary, but nothing that would hurt.

Co-authored-by: Bernd Lörwald <[email protected]>
@rbock
Copy link
Owner

rbock commented Feb 17, 2023

Thanks for going the extra mile! Looks very good to me at this point.

Please let me know if you are OK with merging at this point, too?

@bloerwald
Copy link
Contributor Author

bloerwald commented Feb 17, 2023

Please let me know if you are OK with merging at this point, too?

Seems fine to me. 👍

I had some very-close-to-zero values deserialize badly in our unit tests, but that seems to be a SQLite issue, not an sqlpp one:

input hex         float_safe_ostringstream  deserialized                  output hex
80a797b1d9baf781  -1.6798458567329104e-305  -1.67984585673291039419e-305  80a797b1d9baf781
80a797b1d9baf782  -1.6798458567329106e-305  -1.67984585673291064715e-305  80a797b1d9baf782

Serializer is fine ⬆️ SQLite truncates. ⬇️

sqlite> CREATE TABLE test (value REAL);
sqlite> INSERT INTO test VALUES (-1.6798458567329104e-305);
sqlite> INSERT INTO test VALUES (-1.6798458567329106e-305);
sqlite> SELECT * FROM test;
-1.67984585673291e-305
-1.67984585673291e-305

Appears that SQLite only guarantees 15 digits, for whatever reason.

I think I'll change my tests to not assert bit-identical results ;)

Edit: allowed for some inaccuracy, got 5000 successful test runs.

@rbock rbock merged commit 9412851 into rbock:main Feb 18, 2023
@rbock
Copy link
Owner

rbock commented Feb 18, 2023

Done, thanks!

Edit: allowed for some inaccuracy, got 5000 successful test runs.

👍

@bloerwald bloerwald deleted the serializers-ensure_float_precision branch February 20, 2023 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants