dconv 2.0
C++14 library for printing and parsing floating point numbers
Loading...
Searching...
No Matches
schubfach.hpp
Go to the documentation of this file.
1
25#ifndef __DCONV_SCHUBFACH_HPP__
26#define __DCONV_SCHUBFACH_HPP__
27
28// dconv.
30#include <dconv/format.hpp>
31
32// C.
33#include <cstring>
34#include <cstdint>
35
36namespace dconv
37{
38 namespace schubfach
39 {
46 constexpr int floorLog10Pow2 (int q, bool asymmetric) noexcept
47 {
48 return (q * 315653 - (asymmetric ? 131008 : 0)) >> 20;
49 }
50
56 constexpr int floorLog2Pow10 (int k) noexcept
57 {
58 return (k * 3483294) >> 20;
59 }
60
67 inline uint64_t roundToOdd (const details::Power& g, uint64_t cp) noexcept
68 {
69 uint64_t middle, unused;
70 details::umul128 (g.lo, cp, middle, unused);
71
72 uint64_t high, low;
73 details::umul128 (g.hi, cp, high, low);
74
75 const uint64_t z = low + middle;
76 high += (z < low);
77 return high | (z != 0);
78 }
79
86 inline uint64_t shortest (double value, int& k) noexcept
87 {
88 uint64_t bits;
89 memcpy (&bits, &value, sizeof (double));
90
91 const uint64_t fraction = bits & 0x000FFFFFFFFFFFFF;
92 const int biased = static_cast<int> (bits >> 52);
93 const uint64_t c = (biased != 0) ? (fraction | 0x0010000000000000) : fraction;
94 const int q = (biased != 0) ? biased - 1075 : -1074;
95
96 if ((static_cast<unsigned> (-q) <= 52) && ((c & ((static_cast<uint64_t> (1) << -q) - 1)) == 0))
97 {
98 k = 0;
99 return c >> -q;
100 }
101
102 const bool asymmetric = (fraction == 0) && (biased > 1);
103 const uint64_t out = c & 1;
104
105 const uint64_t cb = c << 2;
106 const uint64_t cbl = asymmetric ? cb - 1 : cb - 2;
107 const uint64_t cbr = cb + 2;
108
109 k = floorLog10Pow2 (q, asymmetric);
110 const int h = q + floorLog2Pow10 (-k) + 3;
111 const details::Power& g = details::schubfachpow[292 - k];
112
113 const uint64_t vb = roundToOdd (g, cb << h);
114 const uint64_t vbl = roundToOdd (g, cbl << h);
115 const uint64_t vbr = roundToOdd (g, cbr << h);
116
117 const uint64_t s = vb >> 2;
118 const uint64_t sp10 = (s / 10) * 10;
119 const uint64_t tp10 = sp10 + 10;
120 const bool upin = vbl + out <= (sp10 << 2);
121 const bool wpin = (tp10 << 2) + out <= vbr;
122 if (upin != wpin)
123 {
124 uint64_t digits = upin ? s / 10 : s / 10 + 1;
125 ++k;
126 if (digits < 1000000000000000)
127 {
128 digits *= 10;
129 --k;
130 }
131 return digits;
132 }
133
134 const uint64_t t = s + 1;
135 const bool uin = vbl + out <= (s << 2);
136 const bool win = (t << 2) + out <= vbr;
137 if (uin != win)
138 {
139 return uin ? s : t;
140 }
141
142 const int64_t cmp = static_cast<int64_t> (vb - ((s + t) << 1));
143 return ((cmp < 0) || ((cmp == 0) && ((s & 1) == 0))) ? s : t;
144 }
145
153 inline void generate (char* buffer, int& length, int& k, double value) noexcept
154 {
155 const uint64_t digits = shortest (value, k);
156 length = details::countDigits (digits);
157 const int zeros = details::writeDigits (buffer, digits, length);
158 length -= zeros;
159 k += zeros;
160 }
161
168 inline char* dtoa (char* buffer, double value) noexcept
169 {
170 uint64_t bits;
171 memcpy (&bits, &value, sizeof (double));
172 bool is_negative = (bits >> 63) != 0;
173
174 *buffer = '-';
175 buffer += is_negative;
176 value = is_negative ? -value : value;
177
178 if (value == 0.0)
179 {
180 memcpy (buffer, "0.0", 3);
181 return buffer + 3;
182 }
183
184 int k = 0;
185 const uint64_t digits = shortest (value, k);
186 return details::format (buffer, digits, details::countDigits (digits), k);
187 }
188 }
189}
190
191#endif
int countDigits(uint64_t digits) noexcept
count the digits of a decimal significand.
Definition digits.hpp:64
char * format(char *buffer, uint64_t digits, int length, int k) noexcept
write a decimal significand with the same layout as prettify.
Definition format.hpp:143
constexpr Power schubfachpow[]
Definition schubfachpow.hpp:35
void umul128(uint64_t a, uint64_t b, uint64_t &high, uint64_t &low) noexcept
multiply two 64 bits unsigned integers.
Definition power.hpp:52
int writeDigits(char *buffer, uint64_t digits, int length) noexcept
write the digits of a decimal significand.
Definition digits.hpp:108
constexpr int floorLog2Pow10(int k) noexcept
compute floor (log2 (10^k)).
Definition schubfach.hpp:56
char * dtoa(char *buffer, double value) noexcept
double to string conversion using Schubfach.
Definition schubfach.hpp:168
uint64_t shortest(double value, int &k) noexcept
compute the shortest decimal significand.
Definition schubfach.hpp:86
void generate(char *buffer, int &length, int &k, double value) noexcept
write the shortest decimal digits.
Definition schubfach.hpp:153
constexpr int floorLog10Pow2(int q, bool asymmetric) noexcept
compute floor (log10 (2^q)) or floor (log10 (3/4 * 2^q)).
Definition schubfach.hpp:46
uint64_t roundToOdd(const details::Power &g, uint64_t cp) noexcept
multiply by a power of ten and round to odd.
Definition schubfach.hpp:67
Definition atod.hpp:47
128 bits power.
Definition power.hpp:37