As per #27 this PR address deficiencies in handling floating point numbers.
Because JSON defines numbers using both standard decimal notation (e.g. 3.14) and exponential/engineering form (e.g. 3e6), this library should support those as well. Converting those values into floating point form can be done using strtof or strtod, but the 'e' and 'g' formats for printf are not available. Newlib doesn't link these and the Sming m_printf uses a dtostrf function which is quite limited.
One other important point is that very large or very small (but low-precision) numbers can be useful. For example, 1e15 or 3.14e8. These two are also integers, but expressed more concisely. Typical use cases might be expressing storage sizes (megabytes, gigabytes) or small timing values (nanoseconds, picoseconds).
This PR adds the number_t union, which stores a floating point number as a decimal (modulo-10) mantissa and base 10 exponent in a 32-bit value. This is much easier to work with than base 2 (although not suitable for computation) and avoids weird rounding errors.
So 3.14, for example, can be stored as {314, -2} or 314e-2. A further advantage of this is that scaling values by factors of 10 can be done by manually adjusting the exponent, no floating-point math is required.
The Number class provides methods for printing and parsing of these values, and is used in the code generator for number fields. Values can be manipulated as strings, floats, integers or raw number_t structures.
One reason for separate number_t and Number definitions is because on the esp8266, values in flash must be 32-bit aligned and cannot be packed. However, ConfigDB data structures are packed for memory efficiency so are not aligned. The two definitions meet these conflicting requirements.
TODO:
[ ] Handle overflow and underflow by clipping to specified minimum / maximum values
As per #27 this PR address deficiencies in handling floating point numbers.
Because JSON defines numbers using both standard decimal notation (e.g. 3.14) and exponential/engineering form (e.g. 3e6), this library should support those as well. Converting those values into floating point form can be done using
strtof
orstrtod
, but the 'e' and 'g' formats for printf are not available. Newlib doesn't link these and the Smingm_printf
uses adtostrf
function which is quite limited.One other important point is that very large or very small (but low-precision) numbers can be useful. For example,
1e15
or3.14e8
. These two are also integers, but expressed more concisely. Typical use cases might be expressing storage sizes (megabytes, gigabytes) or small timing values (nanoseconds, picoseconds).This PR adds the
number_t
union, which stores a floating point number as a decimal (modulo-10) mantissa and base 10 exponent in a 32-bit value. This is much easier to work with than base 2 (although not suitable for computation) and avoids weird rounding errors.So 3.14, for example, can be stored as
{314, -2}
or 314e-2. A further advantage of this is that scaling values by factors of 10 can be done by manually adjusting the exponent, no floating-point math is required.The
Number
class provides methods for printing and parsing of these values, and is used in the code generator fornumber
fields. Values can be manipulated as strings, floats, integers or raw number_t structures.One reason for separate
number_t
andNumber
definitions is because on the esp8266, values in flash must be 32-bit aligned and cannot be packed. However, ConfigDB data structures are packed for memory efficiency so are not aligned. The two definitions meet these conflicting requirements.TODO: