33#include <NDEVR/String.h>
34#include <NDEVR/BaseValues.h>
35#include <NDEVR/NumberParser.h>
40 static const fltp08 kPowersOfTen[23] =
42 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
43 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
50 return kPowersOfTen[exp];
57 static constexpr fltp08 kLog2_10 = 0.30102999566398119521373889472449;
58 static constexpr uint04 maxBase2Precision = 53;
59 static constexpr uint08 two_pow_maxBase2PrecisionMinus1 =
uint08(1) << (maxBase2Precision - 1);
62 if (0 < exp && exp < 64)
78 lowOk = highOk =
true;
83 lowOk = highOk = round;
91 if (
mantissa != two_pow_maxBase2PrecisionMinus1)
93 const fltp08 be = quickPowTwo(
e);
111 else if (
mantissa != two_pow_maxBase2PrecisionMinus1)
115 ds = quickPowTwo(1 -
e);
122 ds = quickPowTwo(2 -
e);
128 const fltp08 fixedPrecisionPowTen = quickPowTen(minPrecision);
129 ds *= fixedPrecisionPowTen;
130 dr *= fixedPrecisionPowTen;
136 fltp08 fracMantissa = std::frexp(v, eptr);
138 return (uint64_t)(fracMantissa * (double)(1LL << 53));
145 bool withinLowEndRoundRange;
146 bool withinHighEndRoundRange;
150 lib_assert(quotient < 10, "quotient cannot be > 9
");
151 double mod = fmod(dr, ds);
154 // check if remaining ratio r/s is within the range of floats which would round to the value we have output
155 // so far when read in from a string.
156 withinLowEndRoundRange = (lowOk ? (dr <= dMMinus) : (dr < dMMinus));
157 withinHighEndRoundRange = (highOk ? (dr + dMPlus >= ds) : (dr + dMPlus > ds));
160 if (!withinLowEndRoundRange)
162 if (!withinHighEndRoundRange) // if not within either error range, set up to generate the next digit.
174 else if (!withinHighEndRoundRange)
180 if (dr * 2 < ds) // if (r*2 < s) todo: faster to do lshift and compare?
192 sint04 expBase10() { return base10Exp; }
194 fltp08 value; // Double value for quick work when e and mantissa are small.
196 uint08 mantissa; // On input, value = mantissa*2^e; Only last 53 bits are used.
197 sint04 mantissaPrec; // The number of bits of precision that are present in the mantissa.
198 sint04 base10Exp; // The (derived) base 10 exponent of value.
199 bool finished; // Set to true when we've output all relevant digits.
202 bool lowOk; // For IEEE unbiased rounding, this is true when mantissa is even. When true, use >= in mMinus test instead of >
203 bool highOk; // Ditto, but for mPlus test.
205 // If !bFastEstimateOk, use these.
207 // If bFastEstimateOk, use these - same as above, but integer value stored in double.
213 // Estimate base 10 exponent of number, scale r,s,mPlus,mMinus appropriately.
214 // Returns result of fixup_ExponentEstimate(est).
217 // estimate base10 exponent:
218 sint04 base2Exponent = e + mantissaPrec - 1;
219 sint04 exponentEstimate = (sint04)ceil((base2Exponent * kLog2_10) - 0.0000000001);
221 fltp08 scale = quickPowTen((exponentEstimate > 0) ? exponentEstimate : -exponentEstimate);
223 if (exponentEstimate >= 0)
226 return fixup_ExponentEstimate(exponentEstimate);
233 return fixup_ExponentEstimate(exponentEstimate);
237 // Used by scale to adjust for possible off-by-one error in the base 10 exponent estimate.
238 // Returns exact base10 exponent of number.
239 sint04 fixup_ExponentEstimate(sint04 exponentEstimate)
241 sint04 correctedEstimate;
242 uint01 quotient = cast<uint01>((dr * 10) / ds);
243 if ((highOk ? (dr + dMPlus) >= ds : dr + dMPlus > ds) || quotient >= 10)
245 correctedEstimate = exponentEstimate + 1;
252 correctedEstimate = exponentEstimate;
254 quotient = cast<uint01>(dr / ds);
255 lib_assert(quotient < 10, "quotient cannot be > 9
");
256 return correctedEstimate;
269 template<class t_type>
270 constexpr static void writeInt(String& string, t_type initial_value)
272 t_type value = initial_value;
273 constexpr uint04 max_digits = maxDigits<t_type>() + (ObjectInfo<t_type>::Unsigned ? 0 : 1U);
274 char digits[max_digits];
275 uint04 index = max_digits;
276 if constexpr (!ObjectInfo<t_type>::Unsigned)
278 if (initial_value < cast<t_type>(0))
279 value = cast<t_type>(0) - value;
289 value = value / cast<t_type>(10);
290 j -= (value * cast<t_type>(10));
291 digits[--index] = (cast<char>(j) + '0');
292 if (value == cast<t_type>(0))
295 if constexpr ((!ObjectInfo<t_type>::Unsigned))
297 if(initial_value < cast<t_type>(0))
298 digits[--index] = '-';
300 string.addAll(&digits[index], max_digits - index);
302 template<class t_type>
303 constexpr static void writeHex(String& string, t_type initial_value)
305 t_type value = initial_value;
306 constexpr uint04 max_digits = maxDigits<t_type>() + (ObjectInfo<t_type>::Unsigned ? 0 : 1U);
307 char digits[max_digits];
308 uint04 index = max_digits;
309 if ((!ObjectInfo<t_type>::Unsigned) && initial_value < cast<t_type>(0))
311 value = cast<t_type>(0) - value;
321 value = value / cast<t_type>(16);
322 j -= (value * cast<t_type>(16));
325 digits[--index] = '0' + cast<char>(j);
330 case 10: digits[--index] = 'A'; break;
331 case 11: digits[--index] = 'B'; break;
332 case 12: digits[--index] = 'C'; break;
333 case 13: digits[--index] = 'D'; break;
334 case 14: digits[--index] = 'E'; break;
335 case 15: digits[--index] = 'F'; break;
338 if (value == cast<t_type>(0))
341 string.addAll(&digits[index], max_digits - index);
344 static void writeFloat(String& string, fltp08 value, flt_to_string mode = DTOSTR_NORMAL, uint01 precision = 10)
346 if (value > Constant<fltp08>::Max)
348 string.addAll("-Infinity
");
351 if (value < Constant<fltp08>::Min)
353 string.addAll("Infinity
");
358 string.addAll("NaN
");
361 if (mode == DTOSTR_NORMAL)
363 sint08 intValue = cast<sint08>(value);
364 if ((value == (double)(intValue)) && ((uint32_t)intValue != 0x80000000))
366 writeInt(string, intValue);
370 const bool negative = value < 0.0;
371 const bool zero = value == 0.0;
376 D2A d2a = D2A(value, mode != DTOSTR_NORMAL, precision);
377 int32_t exp10 = d2a.expBase10() - 1;
391 format = kFixedFraction;
399 case DTOSTR_PRECISION:
404 else if (exp10 >= precision) {
405 format = kExponential;
412 case DTOSTR_EXPONENTIAL:
413 format = kExponential;
417 if (exp10 < 0 && exp10 > -7) {
418 // Number is of form 0.######
419 if (exp10 < -precision) {
420 exp10 = -precision - 1;
424 else if (std::abs(exp10) > 20) { // ECMA spec 9.8.1
425 format = kExponential;
438 digit = d2a.nextDigit();
440 string.add((char)(digit + '0'));
443 digit = (d2a.finished) ? 0 : d2a.nextDigit();
444 string.add((char)(digit + '0'));
448 if (mode == DTOSTR_FIXED)
452 if (mode == DTOSTR_NORMAL)
457 while (!d2a.finished)
458 string.add((char)(d2a.nextDigit() + '0'));
461 else if (digits < precision - 1)
464 for (; digits < precision - 1; digits++)
466 digit = d2a.finished ? 0 : d2a.nextDigit();
467 string.add((char)(digit + '0'));
474 string.add('0'); // Sentinel
476 // Write out leading zeroes
479 while (++exp10 < 10 && digits < precision) {
484 else if (exp10 < 0) {
485 while ((++exp10 < 0) && (precision-- > 0))
488 if (!isNaN(precision))
490 // Write out significand
491 for (; digits < precision; digits++) {
494 if (mode == DTOSTR_NORMAL)
499 string.add((char)(d2a.nextDigit() + '0'));
508 string.add('0'); // Sentinel
511 // Write out leading zeros
514 for (int32_t i = exp10; i < -1; i++) {
519 // Write out significand
521 while (!d2a.finished)
523 string.add((char)(d2a.nextDigit() + '0'));
524 if (mode != DTOSTR_NORMAL && ++i >= precision)
527 if (mode == DTOSTR_PRECISION)
529 while (i++ < precision)
530 string.add((char)(d2a.finished ? '0' : d2a.nextDigit() + '0'));
538 digit = d2a.finished ? 0 : d2a.nextDigit();
539 string.add((char)(digit + '0'));
540 if (((mode == DTOSTR_NORMAL) && !d2a.finished) ||
541 ((mode != DTOSTR_NORMAL) && precision > 1)) {
543 for (int32_t i = 0; i < precision - 1; i++) {
546 if (mode == DTOSTR_NORMAL)
551 string.add((char)(d2a.nextDigit() + '0'));
558 // Clean up zeroes, and place the exponent
563 // Remove trailing zeroes, as might appear in 10e+95
564 while (string.size() > 0 && string.last() == '0')
571 // Place the exponent
576 writeInt(string, exp10);
#define lib_assert(expression, message)
Asserts some logic in the code. Disabled in non debug mode by default. Can be re-enabled in release u...
Definition LibAssert.h:70
Definition NumberWriter.h:56
uint08 n_frexp(double v, int *eptr) const
Definition NumberWriter.h:134
fltp08 value
Definition NumberWriter.h:194
uint08 mantissa
Definition NumberWriter.h:196
sint04 base10Exp
Definition NumberWriter.h:198
bool finished
Definition NumberWriter.h:199
D2A(const fltp08 avalue, bool fixedPrecision, uint04 minPrecision)
Definition NumberWriter.h:69
uint01 nextDigit()
Definition NumberWriter.h:140
sint04 mantissaPrec
Definition NumberWriter.h:197
sint04 e
Definition NumberWriter.h:195
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:98
uint64_t uint08
-Defines an alias representing an 8 byte, unsigned integer -Can represent exact integer values 0 thro...
Definition BaseValues.hpp:132
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:120
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:514
double fltp08
Defines an alias representing an 8 byte floating-point number.
Definition BaseValues.hpp:181
Definition BaseValues.hpp:272