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

Use Grisu for FP formatting with precision #1032

Closed
vitaut opened this issue Feb 6, 2019 · 13 comments
Closed

Use Grisu for FP formatting with precision #1032

vitaut opened this issue Feb 6, 2019 · 13 comments

Comments

@vitaut
Copy link
Contributor

vitaut commented Feb 6, 2019

Currently Grisu is only used for the default (shortest decimal) formatting without precision. Investigate if it is possible to use it with given precision, at least when precision is relatively small.

@vitaut
Copy link
Contributor Author

vitaut commented Feb 22, 2019

Fixed precision is partly implemented in 8af651b.

@vitaut
Copy link
Contributor Author

vitaut commented Mar 10, 2019

Grisu is now used with fixed precision too (f & F specifiers). Need to enable it for g and e as well.

@vitaut
Copy link
Contributor Author

vitaut commented Mar 10, 2019

As a nice side effect {fmt} beats printf now, even without any micro-optimizations:

================= ============= ===========
Library           Method        Run Time, s
================= ============= ===========
libc              printf          1.01
libc++            std::ostream    3.04
fmt 1632f72       fmt::print      0.86
tinyformat 2.0.1  tfm::printf     3.23
Boost Format 1.67 boost::format   7.98
Folly Format      folly::format   2.23
================= ============= ===========

@vitaut
Copy link
Contributor Author

vitaut commented Mar 17, 2019

Enabled Grisu for general format in 76d326a. Need to do the same for exponential.

@vitaut
Copy link
Contributor Author

vitaut commented Nov 20, 2019

Exponent notation is done too.

@vitaut vitaut closed this as completed Nov 20, 2019
@t-b
Copy link

t-b commented Dec 11, 2019

I'm coming from #1244.

Unfortunately this is not yet working, or I'm doing something wrong.

#include <fmt/format.h>
#include <iostream>

int main() {

std::cout << fmt::format("{:.{}e}", 2.5, 0) << std::endl;
}

gives

$ g++ --version
g++.exe (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
g++ -I fmt/include/ -D FMT_HEADER_ONLY test.cpp && ./a.exe
2e+00

but using MSVC gives

E:\projekte\JSON-XOP\src>cl test.cpp /I fmt/include /D FMT_HEADER_ONLY /EHsc
Microsoft (R) C/C++-Optimierungscompiler Version 19.16.27034 für x86
Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.

test.cpp
Microsoft (R) Incremental Linker Version 14.16.27034.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:test.exe
test.obj

E:\projekte\JSON-XOP\src>test.exe
3e+00

Tested with f675cb8 (Remove redundant cast, 2019-12-08).

@vitaut
Copy link
Contributor Author

vitaut commented Dec 11, 2019

Fixed form still uses sprintf as a fallback which is why you get different results (MSVC does rounding incorrectly).

@t-b
Copy link

t-b commented Dec 12, 2019

@vitaut Thanks, but I'm using e which is exponential notation or? Could you give me a hint were the code needs fixing?

@vitaut
Copy link
Contributor Author

vitaut commented Dec 12, 2019

I'm using e which is exponential notation or?

By fixed I meant any of e, f, g and their uppercase counterpart which use a given (fixed) precision as opposed to the default shortest representation where precision is determined by the input.

Could you give me a hint were the code needs fixing?

Here's where the fallback is called if Grisu gives up:

return snprintf_float(value, precision, specs, buf);

It needs to be replaced with a fixed-precision equivalent of fallback_format:

void fallback_format(Double d, buffer<char>& buf, int& exp10) {

It might be a fair amount of work mostly to generalize fallback_format to work with a given precision.

@vitaut
Copy link
Contributor Author

vitaut commented Dec 12, 2019

Note that the current behavior is not completely incorrect, it's just that the rounding mode is inconsistent between platforms.

@t-b
Copy link

t-b commented Dec 12, 2019

@vitaut Thanks for the hints!

@vitaut
Copy link
Contributor Author

vitaut commented Sep 7, 2020

{fmt} now uses the correct rounding even on systems with broken printf (e.g. Windows):

  fmt::print("{:.0e}", 2.5);

Output:

2e+00

@t-b
Copy link

t-b commented Sep 7, 2020

@vitaut Thanks for the fix. I've just tested it and it works now for my use case as well.

FYI: We are using fmt inside https://docs.byte-physics.de/json-xop.

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

No branches or pull requests

2 participants