Number.h
Go to the documentation of this file.
1 
20 #pragma once
21 
22 #include <WString.h>
23 #include <Print.h>
24 #include <Data/BitSet.h>
25 #include <cmath>
26 
27 namespace ConfigDB
28 {
99 struct number_t {
100  int32_t mantissa : 26;
101  int32_t exponent : 6;
102 
103  static constexpr unsigned maxMantissa{0x1ffffff}; // 33554431
104  static constexpr int maxExponent{0x1f}; // 31
105  static constexpr unsigned maxSignificantDigits{8};
106  static constexpr unsigned minBufferSize{17};
107 
111  static constexpr const number_t min()
112  {
113  return {1, -maxExponent};
114  }
115 
119  static constexpr const number_t max()
120  {
121  return {maxMantissa, maxExponent};
122  }
123 
127  static constexpr const number_t lowest()
128  {
129  return {-int(maxMantissa), maxExponent};
130  }
131 
132  bool operator==(const number_t& other) const
133  {
134  return mantissa == other.mantissa && exponent == other.exponent;
135  }
136 
137  bool operator!=(const number_t& other) const
138  {
139  return !operator==(other);
140  }
141 
142  bool sign() const
143  {
144  return mantissa < 0;
145  }
146 
147  bool operator<(const number_t& other) const
148  {
149  return compare(*this, other) < 0;
150  }
151 
152  bool operator>(const number_t& other) const
153  {
154  return compare(*this, other) > 0;
155  }
156 
157  static double asFloat(number_t number);
158 
159  static int64_t asInt64(number_t number);
160 
161  size_t printTo(Print& p) const
162  {
163  char buf[minBufferSize];
164  return p.print(format(buf, *this));
165  }
166 
167  static int compare(number_t num1, number_t num2);
168 
176  static const char* format(char* buf, number_t number);
177 
178  static bool parse(const char* value, unsigned length, number_t& number);
179 
180  static number_t parse(const char* value, unsigned length)
181  {
182  number_t num{};
183  parse(value, length, num);
184  return num;
185  }
186 
204  static constexpr number_t normalise(unsigned mantissa, int exponent, bool isNeg)
205  {
206  // A non-zero exponent indicates rounding occurred, so 0 isn't zero!
207  if(mantissa == 0 && exponent != 0) {
208  return number_t{isNeg ? -1 : 1, -number_t::maxExponent};
209  }
210 
211  // Discard non-significant digits
212  while(mantissa > number_t::maxMantissa * 10) {
213  mantissa /= 10;
214  ++exponent;
215  }
216 
217  // Round down
219  auto newMantissa = (mantissa + 5) / 10;
220  if(newMantissa > mantissa) {
221  // Number was rounded up and gained a digit
222  newMantissa /= 10;
223  }
224  mantissa = newMantissa;
225  ++exponent;
226  }
227 
228  // Drop any trailing 0's from mantissa
229  while(mantissa >= 10 && mantissa % 10 == 0 && exponent < number_t::maxExponent) {
230  mantissa /= 10;
231  ++exponent;
232  }
233 
234  // Adjust exponent to keep it in range (without losing precision)
236  mantissa *= 10;
238  break;
239  }
240  --exponent;
241  }
242 
246  } else if(exponent < -number_t::maxExponent) {
247  mantissa = 1;
249  } else {
251  }
252 
253  return number_t{isNeg ? -int32_t(mantissa) : int32_t(mantissa), exponent};
254  }
255 
256  static constexpr number_t normalise(double mantissa)
257  {
258  // Check for special values. NB. NaN values always fail self-compare
259  if(mantissa == 0 || mantissa != mantissa) {
260  return {};
261  }
262  if(mantissa == std::numeric_limits<double>::infinity()) {
263  return max();
264  }
265  if(mantissa == -std::numeric_limits<double>::infinity()) {
266  return lowest();
267  }
268 
269  // Pull significant digits into integer part
270  int exponent = 0;
271  while(mantissa > -double(number_t::maxMantissa) && mantissa < double(number_t::maxMantissa) &&
273  mantissa *= 10.0;
274  --exponent;
275  }
276  // Reduce integer part to int32 range
277  while(mantissa < -0x7fffffff || mantissa > 0x7fffffff) {
278  mantissa /= 10;
279  ++exponent;
280  }
281 
282  return (mantissa < 0) ? normalise(unsigned(-mantissa), exponent, true)
283  : normalise(unsigned(mantissa), exponent, false);
284  }
285 
286  static constexpr number_t normalise(int mantissa, int exponent)
287  {
288  return normalise(abs(mantissa), exponent, mantissa < 0);
289  }
290 
291  static constexpr number_t normalise(int64_t value)
292  {
293  bool isNeg{false};
294  if(value < 0) {
295  isNeg = true;
296  value = -value;
297  }
298  int exponent = 0;
299  while(value > 0xffffffffll) {
300  value /= 10;
301  ++exponent;
302  }
303  return normalise(unsigned(value), exponent, isNeg);
304  }
305 };
306 
307 static_assert(sizeof(number_t) == 4, "Bad number_t size");
308 
327 struct const_number_t : public number_t {
328  const_number_t() = default;
329 
333  constexpr const_number_t(double value) : number_t(normalise(value))
334  {
335  }
336 };
337 
346 class __attribute__((packed)) Number
347 {
348 public:
349  Number() = default;
350 
351  constexpr Number(const number_t& number) : number(number)
352  {
353  }
354 
355  constexpr Number(const const_number_t& number) : number(number)
356  {
357  }
358 
359  constexpr Number(const Number& number) = default;
360 
361  constexpr Number(double value) : number(number_t::normalise(value))
362  {
363  }
364 
365  constexpr Number(int64_t value) : number(number_t::normalise(value))
366  {
367  }
368 
369  constexpr Number(int value) : Number(int64_t(value))
370  {
371  }
372 
373  constexpr Number(unsigned int value) : Number(int64_t(value))
374  {
375  }
376 
380  Number(const char* value, unsigned length) : number(number_t::parse(value, length))
381  {
382  }
383 
384  Number(const char* value) : Number(value, value ? strlen(value) : 0)
385  {
386  }
387 
388  Number(const String& str) : Number(str.c_str(), str.length())
389  {
390  }
391 
392  bool operator<(const Number& other) const
393  {
394  return number < other.number;
395  }
396 
397  bool operator>(const Number& other) const
398  {
399  return number > other.number;
400  }
401 
402  bool operator==(const number_t& other) const
403  {
404  return number == other;
405  }
406 
407  bool operator!=(const number_t& other) const
408  {
409  return number != other;
410  }
411 
412  int compare(const Number& other) const
413  {
414  return number_t::compare(number, other.number);
415  }
416 
417  size_t printTo(Print& p) const
418  {
419  char buf[number_t::minBufferSize];
420  return p.print(number_t::format(buf, number));
421  }
422 
423  double asFloat() const
424  {
425  return number_t::asFloat(number);
426  }
427 
428  int64_t asInt64() const
429  {
430  return number_t::asInt64(number);
431  }
432 
433  String toString() const
434  {
435  char buf[number_t::minBufferSize];
436  return number_t::format(buf, number);
437  }
438 
439  explicit operator String() const
440  {
441  return toString();
442  }
443 
444  constexpr operator number_t() const
445  {
446  return number;
447  }
448 
449 private:
450  number_t number;
451 };
452 
453 } // namespace ConfigDB
454 
457 
458 inline String toString(number_t number)
459 {
460  return ConfigDB::Number(number).toString();
461 }
#define abs(x)
< sprintf()
Definition: ArduinoCompat.h:22
String toString(number_t number)
Definition: Number.h:458
ConfigDB::const_number_t const_number_t
Definition: Number.h:456
ConfigDB::number_t number_t
Definition: Number.h:455
Base-10 floating-point storage format.
Definition: Number.h:347
Number(const char *value)
Definition: Number.h:384
double asFloat() const
Definition: Number.h:423
int compare(const Number &other) const
Definition: Number.h:412
constexpr Number(const Number &number)=default
bool operator<(const Number &other) const
Definition: Number.h:392
Number()=default
Number(const char *value, unsigned length)
Parse a number from a string.
Definition: Number.h:380
constexpr Number(const number_t &number)
Definition: Number.h:351
constexpr Number(int64_t value)
Definition: Number.h:365
bool operator>(const Number &other) const
Definition: Number.h:397
String toString() const
Definition: Number.h:433
constexpr Number(int value)
Definition: Number.h:369
size_t printTo(Print &p) const
Definition: Number.h:417
Number(const String &str)
Definition: Number.h:388
bool operator!=(const number_t &other) const
Definition: Number.h:407
int64_t asInt64() const
Definition: Number.h:428
constexpr Number(double value)
Definition: Number.h:361
constexpr Number(unsigned int value)
Definition: Number.h:373
bool operator==(const number_t &other) const
Definition: Number.h:402
constexpr Number(const const_number_t &number)
Definition: Number.h:355
Provides formatted output to stream.
Definition: Print.h:37
size_t print(char c)
Prints a single character to output stream.
Definition: Print.h:103
The String class.
Definition: WString.h:133
Definition: Array.h:26
Compile-time constant number.
Definition: Number.h:327
constexpr const_number_t(double value)
Computer number from a compile-time constant value.
Definition: Number.h:333
Basic definition of base-10 floating point value.
Definition: Number.h:99
static constexpr const number_t lowest()
Most negative value.
Definition: Number.h:127
static number_t parse(const char *value, unsigned length)
Definition: Number.h:180
static constexpr const number_t min()
Smallest positive value.
Definition: Number.h:111
static constexpr number_t normalise(int mantissa, int exponent)
Definition: Number.h:286
static constexpr number_t normalise(unsigned mantissa, int exponent, bool isNeg)
Produce a normalised number_t from component values.
Definition: Number.h:204
static constexpr number_t normalise(double mantissa)
Definition: Number.h:256
bool sign() const
Definition: Number.h:142
static int compare(number_t num1, number_t num2)
size_t printTo(Print &p) const
Definition: Number.h:161
bool operator<(const number_t &other) const
Definition: Number.h:147
static constexpr unsigned minBufferSize
Definition: Number.h:106
static constexpr const number_t max()
Largest positive value.
Definition: Number.h:119
static const char * format(char *buf, number_t number)
Convert number to string.
bool operator!=(const number_t &other) const
Definition: Number.h:137
static bool parse(const char *value, unsigned length, number_t &number)
static constexpr number_t normalise(int64_t value)
Definition: Number.h:291
bool operator>(const number_t &other) const
Definition: Number.h:152
static constexpr unsigned maxSignificantDigits
Definition: Number.h:105
static constexpr int maxExponent
Definition: Number.h:104
static int64_t asInt64(number_t number)
static constexpr unsigned maxMantissa
Definition: Number.h:103
int32_t mantissa
Definition: Number.h:100
bool operator==(const number_t &other) const
Definition: Number.h:132
static double asFloat(number_t number)
int32_t exponent
Definition: Number.h:101
#define str(s)
Definition: testrunner.h:124