aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Paland <marco@paland.com>2018-08-21 12:37:46 +0200
committerMarco Paland <marco@paland.com>2018-08-21 12:37:46 +0200
commite6b5331a36a5815cc36a9b2872f29234efee72cb (patch)
tree53519bcfd31b2663c749f86ddc1cfdcc388ea911
parent61de9c0cb0738e51625b6071a88921fecd591180 (diff)
downloadprintf-e6b5331a36a5815cc36a9b2872f29234efee72cb.tar.gz
printf-e6b5331a36a5815cc36a9b2872f29234efee72cb.tar.bz2
printf-e6b5331a36a5815cc36a9b2872f29234efee72cb.zip
fix(printf): fix floating point precision limit
Return the correct count of precision digits now. Fixes #22
-rw-r--r--README.md8
-rw-r--r--printf.c18
-rw-r--r--test/test_suite.cpp12
3 files changed, 29 insertions, 9 deletions
diff --git a/README.md b/README.md
index 930207f..eb360fa 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Therefore I decided to write an own, final implementation which meets the follow
- Support of decimal/floating number representation (with an own fast itoa/ftoa)
- Reentrant and thread-safe, malloc free, no static vars/buffers
- LINT and compiler L4 warning free, mature, coverity clean, automotive ready
- - Extensive test suite (> 320 test cases) passing
+ - Extensive test suite (> 330 test cases) passing
- Simply the best *printf* around the net
- MIT license
@@ -167,6 +167,12 @@ int length = sprintf(NULL, "Hello, world"); // length is set to 12
| PRINTF_SUPPORT_PTRDIFF_T | defined | Define this to enable ptrdiff_t (%t) support |
+## Caveats
+- 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.
+ So `printf("%.12f", 42.89522312345678)` gives `42.895223123000`.
+- Exponential floating point format (e.g. `"%.10e"` to get `1.167e+65`) for large numbers is not supported yet. Sorry.
+
+
## Test suite
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().
Running with the `--wait-for-keypress exit` option waits for the enter key after test end.
diff --git a/printf.c b/printf.c
index 0fd6569..c28cf13 100644
--- a/printf.c
+++ b/printf.c
@@ -277,13 +277,14 @@ static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, d
value = 0 - value;
}
- // limit precision
+ // set default precision to 6, if not set explicitly
if (!(flags & FLAGS_PRECISION)) {
- prec = 6U; // by default, precesion is 6
+ prec = 6U;
}
- if (prec > 9U) {
- // precision of >= 10 can lead to overflow errors
- prec = 9U;
+ // limit precision to 9, cause a prec >= 10 can lead to overflow errors
+ while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
+ buf[len++] = '0';
+ prec--;
}
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
else {
unsigned int count = prec;
// now do fractional part, as an unsigned number
- do {
+ while (len < PRINTF_FTOA_BUFFER_SIZE) {
--count;
buf[len++] = (char)(48U + (frac % 10U));
- } while ((len < PRINTF_FTOA_BUFFER_SIZE) && (frac /= 10U));
+ if (!(frac /= 10U)) {
+ break;
+ }
+ }
// add extra 0s
while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
buf[len++] = '0';
diff --git a/test/test_suite.cpp b/test/test_suite.cpp
index 3d7c10d..212fbd3 100644
--- a/test/test_suite.cpp
+++ b/test/test_suite.cpp
@@ -933,7 +933,17 @@ TEST_CASE("float", "[]" ) {
REQUIRE(!strcmp(buffer, "42.895200000"));
test::sprintf(buffer, "%.10f", 42.895223);
- REQUIRE(!strcmp(buffer, "42.895223000"));
+ REQUIRE(!strcmp(buffer, "42.8952230000"));
+
+ // this testcase checks, that the precision is truncated to 9 digits.
+ // a perfect working float should return the whole number
+ test::sprintf(buffer, "%.12f", 42.89522312345678);
+ REQUIRE(!strcmp(buffer, "42.895223123000"));
+
+ // this testcase checks, that the precision is truncated AND rounded to 9 digits.
+ // a perfect working float should return the whole number
+ test::sprintf(buffer, "%.12f", 42.89522387654321);
+ REQUIRE(!strcmp(buffer, "42.895223877000"));
test::sprintf(buffer, "%6.2f", 42.8952);
REQUIRE(!strcmp(buffer, " 42.90"));