Skip to content

Commit e6b5331

Browse files
committed
fix(printf): fix floating point precision limit
Return the correct count of precision digits now. Fixes #22
1 parent 61de9c0 commit e6b5331

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Therefore I decided to write an own, final implementation which meets the follow
2828
- Support of decimal/floating number representation (with an own fast itoa/ftoa)
2929
- Reentrant and thread-safe, malloc free, no static vars/buffers
3030
- LINT and compiler L4 warning free, mature, coverity clean, automotive ready
31-
- Extensive test suite (> 320 test cases) passing
31+
- Extensive test suite (> 330 test cases) passing
3232
- Simply the best *printf* around the net
3333
- MIT license
3434

@@ -167,6 +167,12 @@ int length = sprintf(NULL, "Hello, world"); // length is set to 12
167167
| PRINTF_SUPPORT_PTRDIFF_T | defined | Define this to enable ptrdiff_t (%t) support |
168168

169169

170+
## Caveats
171+
- The internal floating point conversion has a maximum precision of 9 digits. Any higher precision is truncated after the 9th digit and zeros are returned.
172+
So `printf("%.12f", 42.89522312345678)` gives `42.895223123000`.
173+
- Exponential floating point format (e.g. `"%.10e"` to get `1.167e+65`) for large numbers is not supported yet. Sorry.
174+
175+
170176
## Test suite
171177
For testing just compile, build and run the test suite located in `test/test_suite.cpp`. This uses the [catch](https://github.com/catchorg/Catch2) framework for unit-tests, which is auto-adding main().
172178
Running with the `--wait-for-keypress exit` option waits for the enter key after test end.

printf.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,14 @@ static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d
277277
value = 0 - value;
278278
}
279279

280-
// limit precision
280+
// set default precision to 6, if not set explicitly
281281
if (!(flags & FLAGS_PRECISION)) {
282-
prec = 6U; // by default, precesion is 6
282+
prec = 6U;
283283
}
284-
if (prec > 9U) {
285-
// precision of >= 10 can lead to overflow errors
286-
prec = 9U;
284+
// limit precision to 9, cause a prec >= 10 can lead to overflow errors
285+
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
286+
buf[len++] = '0';
287+
prec--;
287288
}
288289

289290
int whole = (int)value;
@@ -325,10 +326,13 @@ static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d
325326
else {
326327
unsigned int count = prec;
327328
// now do fractional part, as an unsigned number
328-
do {
329+
while (len < PRINTF_FTOA_BUFFER_SIZE) {
329330
--count;
330331
buf[len++] = (char)(48U + (frac % 10U));
331-
} while ((len < PRINTF_FTOA_BUFFER_SIZE) && (frac /= 10U));
332+
if (!(frac /= 10U)) {
333+
break;
334+
}
335+
}
332336
// add extra 0s
333337
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
334338
buf[len++] = '0';

test/test_suite.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,17 @@ TEST_CASE("float", "[]" ) {
933933
REQUIRE(!strcmp(buffer, "42.895200000"));
934934

935935
test::sprintf(buffer, "%.10f", 42.895223);
936-
REQUIRE(!strcmp(buffer, "42.895223000"));
936+
REQUIRE(!strcmp(buffer, "42.8952230000"));
937+
938+
// this testcase checks, that the precision is truncated to 9 digits.
939+
// a perfect working float should return the whole number
940+
test::sprintf(buffer, "%.12f", 42.89522312345678);
941+
REQUIRE(!strcmp(buffer, "42.895223123000"));
942+
943+
// this testcase checks, that the precision is truncated AND rounded to 9 digits.
944+
// a perfect working float should return the whole number
945+
test::sprintf(buffer, "%.12f", 42.89522387654321);
946+
REQUIRE(!strcmp(buffer, "42.895223877000"));
937947

938948
test::sprintf(buffer, "%6.2f", 42.8952);
939949
REQUIRE(!strcmp(buffer, " 42.90"));

0 commit comments

Comments
 (0)