dconv 2.0
C++14 library for printing and parsing floating point numbers
Loading...
Searching...
No Matches
grisu2.hpp
Go to the documentation of this file.
1
25#ifndef __DCONV_GRISU2_HPP__
26#define __DCONV_GRISU2_HPP__
27
28// dconv.
29#include <dconv/grisu.hpp>
30
31// C.
32#include <cassert>
33#include <cstdint>
34
35namespace dconv
36{
37 namespace grisu2
38 {
47 inline void scaledBoundaries (double value, DiyFp& w, DiyFp& minus, DiyFp& plus, int& k) noexcept
48 {
49 w = DiyFp (value);
50 w.normalizedBoundaries (minus, plus);
51
52 const DiyFp& power = grisu::cachedPower (plus._exponent, k);
53 minus *= power;
54 plus *= power;
55 w.normalize ();
56 w *= power;
57 }
58
68 inline void round (char* buffer, int length, uint64_t delta, uint64_t rest, uint64_t tenKappa,
69 uint64_t wpW) noexcept
70 {
71 while ((rest < wpW && delta - rest >= tenKappa) &&
72 (rest + tenKappa < wpW || wpW - rest > rest + tenKappa - wpW))
73 {
74 --buffer[length - 1];
75 rest += tenKappa;
76 }
77 }
78
88 inline void digitsGen (const DiyFp& w, const DiyFp& high, uint64_t delta, char* buffer, int& length,
89 int& k) noexcept
90 {
91 const DiyFp one (static_cast<uint64_t> (1) << -high._exponent, high._exponent);
92 const DiyFp wpW = high - w;
93 uint32_t p1 = static_cast<uint32_t> (high._mantissa >> -one._exponent);
94 uint64_t p2 = high._mantissa & (one._mantissa - 1);
95 int kappa = details::countDigits (p1);
96 length = 0;
97
98 while (kappa > 0)
99 {
100 assert (kappa >= 1 && kappa <= 10);
101 uint32_t d = p1 / details::pow10[kappa - 1];
102 p1 %= details::pow10[kappa - 1];
103 if (d || length)
104 {
105 buffer[length++] = '0' + d;
106 }
107 --kappa;
108 uint64_t rest = (static_cast<uint64_t> (p1) << -one._exponent) + p2;
109 if (rest <= delta)
110 {
111 k += kappa;
112 round (buffer, length, delta, rest, static_cast<uint64_t> (details::pow10[kappa]) << -one._exponent,
113 wpW._mantissa);
114 return;
115 }
116 }
117
118 uint64_t unit = 1;
119 for (;;)
120 {
121 assert (unit <= UINT64_MAX / 10);
122 p2 *= 10;
123 delta *= 10;
124 unit *= 10;
125 char d = static_cast<char> (p2 >> -one._exponent);
126 buffer[length] = '0' + d;
127 length += (d || length);
128 p2 &= one._mantissa - 1;
129 --kappa;
130 if (p2 < delta)
131 {
132 k += kappa;
133 round (buffer, length, delta, p2, one._mantissa, wpW._mantissa * unit);
134 return;
135 }
136 }
137 }
138
146 inline void generate (char* buffer, int& length, int& k, double value) noexcept
147 {
148 DiyFp w, minus, plus;
149 scaledBoundaries (value, w, minus, plus, k);
150
151 ++minus._mantissa;
152 --plus._mantissa;
153
154 digitsGen (w, plus, plus._mantissa - minus._mantissa, buffer, length, k);
155 }
156
163 inline char* dtoa (char* buffer, double value) noexcept
164 {
165 return grisu::details::dtoa (buffer, value, generate);
166 }
167 }
168}
169
170#endif
hand made floating point.
Definition diyfp.hpp:41
constexpr DiyFp & normalize() noexcept
normalize floating point.
Definition diyfp.hpp:104
uint64_t _mantissa
mantissa.
Definition diyfp.hpp:223
int _exponent
exponent.
Definition diyfp.hpp:226
constexpr uint32_t pow10[]
powers of ten that fit in 32 bits.
Definition digits.hpp:36
int countDigits(uint64_t digits) noexcept
count the digits of a decimal significand.
Definition digits.hpp:64
char * dtoa(char *buffer, double value) noexcept
double to string conversion using Grisu2.
Definition grisu2.hpp:163
void round(char *buffer, int length, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t wpW) noexcept
move the last digit closer to the value while it stays within the boundaries.
Definition grisu2.hpp:68
void scaledBoundaries(double value, DiyFp &w, DiyFp &minus, DiyFp &plus, int &k) noexcept
compute the scaled value and its scaled boundaries.
Definition grisu2.hpp:47
void digitsGen(const DiyFp &w, const DiyFp &high, uint64_t delta, char *buffer, int &length, int &k) noexcept
generate the shortest digits within the conservative boundaries.
Definition grisu2.hpp:88
void generate(char *buffer, int &length, int &k, double value) noexcept
write the shortest decimal digits within the conservative boundaries.
Definition grisu2.hpp:146
char * dtoa(char *buffer, double value, void(*generate)(char *, int &, int &, double) noexcept) noexcept
double to string conversion with the given digits generator.
Definition grisu.hpp:50
const DiyFp & cachedPower(int exponent, int &k) noexcept
get the cached power of ten that scales a binary exponent into the digit generation range.
Definition grisu.hpp:79
Definition atod.hpp:47