dconv 2.0
C++14 library for printing and parsing floating point numbers
Loading...
Searching...
No Matches
grisu3.hpp
Go to the documentation of this file.
1
25#ifndef __DCONV_GRISU3_HPP__
26#define __DCONV_GRISU3_HPP__
27
28// dconv.
29#include <dconv/grisu2.hpp>
30
31// C++.
32#include <charconv>
33
34// C.
35#include <cstdint>
36
37namespace dconv
38{
39 namespace grisu3
40 {
52 inline bool roundWeed (char* buffer, int length, uint64_t wpW, uint64_t delta, uint64_t rest, uint64_t tenKappa,
53 uint64_t ulp) noexcept
54 {
55 const uint64_t wpWup = wpW - ulp;
56 const uint64_t wpWdown = wpW + ulp;
57
58 while ((rest < wpWup) && (delta - rest >= tenKappa) &&
59 ((rest + tenKappa < wpWup) || (wpWup - rest >= rest + tenKappa - wpWup)))
60 {
61 --buffer[length - 1];
62 rest += tenKappa;
63 }
64
65 if ((rest < wpWdown) && (delta - rest >= tenKappa) &&
66 ((rest + tenKappa < wpWdown) || (wpWdown - rest > rest + tenKappa - wpWdown)))
67 {
68 return false;
69 }
70
71 return (2 * ulp <= rest) && (rest <= delta - 4 * ulp);
72 }
73
84 inline bool digitsGen (const DiyFp& low, const DiyFp& w, const DiyFp& high, char* buffer, int& length,
85 int& k) noexcept
86 {
87 uint64_t unit = 1;
88 const uint64_t tooLow = low._mantissa - unit;
89 const uint64_t tooHigh = high._mantissa + unit;
90 uint64_t unsafe = tooHigh - tooLow;
91
92 const DiyFp one (static_cast<uint64_t> (1) << -w._exponent, w._exponent);
93 uint32_t p1 = static_cast<uint32_t> (tooHigh >> -one._exponent);
94 uint64_t p2 = tooHigh & (one._mantissa - 1);
95 int kappa = details::countDigits (p1);
96 length = 0;
97
98 while (kappa > 0)
99 {
100 buffer[length++] = static_cast<char> ('0' + p1 / details::pow10[kappa - 1]);
101 p1 %= details::pow10[kappa - 1];
102 --kappa;
103
104 const uint64_t rest = (static_cast<uint64_t> (p1) << -one._exponent) + p2;
105 if (rest < unsafe)
106 {
107 k += kappa;
108 return roundWeed (buffer, length, tooHigh - w._mantissa, unsafe, rest,
109 static_cast<uint64_t> (details::pow10[kappa]) << -one._exponent, unit);
110 }
111 }
112
113 for (;;)
114 {
115 p2 *= 10;
116 unit *= 10;
117 unsafe *= 10;
118 buffer[length++] = static_cast<char> ('0' + (p2 >> -one._exponent));
119 p2 &= one._mantissa - 1;
120 --kappa;
121
122 if (p2 < unsafe)
123 {
124 k += kappa;
125 return roundWeed (buffer, length, (tooHigh - w._mantissa) * unit, unsafe, p2, one._mantissa, unit);
126 }
127 }
128 }
129
137 inline void fallback (char* buffer, int& length, int& k, double value) noexcept
138 {
139 char text[32];
140 const char* end = std::to_chars (text, text + sizeof (text), value, std::chars_format::scientific).ptr;
141 const char* cur = text;
142
143 length = 0;
144 for (; *cur != 'e'; ++cur)
145 {
146 if (*cur != '.')
147 {
148 buffer[length++] = *cur;
149 }
150 }
151
152 int exponent = 0;
153 std::from_chars (cur + 2, end, exponent);
154 k = ((cur[1] == '-') ? -exponent : exponent) - (length - 1);
155 }
156
164 inline void generate (char* buffer, int& length, int& k, double value) noexcept
165 {
166 DiyFp w, minus, plus;
167 grisu2::scaledBoundaries (value, w, minus, plus, k);
168
169 if (!digitsGen (minus, w, plus, buffer, length, k))
170 {
171 fallback (buffer, length, k, value);
172 }
173 }
174
181 inline char* dtoa (char* buffer, double value) noexcept
182 {
183 return grisu::details::dtoa (buffer, value, generate);
184 }
185 }
186}
187
188#endif
hand made floating point.
Definition diyfp.hpp:41
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
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
bool digitsGen(const DiyFp &low, const DiyFp &w, const DiyFp &high, char *buffer, int &length, int &k) noexcept
generate the shortest digits within the liberal boundaries.
Definition grisu3.hpp:84
void fallback(char *buffer, int &length, int &k, double value) noexcept
write the shortest and closest decimal digits using the standard library.
Definition grisu3.hpp:137
char * dtoa(char *buffer, double value) noexcept
double to string conversion using Grisu3.
Definition grisu3.hpp:181
bool roundWeed(char *buffer, int length, uint64_t wpW, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t ulp) noexcept
round the last digit to the closest value and check it is safe.
Definition grisu3.hpp:52
void generate(char *buffer, int &length, int &k, double value) noexcept
write the shortest and closest decimal digits.
Definition grisu3.hpp:164
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
Definition atod.hpp:47