Basic definition of base-10 floating point value. More...

#include <Number.h>

Inheritance diagram for ConfigDB::number_t:
Collaboration diagram for ConfigDB::number_t:

Public Member Functions

bool operator== (const number_t &other) const
 
bool operator!= (const number_t &other) const
 
bool sign () const
 
bool operator< (const number_t &other) const
 
bool operator> (const number_t &other) const
 
size_t printTo (Print &p) const
 

Static Public Member Functions

static constexpr const number_t min ()
 Smallest positive value. More...
 
static constexpr const number_t max ()
 Largest positive value. More...
 
static constexpr const number_t lowest ()
 Most negative value. More...
 
static double asFloat (number_t number)
 
static int64_t asInt64 (number_t number)
 
static int compare (number_t num1, number_t num2)
 
static const char * format (char *buf, number_t number)
 Convert number to string. More...
 
static bool parse (const char *value, unsigned length, number_t &number)
 
static number_t parse (const char *value, unsigned length)
 
static constexpr number_t normalise (unsigned mantissa, int exponent, bool isNeg)
 Produce a normalised number_t from component values. More...
 
static constexpr number_t normalise (double mantissa)
 
static constexpr number_t normalise (int mantissa, int exponent)
 
static constexpr number_t normalise (int64_t value)
 

Public Attributes

int32_t mantissa: 26
 
int32_t exponent: 6
 

Static Public Attributes

static constexpr unsigned maxMantissa {0x1ffffff}
 
static constexpr int maxExponent {0x1f}
 
static constexpr unsigned maxSignificantDigits {8}
 
static constexpr unsigned minBufferSize {17}
 

Detailed Description

Basic definition of base-10 floating point value.

    value = mantissa * 10^exponent

This format is aimed to be a simple and transparent way to store floating-point numbers without the weird rounding issues of IEEE754 base-2 float / double.

Conversion to floating-point format is only done when required by the application. This can be avoided completely by using strings instead of floats to set values.

Constant values can also be specified which are converted at compile-time. See const_number_t.

Integer values can also be specified, but may be subject to rounding if too precise. Very large (or small) values can be used, such as 1.5e25. This would actually be stored as 15e4 {15, 24}.

It does not need to be computationally efficient, but does have advantages:

    - structure is transparent
- Base-10 operations can be performed efficiently without rounding errors
- Serialising (converting to strings) and de-serialising is consistent and JSON-compatible

Some similarity to python's Decimal class, but with restriction on significant digits and exponent.

The initial version of this used 24 bits for the mantissa, but 8 bits for the exponent is overkill. Reducing exponent to 6 bits increases precision by 2 bits to give: smallest: 1e-31 largest: 33554431e31 (3.3554431e38)

Numbers always have a valid representation for ease of use and JSON compatibility. There is no definition for 'NaN' (not a number) or 'infinity. Values are never rounded down to 0, but clipped to the above valid range. Thus convering any number smaller than 1e-31 (but > 0) is stored as 1e-31. Applications can consider number_t::min() and number_t::max() as the 'overflow' values. As with the C++ STL, lowest() indicates the most negative value which is equivalent to -max().

The mantissa/exponent fields can be manipulated directly if required. For example, to convert terabytes to gigabytes we just subtract 3 from the exponent.

An example of custom arithmetic:

        number_t multiplyBy2000(number_t value)
        {
            value.mantissa *= 2;
            value.exponent += 3;
            return value;
        }

If there's a risk of over/under flowing in the calculation, do this:

        number_t multiplyBy2000(number_t value)
        {
            int mantissa = value.mantissa * 2;
            int exponent = value.exponent + 3;
            return number_t::normalise(mantissa, exponent);
        }

, avoiding overflow risk, multiplying a number by 2000 int mantissa = number.mantissa; int exponent = number.exponent; mantissa *= 2; exponent += 3; number_t new_number = number_t::normalise(number);

Note
This structure is not packed to ensure values stored in flash behave correctly.

Member Function Documentation

◆ asFloat()

static double ConfigDB::number_t::asFloat ( number_t  number)
static

◆ asInt64()

static int64_t ConfigDB::number_t::asInt64 ( number_t  number)
static

◆ compare()

static int ConfigDB::number_t::compare ( number_t  num1,
number_t  num2 
)
static

◆ format()

static const char* ConfigDB::number_t::format ( char *  buf,
number_t  number 
)
static

Convert number to string.

Parameters
bufBuffer of at least number_t::minBufferSize
number
Return values
char*Points to string, may not be start of buf
Note
Always use return value to give implementation flexible use of buffer

◆ lowest()

static constexpr const number_t ConfigDB::number_t::lowest ( )
inlinestaticconstexpr

Most negative value.

◆ max()

static constexpr const number_t ConfigDB::number_t::max ( )
inlinestaticconstexpr

Largest positive value.

◆ min()

static constexpr const number_t ConfigDB::number_t::min ( )
inlinestaticconstexpr

Smallest positive value.

◆ normalise() [1/4]

static constexpr number_t ConfigDB::number_t::normalise ( double  mantissa)
inlinestaticconstexpr

◆ normalise() [2/4]

static constexpr number_t ConfigDB::number_t::normalise ( int  mantissa,
int  exponent 
)
inlinestaticconstexpr

◆ normalise() [3/4]

static constexpr number_t ConfigDB::number_t::normalise ( int64_t  value)
inlinestaticconstexpr

◆ normalise() [4/4]

static constexpr number_t ConfigDB::number_t::normalise ( unsigned  mantissa,
int  exponent,
bool  isNeg 
)
inlinestaticconstexpr

Produce a normalised number_t from component values.

Parameters
mantissaMantissa without sign, containing significant digits
exponentExponent
isNegtrue if mantissa is negative, false if positive
Return values
number_tNormalised number value For example, 1000e9 and 10e11 are normalised to 1e12. This allows values to be directly compared for equality.

Mantissa has trailing 0's removed, although may be required for large negative exponents. For example, 100000e-30 exponent is at limit so cannot be reduced further.

If necessary, the mantissa is rounded to the nearest whole value. For example, 3141592654 is rounded up to 31415927.

If the value is out of range, number_t::overflow is returned.

◆ operator!=()

bool ConfigDB::number_t::operator!= ( const number_t other) const
inline

◆ operator<()

bool ConfigDB::number_t::operator< ( const number_t other) const
inline

◆ operator==()

bool ConfigDB::number_t::operator== ( const number_t other) const
inline

◆ operator>()

bool ConfigDB::number_t::operator> ( const number_t other) const
inline

◆ parse() [1/2]

static number_t ConfigDB::number_t::parse ( const char *  value,
unsigned  length 
)
inlinestatic

◆ parse() [2/2]

static bool ConfigDB::number_t::parse ( const char *  value,
unsigned  length,
number_t number 
)
static

◆ printTo()

size_t ConfigDB::number_t::printTo ( Print p) const
inline

◆ sign()

bool ConfigDB::number_t::sign ( ) const
inline

Member Data Documentation

◆ exponent

int32_t ConfigDB::number_t::exponent

◆ mantissa

int32_t ConfigDB::number_t::mantissa

◆ maxExponent

constexpr int ConfigDB::number_t::maxExponent {0x1f}
staticconstexpr

◆ maxMantissa

constexpr unsigned ConfigDB::number_t::maxMantissa {0x1ffffff}
staticconstexpr

◆ maxSignificantDigits

constexpr unsigned ConfigDB::number_t::maxSignificantDigits {8}
staticconstexpr

◆ minBufferSize

constexpr unsigned ConfigDB::number_t::minBufferSize {17}
staticconstexpr

The documentation for this struct was generated from the following file: