Skip to content

Commit

Permalink
Change the error text and retarget the submodule to main
Browse files Browse the repository at this point in the history
  • Loading branch information
Okarss committed Jun 9, 2024
1 parent c785fc1 commit 5368d70
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 16 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ If a disabled format specifier feature is used, no conversion will occur and the
### Floating-Point Conversion
nanoprintf has the following floating-point specific configuration defines.

* `NANOPRINTF_CONVERSION_BUFFER_SIZE`: Optional, defaults to `23`. Sets the size of a character buffer used for storing the converted value. Set to a larger number to enable printing of floating-point numbers with more characters. The buffer size does include the integer part, the fraction part and the decimal separator, but does not include the sign and the padding characters. If the number does not fit into buffer, an `oor` is printed. Be careful with large sizes as the conversion buffer is allocated on stack memory.
* `NANOPRINTF_CONVERSION_BUFFER_SIZE`: Optional, defaults to `23`. Sets the size of a character buffer used for storing the converted value. Set to a larger number to enable printing of floating-point numbers with more characters. The buffer size does include the integer part, the fraction part and the decimal separator, but does not include the sign and the padding characters. If the number does not fit into buffer, an `err` is printed. Be careful with large sizes as the conversion buffer is allocated on stack memory.
* `NANOPRINTF_CONVERSION_FLOAT_TYPE`: Optional, defaults to `unsigned int`. Sets the integer type used for float conversion algorithm, which determines the conversion accuracy. Can be set to any unsigned integer type, like for example `uint64_t` or `uint8_t`.

### Sprintf Safety
Expand Down Expand Up @@ -160,7 +160,7 @@ Like `printf`, `nanoprintf` expects a conversion specification string of the fol

## Floating-Point

Floating-point conversion is performed by extracting the integer and fraction parts of the number into two separate integer variables and then doing a dynamic scaling to bring those values down or up to the decimal separator. The dynamic scaling multiplies and divides the value by 2 and 10 iteratively to keep the most significant bits of the value. The further the value is away from the decimal separator, the more of an error the scaling will accumulate. With an integer width of `N` bits on average the algorithm keeps `N - log2(5)` or `N - 2.322` bits of accuracy. In addition integer parts up to `2 ^^ N - 1` and fraction parts with up to `N - 2.322` bits after the decimal separator are converted perfectly without loosing any bits.
Floating-point conversion is performed by extracting the integer and fraction parts of the number into two separate integer variables. For each part the exponent is then scaled from base-2 to base-10 by iteratively multiplying and dividing the mantissa by 2 and 5 appropriately. The order of the scaling operations is selected dynamically (depending on value) to retain as much of the most significant bits of the mantissa as possible. The further the value is away from the decimal separator, the more of an error the scaling will accumulate. With a conversion integer type width of `N` bits on average the algorithm retains `N - log2(5)` or `N - 2.322` bits of accuracy. In addition integer parts up to `2 ^^ N - 1` and fraction parts with up to `N - 2.322` bits after the decimal separator are converted perfectly without loosing any bits.

Because the float -> fixed code operates on the raw float value bits, no floating-point operations are performed. This allows nanoprintf to efficiently format floats on soft-float architectures like Cortex-M0, to function identically with or without optimizations like "fast math", and to minimize the code footprint.

Expand Down
18 changes: 9 additions & 9 deletions nanoprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
buf[dec++] = '.';
}

{ // integer part
{ // Integer part
npf_ftoa_man_t man_i;

if (exp >= 0) {
Expand All @@ -586,10 +586,10 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
if (shift_i) {
carry = (bin >> (shift_i - 1)) & 0x1;
}
exp = NPF_DOUBLE_MAN_BITS; // disable the fraction part
exp = NPF_DOUBLE_MAN_BITS; // invalidate the fraction part
}

// Scale the integer down to the decimal separator.
// Scale the exponent from base-2 to base-10.
for (; exp_i; --exp_i) {
if (!(man_i & ((npf_ftoa_man_t)0x1 << (NPF_FTOA_MAN_BITS - 1)))) {
man_i = (npf_ftoa_man_t)(man_i << 1);
Expand All @@ -606,15 +606,15 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
}
end = dec;

// print the integer
// Print the integer
do {
if (end >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; }
buf[end++] = (char)('0' + (char)(man_i % 10));
man_i /= 10;
} while (man_i);
}

{ // fraction part
{ // Fraction part
npf_ftoa_man_t man_f;
npf_ftoa_dec_t dec_f = (npf_ftoa_dec_t)spec->prec;

Expand All @@ -632,7 +632,7 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
carry = 0;
}

// Scale the fraction up to the decimal separator and prepare the first digit.
// Scale the exponent from base-2 to base-10 and prepare the first digit.
for (uint_fast8_t digit = 0; dec_f && (exp_f < 4); ++exp_f) {
if ((man_f > ((npf_ftoa_man_t)-4 / 5)) || digit) {
carry = (uint_fast8_t)(man_f & 0x1);
Expand All @@ -655,7 +655,7 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
}

if (dec_f) {
// print the fraction
// Print the fraction
for (;;) {
buf[--dec_f] = (char)('0' + (char)(man_f >> (NPF_FTOA_MAN_BITS - 4)));
man_f = (npf_ftoa_man_t)(man_f & ~((npf_ftoa_man_t)0xF << (NPF_FTOA_MAN_BITS - 4)));
Expand All @@ -669,7 +669,7 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {
}
}

// round the number
// Round the number
for (; carry; ++dec) {
if (dec >= NANOPRINTF_CONVERSION_BUFFER_SIZE) { goto exit; }
if (dec >= end) { buf[end++] = '0'; }
Expand All @@ -680,7 +680,7 @@ static int npf_ftoa_rev(char *buf, npf_format_spec_t const *spec, double f) {

return (int)end;
exit:
if (!ret) { ret = "ROO"; }
if (!ret) { ret = "RRE"; }
uint_fast8_t i;
for (i = 0; ret[i]; ++i) { buf[i] = (char)(ret[i] + spec->case_adjust); }
return (int)i;
Expand Down
2 changes: 1 addition & 1 deletion tests/mpaland-conformance
Submodule mpaland-conformance updated 0 files
8 changes: 4 additions & 4 deletions tests/unit_ftoa_rev.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ TEST_CASE("ftoa_rev") {
require_ftoa_rev("NAN", (double)-NAN);
require_ftoa_rev("INF", (double)+INFINITY);
require_ftoa_rev("INF", (double)-INFINITY);
require_ftoa_rev("OOR", DBL_MAX);
require_ftoa_rev("ERR", DBL_MAX);
spec.prec = NANOPRINTF_CONVERSION_BUFFER_SIZE - 2;
require_ftoa_rev("OOR", 10.);
require_ftoa_rev("ERR", 10.);
spec.prec += 1;
require_ftoa_rev("OOR", 9.);
require_ftoa_rev("ERR", 9.);
spec.case_adjust = 'a' - 'A'; // lowercase
require_ftoa_rev("oor", 0.);
require_ftoa_rev("err", 0.);
}

SUBCASE("zero and decimal separator") {
Expand Down

0 comments on commit 5368d70

Please sign in to comment.