NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
digit_comparison.h
Go to the documentation of this file.
1#ifndef FASTFLOAT_DIGIT_COMPARISON_H
2#define FASTFLOAT_DIGIT_COMPARISON_H
3
4#include <algorithm>
5#include <cstdint>
6#include <cstring>
7#include <iterator>
8
9#include "float_common.h"
10#include "bigint.h"
11#include "ascii_number.h"
12
13namespace fast_float {
14
15// 1e0 to 1e19
16constexpr static uint64_t powers_of_ten_uint64[] = {
17 1UL, 10UL, 100UL, 1000UL, 10000UL, 100000UL, 1000000UL, 10000000UL, 100000000UL,
18 1000000000UL, 10000000000UL, 100000000000UL, 1000000000000UL, 10000000000000UL,
19 100000000000000UL, 1000000000000000UL, 10000000000000000UL, 100000000000000000UL,
20 1000000000000000000UL, 10000000000000000000UL};
21
22// calculate the exponent, in scientific notation, of the number.
23// this algorithm is not even close to optimized, but it has no practical
24// effect on performance: in order to have a faster algorithm, we'd need
25// to slow down performance for faster algorithms, and this is still fast.
27 uint64_t mantissa = num.mantissa;
28 int32_t exponent = int32_t(num.exponent);
29 while (mantissa >= 10000) {
30 mantissa /= 10000;
31 exponent += 4;
32 }
33 while (mantissa >= 100) {
34 mantissa /= 100;
35 exponent += 2;
36 }
37 while (mantissa >= 10) {
38 mantissa /= 10;
39 exponent += 1;
40 }
41 return exponent;
42}
43
44// this converts a native floating-point number to an extended-precision float.
45template <typename T>
47 using equiv_uint = typename binary_format<T>::equiv_uint;
48 constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
49 constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
50 constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
51
54 equiv_uint bits;
55 ::memcpy(&bits, &value, sizeof(T));
56 if ((bits & exponent_mask) == 0) {
57 // denormal
58 am.power2 = 1 - bias;
59 am.mantissa = bits & mantissa_mask;
60 } else {
61 // normal
62 am.power2 = int32_t((bits & exponent_mask) >> binary_format<T>::mantissa_explicit_bits());
63 am.power2 -= bias;
64 am.mantissa = (bits & mantissa_mask) | hidden_bit_mask;
65 }
66
67 return am;
68}
69
70// get the extended precision value of the halfway point between b and b+u.
71// we are given a native float that represents b, so we need to adjust it
72// halfway between b and b+u.
73template <typename T>
76 am.mantissa <<= 1;
77 am.mantissa += 1;
78 am.power2 -= 1;
79 return am;
80}
81
82// round an extended-precision float to the nearest machine float.
83template <typename T, typename callback>
84fastfloat_really_inline void round(adjusted_mantissa& am, callback cb) noexcept {
85 int32_t mantissa_shift = 64 - binary_format<T>::mantissa_explicit_bits() - 1;
86 if (-am.power2 >= mantissa_shift) {
87 // have a denormal float
88 int32_t shift = -am.power2 + 1;
89 cb(am, std::min<int32_t>(shift, 64));
90 // check for round-up: if rounding-nearest carried us to the hidden bit.
91 am.power2 = (am.mantissa < (uint64_t(1) << binary_format<T>::mantissa_explicit_bits())) ? 0 : 1;
92 return;
93 }
94
95 // have a normal float, use the default shift.
96 cb(am, mantissa_shift);
97
98 // check for carry
99 if (am.mantissa >= (uint64_t(2) << binary_format<T>::mantissa_explicit_bits())) {
100 am.mantissa = (uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
101 am.power2++;
102 }
103
104 // check for infinite: we could have carried to an infinite power
105 am.mantissa &= ~(uint64_t(1) << binary_format<T>::mantissa_explicit_bits());
106 if (am.power2 >= binary_format<T>::infinite_power()) {
108 am.mantissa = 0;
109 }
110}
111
112template <typename callback>
114void round_nearest_tie_even(adjusted_mantissa& am, int32_t shift, callback cb) noexcept {
115 uint64_t mask;
116 uint64_t halfway;
117 if (shift == 64) {
118 mask = UINT64_MAX;
119 } else {
120 mask = (uint64_t(1) << shift) - 1;
121 }
122 if (shift == 0) {
123 halfway = 0;
124 } else {
125 halfway = uint64_t(1) << (shift - 1);
126 }
127 uint64_t truncated_bits = am.mantissa & mask;
128 uint64_t is_above = truncated_bits > halfway;
129 uint64_t is_halfway = truncated_bits == halfway;
130
131 // shift digits into position
132 if (shift == 64) {
133 am.mantissa = 0;
134 } else {
135 am.mantissa >>= shift;
136 }
137 am.power2 += shift;
138
139 bool is_odd = (am.mantissa & 1) == 1;
140 am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above));
141}
142
143fastfloat_really_inline void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
144 if (shift == 64) {
145 am.mantissa = 0;
146 } else {
147 am.mantissa >>= shift;
148 }
149 am.power2 += shift;
150}
151
152fastfloat_really_inline void skip_zeros(const char*& first, const char* last) noexcept {
153 uint64_t val;
154 while (std::distance(first, last) >= 8) {
155 ::memcpy(&val, first, sizeof(uint64_t));
156 if (val != 0x3030303030303030) {
157 break;
158 }
159 first += 8;
160 }
161 while (first != last) {
162 if (*first != '0') {
163 break;
164 }
165 first++;
166 }
167}
168
169// determine if any non-zero digits were truncated.
170// all characters must be valid digits.
171fastfloat_really_inline bool is_truncated(const char* first, const char* last) noexcept {
172 // do 8-bit optimizations, can just compare to 8 literal 0s.
173 uint64_t val;
174 while (std::distance(first, last) >= 8) {
175 ::memcpy(&val, first, sizeof(uint64_t));
176 if (val != 0x3030303030303030) {
177 return true;
178 }
179 first += 8;
180 }
181 while (first != last) {
182 if (*first != '0') {
183 return true;
184 }
185 first++;
186 }
187 return false;
188}
189
191 return is_truncated(s.ptr, s.ptr + s.len());
192}
193
195void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
196 value = value * 100000000 + parse_eight_digits_unrolled(p);
197 p += 8;
198 counter += 8;
199 count += 8;
200}
201
203void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count) noexcept {
204 value = value * 10 + limb(*p - '0');
205 p++;
206 counter++;
207 count++;
208}
209
211void add_native(bigint& big, limb power, limb value) noexcept {
212 big.mul(power);
213 big.add(value);
214}
215
216fastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcept {
217 // need to round-up the digits, but need to avoid rounding
218 // ....9999 to ...10000, which could cause a false halfway point.
219 add_native(big, 10, 1);
220 count++;
221}
222
223// parse the significant digits into a big integer
224inline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept {
225 // try to minimize the number of big integer and scalar multiplication.
226 // therefore, try to parse 8 digits at a time, and multiply by the largest
227 // scalar value (9 or 19 digits) for each step.
228 size_t counter = 0;
229 digits = 0;
230 limb value = 0;
231#ifdef FASTFLOAT_64BIT_LIMB
232 size_t step = 19;
233#else
234 size_t step = 9;
235#endif
236
237 // process all integer digits.
238 const char* p = num.integer.ptr;
239 const char* pend = p + num.integer.len();
240 skip_zeros(p, pend);
241 // process all digits, in increments of step per loop
242 while (p != pend) {
243 while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
244 parse_eight_digits(p, value, counter, digits);
245 }
246 while (counter < step && p != pend && digits < max_digits) {
247 parse_one_digit(p, value, counter, digits);
248 }
249 if (digits == max_digits) {
250 // add the temporary value, then check if we've truncated any digits
251 add_native(result, limb(powers_of_ten_uint64[counter]), value);
252 bool truncated = is_truncated(p, pend);
253 if (num.fraction.ptr != nullptr) {
254 truncated |= is_truncated(num.fraction);
255 }
256 if (truncated) {
257 round_up_bigint(result, digits);
258 }
259 return;
260 } else {
261 add_native(result, limb(powers_of_ten_uint64[counter]), value);
262 counter = 0;
263 value = 0;
264 }
265 }
266
267 // add our fraction digits, if they're available.
268 if (num.fraction.ptr != nullptr) {
269 p = num.fraction.ptr;
270 pend = p + num.fraction.len();
271 if (digits == 0) {
272 skip_zeros(p, pend);
273 }
274 // process all digits, in increments of step per loop
275 while (p != pend) {
276 while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && (max_digits - digits >= 8)) {
277 parse_eight_digits(p, value, counter, digits);
278 }
279 while (counter < step && p != pend && digits < max_digits) {
280 parse_one_digit(p, value, counter, digits);
281 }
282 if (digits == max_digits) {
283 // add the temporary value, then check if we've truncated any digits
284 add_native(result, limb(powers_of_ten_uint64[counter]), value);
285 bool truncated = is_truncated(p, pend);
286 if (truncated) {
287 round_up_bigint(result, digits);
288 }
289 return;
290 } else {
291 add_native(result, limb(powers_of_ten_uint64[counter]), value);
292 counter = 0;
293 value = 0;
294 }
295 }
296 }
297
298 if (counter != 0) {
299 add_native(result, limb(powers_of_ten_uint64[counter]), value);
300 }
301}
302
303template <typename T>
304inline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept {
305 FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent)));
306 adjusted_mantissa answer;
307 bool truncated;
308 answer.mantissa = bigmant.hi64(truncated);
310 answer.power2 = bigmant.bit_length() - 64 + bias;
311
312 round<T>(answer, [truncated](adjusted_mantissa& a, int32_t shift) {
313 round_nearest_tie_even(a, shift, [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool {
314 return is_above || (is_halfway && truncated) || (is_odd && is_halfway);
315 });
316 });
317
318 return answer;
319}
320
321// the scaling here is quite simple: we have, for the real digits `m * 10^e`,
322// and for the theoretical digits `n * 2^f`. Since `e` is always negative,
323// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`.
324// we then need to scale by `2^(f- e)`, and then the two significant digits
325// are of the same magnitude.
326template <typename T>
327inline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
328 bigint& real_digits = bigmant;
329 int32_t real_exp = exponent;
330
331 // get the value of `b`, rounded down, and get a bigint representation of b+h
332 adjusted_mantissa am_b = am;
333 // gcc7 buf: use a lambda to remove the noexcept qualifier bug with -Wnoexcept-type.
334 round<T>(am_b, [](adjusted_mantissa&a, int32_t shift) { round_down(a, shift); });
335 T b;
336 to_float(false, am_b, b);
338 bigint theor_digits(theor.mantissa);
339 int32_t theor_exp = theor.power2;
340
341 // scale real digits and theor digits to be same power.
342 int32_t pow2_exp = theor_exp - real_exp;
343 uint32_t pow5_exp = uint32_t(-real_exp);
344 if (pow5_exp != 0) {
345 FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));
346 }
347 if (pow2_exp > 0) {
348 FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp)));
349 } else if (pow2_exp < 0) {
350 FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp)));
351 }
352
353 // compare digits, and use it to director rounding
354 int ord = real_digits.compare(theor_digits);
355 adjusted_mantissa answer = am;
356 round<T>(answer, [ord](adjusted_mantissa& a, int32_t shift) {
357 round_nearest_tie_even(a, shift, [ord](bool is_odd, bool _, bool __) -> bool {
358 (void)_; // not needed, since we've done our comparison
359 (void)__; // not needed, since we've done our comparison
360 if (ord > 0) {
361 return true;
362 } else if (ord < 0) {
363 return false;
364 } else {
365 return is_odd;
366 }
367 });
368 });
369
370 return answer;
371}
372
373// parse the significant digits as a big integer to unambiguously round the
374// the significant digits. here, we are trying to determine how to round
375// an extended float representation close to `b+h`, halfway between `b`
376// (the float rounded-down) and `b+u`, the next positive float. this
377// algorithm is always correct, and uses one of two approaches. when
378// the exponent is positive relative to the significant digits (such as
379// 1234), we create a big-integer representation, get the high 64-bits,
380// determine if any lower bits are truncated, and use that to direct
381// rounding. in case of a negative exponent relative to the significant
382// digits (such as 1.2345), we create a theoretical representation of
383// `b` as a big-integer type, scaled to the same binary exponent as
384// the actual digits. we then compare the big integer representations
385// of both, and use that to direct rounding.
386template <typename T>
388 // remove the invalid exponent bias
390
391 int32_t sci_exp = scientific_exponent(num);
392 size_t max_digits = binary_format<T>::max_digits();
393 size_t digits = 0;
394 bigint bigmant;
395 parse_mantissa(bigmant, num, max_digits, digits);
396 // can't underflow, since digits is at most max_digits.
397 int32_t exponent = sci_exp + 1 - int32_t(digits);
398 if (exponent >= 0) {
399 return positive_digit_comp<T>(bigmant, exponent);
400 } else {
401 return negative_digit_comp<T>(bigmant, am, exponent);
402 }
403}
404
405} // namespace fast_float
406
407#endif
#define FASTFLOAT_ASSERT(x)
Definition: float_common.h:80
#define fastfloat_really_inline
Definition: float_common.h:76
CONSTDATA date::last_spec last
Definition: date.h:1989
constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept
fastfloat_really_inline adjusted_mantissa to_extended_halfway(T value) noexcept
fastfloat_really_inline void round_down(adjusted_mantissa &am, int32_t shift) noexcept
fastfloat_really_inline void parse_one_digit(const char *&p, limb &value, size_t &counter, size_t &count) noexcept
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value)
Definition: float_common.h:377
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(uint64_t val)
Definition: ascii_number.h:47
fastfloat_really_inline int32_t scientific_exponent(parsed_number_string &num) noexcept
static constexpr int32_t invalid_am_bias
Definition: float_common.h:215
fastfloat_really_inline void parse_eight_digits(const char *&p, limb &value, size_t &counter, size_t &count) noexcept
adjusted_mantissa digit_comp(parsed_number_string &num, adjusted_mantissa am) noexcept
fastfloat_really_inline void skip_zeros(const char *&first, const char *last) noexcept
fastfloat_really_inline void round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, callback cb) noexcept
fastfloat_really_inline bool is_truncated(const char *first, const char *last) noexcept
adjusted_mantissa negative_digit_comp(bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept
fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept
void parse_mantissa(bigint &result, parsed_number_string &num, size_t max_digits, size_t &digits) noexcept
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
fastfloat_really_inline void round_up_bigint(bigint &big, size_t &count) noexcept
static constexpr uint64_t powers_of_ten_uint64[]
uint32_t limb
Definition: bigint.h:25
fastfloat_really_inline void add_native(bigint &big, limb power, limb value) noexcept
adjusted_mantissa positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept
CONSTDATA solar_hijri::month ord
Definition: solar_hijri.h:1384
bool pow2(uint32_t exp) noexcept
Definition: bigint.h:532
bool pow5(uint32_t exp) noexcept
Definition: bigint.h:537
int compare(const bigint &other) const noexcept
Definition: bigint.h:422
static constexpr int mantissa_explicit_bits()
typename std::conditional< sizeof(T)==4, uint32_t, uint64_t >::type equiv_uint
Definition: float_common.h:224
static constexpr equiv_uint hidden_bit_mask()
static constexpr equiv_uint exponent_mask()
static constexpr size_t max_digits()
static constexpr equiv_uint mantissa_mask()
static constexpr int infinite_power()
static constexpr int minimum_exponent()
#define bits
Definition: unzip.cpp:990