clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name binary-to-decimal.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/flang/lib/Decimal -I /build/source/flang/lib/Decimal -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U _GLIBCXX_ASSERTIONS -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/flang/lib/Decimal/binary-to-decimal.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "big-radix-floating-point.h" |
10 | #include "flang/Decimal/decimal.h" |
11 | #include <cassert> |
12 | #include <cfloat> |
13 | #include <string> |
14 | |
15 | namespace Fortran::decimal { |
16 | |
17 | template <int PREC, int LOG10RADIX> |
18 | BigRadixFloatingPointNumber<PREC, LOG10RADIX>::BigRadixFloatingPointNumber( |
19 | BinaryFloatingPointNumber<PREC> x, enum FortranRounding rounding) |
20 | : rounding_{rounding} { |
21 | bool negative{x.IsNegative()}; |
22 | if (x.IsZero()) { |
23 | isNegative_ = negative; |
24 | return; |
25 | } |
26 | if (negative) { |
27 | x.Negate(); |
28 | } |
29 | int twoPow{x.UnbiasedExponent()}; |
30 | twoPow -= x.bits - 1; |
31 | if (!x.isImplicitMSB) { |
32 | ++twoPow; |
33 | } |
34 | int lshift{x.exponentBits}; |
35 | if (twoPow <= -lshift) { |
36 | twoPow += lshift; |
37 | lshift = 0; |
38 | } else if (twoPow < 0) { |
39 | lshift += twoPow; |
40 | twoPow = 0; |
41 | } |
42 | auto word{x.Fraction()}; |
43 | word <<= lshift; |
44 | SetTo(word); |
45 | isNegative_ = negative; |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | for (; twoPow > 0 && IsDivisibleBy<5>(); --twoPow) { |
56 | DivideBy<5>(); |
57 | ++exponent_; |
58 | } |
59 | |
60 | int overflow{0}; |
61 | for (; twoPow >= 9; twoPow -= 9) { |
62 | |
63 | overflow |= MultiplyBy<512>(); |
64 | } |
65 | for (; twoPow >= 3; twoPow -= 3) { |
66 | |
67 | overflow |= MultiplyBy<8>(); |
68 | } |
69 | for (; twoPow > 0; --twoPow) { |
70 | |
71 | overflow |= MultiplyBy<2>(); |
72 | } |
73 | |
74 | overflow |= DivideByPowerOfTwoInPlace(-twoPow); |
75 | assert(overflow == 0); |
76 | Normalize(); |
77 | } |
78 | |
79 | template <int PREC, int LOG10RADIX> |
80 | ConversionToDecimalResult |
81 | BigRadixFloatingPointNumber<PREC, LOG10RADIX>::ConvertToDecimal(char *buffer, |
82 | std::size_t n, enum DecimalConversionFlags flags, int maxDigits) const { |
83 | if (n < static_cast<std::size_t>(3 + digits_ * LOG10RADIX)) { |
84 | return {nullptr, 0, 0, Overflow}; |
85 | } |
86 | char *start{buffer}; |
87 | if (isNegative_) { |
88 | *start++ = '-'; |
89 | } else if (flags & AlwaysSign) { |
90 | *start++ = '+'; |
91 | } |
92 | if (IsZero()) { |
93 | *start++ = '0'; |
94 | *start = '\0'; |
95 | return {buffer, static_cast<std::size_t>(start - buffer), 0, Exact}; |
96 | } |
97 | char *p{start}; |
98 | static_assert((LOG10RADIX % 2) == 0, "radix not a power of 100"); |
99 | static const char lut[] = "0001020304050607080910111213141516171819" |
100 | "2021222324252627282930313233343536373839" |
101 | "4041424344454647484950515253545556575859" |
102 | "6061626364656667686970717273747576777879" |
103 | "8081828384858687888990919293949596979899"; |
104 | |
105 | Digit dig{digit_[digits_ - 1]}; |
106 | char stack[LOG10RADIX], *sp{stack}; |
107 | for (int k{0}; k < log10Radix; k += 2) { |
108 | Digit newDig{dig / 100}; |
109 | auto d{static_cast<std::uint32_t>(dig) - |
110 | std::uint32_t{100} * static_cast<std::uint32_t>(newDig)}; |
111 | dig = newDig; |
112 | const char *q{lut + d + d}; |
113 | *sp++ = q[1]; |
114 | *sp++ = q[0]; |
115 | } |
116 | while (sp > stack && sp[-1] == '0') { |
117 | --sp; |
118 | } |
119 | while (sp > stack) { |
120 | *p++ = *--sp; |
121 | } |
122 | for (int j{digits_ - 1}; j-- > 0;) { |
123 | Digit dig{digit_[j]}; |
124 | char *reverse{p += log10Radix}; |
125 | for (int k{0}; k < log10Radix; k += 2) { |
126 | Digit newDig{dig / 100}; |
127 | auto d{static_cast<std::uint32_t>(dig) - |
128 | std::uint32_t{100} * static_cast<std::uint32_t>(newDig)}; |
129 | dig = newDig; |
130 | const char *q{lut + d + d}; |
131 | *--reverse = q[1]; |
132 | *--reverse = q[0]; |
133 | } |
134 | } |
135 | |
136 | |
137 | int expo = exponent_ + p - start; |
138 | |
139 | while (p[-1] == '0') { |
140 | --p; |
141 | } |
142 | char *end{start + maxDigits}; |
143 | if (maxDigits == 0) { |
144 | p = end; |
145 | } |
146 | if (p <= end) { |
147 | *p = '\0'; |
148 | return {buffer, static_cast<std::size_t>(p - buffer), expo, Exact}; |
149 | } else { |
150 | |
151 | bool incr{false}; |
152 | switch (rounding_) { |
153 | case RoundNearest: |
154 | incr = *end > '5' || |
155 | (*end == '5' && (p > end + 1 || ((end[-1] - '0') & 1) != 0)); |
156 | break; |
157 | case RoundUp: |
158 | incr = !isNegative_; |
159 | break; |
160 | case RoundDown: |
161 | incr = isNegative_; |
162 | break; |
163 | case RoundToZero: |
164 | break; |
165 | case RoundCompatible: |
166 | incr = *end >= '5'; |
167 | break; |
168 | } |
169 | p = end; |
170 | if (incr) { |
171 | while (p > start && p[-1] == '9') { |
172 | --p; |
173 | } |
174 | if (p == start) { |
175 | *p++ = '1'; |
176 | ++expo; |
177 | } else { |
178 | ++p[-1]; |
179 | } |
180 | } |
181 | |
182 | *p = '\0'; |
183 | return {buffer, static_cast<std::size_t>(p - buffer), expo, Inexact}; |
184 | } |
185 | } |
186 | |
187 | template <int PREC, int LOG10RADIX> |
188 | bool BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Mean( |
189 | const BigRadixFloatingPointNumber &that) { |
190 | while (digits_ < that.digits_) { |
191 | digit_[digits_++] = 0; |
192 | } |
193 | int carry{0}; |
194 | for (int j{0}; j < that.digits_; ++j) { |
195 | Digit v{digit_[j] + that.digit_[j] + carry}; |
196 | if (v >= radix) { |
197 | digit_[j] = v - radix; |
198 | carry = 1; |
199 | } else { |
200 | digit_[j] = v; |
201 | carry = 0; |
202 | } |
203 | } |
204 | if (carry != 0) { |
205 | AddCarry(that.digits_, carry); |
206 | } |
207 | return DivideBy<2>() != 0; |
208 | } |
209 | |
210 | template <int PREC, int LOG10RADIX> |
211 | void BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Minimize( |
212 | BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more) { |
213 | int leastExponent{exponent_}; |
214 | if (less.exponent_ < leastExponent) { |
| |
215 | leastExponent = less.exponent_; |
216 | } |
217 | if (more.exponent_ < leastExponent) { |
| |
218 | leastExponent = more.exponent_; |
219 | } |
220 | while (exponent_ > leastExponent) { |
| 9 | | Loop condition is false. Execution continues on line 224 | |
|
221 | --exponent_; |
222 | MultiplyBy<10>(); |
223 | } |
224 | while (less.exponent_ > leastExponent) { |
| 10 | | Loop condition is false. Execution continues on line 228 | |
|
225 | --less.exponent_; |
226 | less.MultiplyBy<10>(); |
227 | } |
228 | while (more.exponent_ > leastExponent) { |
| 11 | | Loop condition is false. Execution continues on line 232 | |
|
229 | --more.exponent_; |
230 | more.MultiplyBy<10>(); |
231 | } |
232 | if (less.Mean(*this)) { |
| |
233 | less.AddCarry(); |
234 | } |
235 | if (!more.Mean(*this)) { |
| |
236 | more.Decrement(); |
| 14 | | Calling 'BigRadixFloatingPointNumber::Decrement' | |
|
237 | } |
238 | while (less.digits_ < more.digits_) { |
239 | less.digit_[less.digits_++] = 0; |
240 | } |
241 | while (more.digits_ < less.digits_) { |
242 | more.digit_[more.digits_++] = 0; |
243 | } |
244 | int digits{more.digits_}; |
245 | int same{0}; |
246 | while (same < digits && |
247 | less.digit_[digits - 1 - same] == more.digit_[digits - 1 - same]) { |
248 | ++same; |
249 | } |
250 | if (same == digits) { |
251 | return; |
252 | } |
253 | digits_ = same + 1; |
254 | int offset{digits - digits_}; |
255 | exponent_ += offset * log10Radix; |
256 | for (int j{0}; j < digits_; ++j) { |
257 | digit_[j] = more.digit_[j + offset]; |
258 | } |
259 | Digit least{less.digit_[offset]}; |
260 | Digit my{digit_[0]}; |
261 | while (true) { |
262 | Digit q{my / 10u}; |
263 | Digit r{my - 10 * q}; |
264 | Digit lq{least / 10u}; |
265 | Digit lr{least - 10 * lq}; |
266 | if (r != 0 && lq == q) { |
267 | Digit sub{(r - lr) >> 1}; |
268 | digit_[0] -= sub; |
269 | break; |
270 | } else { |
271 | least = lq; |
272 | my = q; |
273 | DivideBy<10>(); |
274 | ++exponent_; |
275 | } |
276 | } |
277 | Normalize(); |
278 | } |
279 | |
280 | template <int PREC> |
281 | ConversionToDecimalResult ConvertToDecimal(char *buffer, std::size_t size, |
282 | enum DecimalConversionFlags flags, int digits, |
283 | enum FortranRounding rounding, BinaryFloatingPointNumber<PREC> x) { |
284 | if (x.IsNaN()) { |
| |
285 | return {"NaN", 3, 0, Invalid}; |
286 | } else if (x.IsInfinite()) { |
| |
287 | if (x.IsNegative()) { |
288 | return {"-Inf", 4, 0, Exact}; |
289 | } else if (flags & AlwaysSign) { |
290 | return {"+Inf", 4, 0, Exact}; |
291 | } else { |
292 | return {"Inf", 3, 0, Exact}; |
293 | } |
294 | } else { |
295 | using Big = BigRadixFloatingPointNumber<PREC>; |
296 | Big number{x, rounding}; |
297 | if ((flags & Minimize) && !x.IsZero()) { |
| 3 | | Assuming the condition is true | |
|
| |
298 | |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | |
306 | using Binary = typename Big::Real; |
307 | Binary less{x}; |
308 | less.Previous(); |
309 | Binary more{x}; |
310 | if (!x.IsMaximalFiniteMagnitude()) { |
| |
311 | more.Next(); |
312 | } |
313 | number.Minimize(Big{less, rounding}, Big{more, rounding}); |
| 6 | | Calling 'BigRadixFloatingPointNumber::Minimize' | |
|
314 | } |
315 | return number.ConvertToDecimal(buffer, size, flags, digits); |
316 | } |
317 | } |
318 | |
319 | template ConversionToDecimalResult ConvertToDecimal<8>(char *, std::size_t, |
320 | enum DecimalConversionFlags, int, enum FortranRounding, |
321 | BinaryFloatingPointNumber<8>); |
322 | template ConversionToDecimalResult ConvertToDecimal<11>(char *, std::size_t, |
323 | enum DecimalConversionFlags, int, enum FortranRounding, |
324 | BinaryFloatingPointNumber<11>); |
325 | template ConversionToDecimalResult ConvertToDecimal<24>(char *, std::size_t, |
326 | enum DecimalConversionFlags, int, enum FortranRounding, |
327 | BinaryFloatingPointNumber<24>); |
328 | template ConversionToDecimalResult ConvertToDecimal<53>(char *, std::size_t, |
329 | enum DecimalConversionFlags, int, enum FortranRounding, |
330 | BinaryFloatingPointNumber<53>); |
331 | template ConversionToDecimalResult ConvertToDecimal<64>(char *, std::size_t, |
332 | enum DecimalConversionFlags, int, enum FortranRounding, |
333 | BinaryFloatingPointNumber<64>); |
334 | template ConversionToDecimalResult ConvertToDecimal<113>(char *, std::size_t, |
335 | enum DecimalConversionFlags, int, enum FortranRounding, |
336 | BinaryFloatingPointNumber<113>); |
337 | |
338 | extern "C" { |
339 | ConversionToDecimalResult ConvertFloatToDecimal(char *buffer, std::size_t size, |
340 | enum DecimalConversionFlags flags, int digits, |
341 | enum FortranRounding rounding, float x) { |
342 | return Fortran::decimal::ConvertToDecimal(buffer, size, flags, digits, |
343 | rounding, Fortran::decimal::BinaryFloatingPointNumber<24>(x)); |
344 | } |
345 | |
346 | ConversionToDecimalResult ConvertDoubleToDecimal(char *buffer, std::size_t size, |
347 | enum DecimalConversionFlags flags, int digits, |
348 | enum FortranRounding rounding, double x) { |
349 | return Fortran::decimal::ConvertToDecimal(buffer, size, flags, digits, |
350 | rounding, Fortran::decimal::BinaryFloatingPointNumber<53>(x)); |
351 | } |
352 | |
353 | #if LDBL_MANT_DIG == 64 |
354 | ConversionToDecimalResult ConvertLongDoubleToDecimal(char *buffer, |
355 | std::size_t size, enum DecimalConversionFlags flags, int digits, |
356 | enum FortranRounding rounding, long double x) { |
357 | return Fortran::decimal::ConvertToDecimal(buffer, size, flags, digits, |
358 | rounding, Fortran::decimal::BinaryFloatingPointNumber<64>(x)); |
359 | } |
360 | #elif LDBL_MANT_DIG == 113 |
361 | ConversionToDecimalResult ConvertLongDoubleToDecimal(char *buffer, |
362 | std::size_t size, enum DecimalConversionFlags flags, int digits, |
363 | enum FortranRounding rounding, long double x) { |
364 | return Fortran::decimal::ConvertToDecimal(buffer, size, flags, digits, |
365 | rounding, Fortran::decimal::BinaryFloatingPointNumber<113>(x)); |
366 | } |
367 | #endif |
368 | } |
369 | |
370 | template <int PREC, int LOG10RADIX> |
371 | template <typename STREAM> |
372 | STREAM &BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Dump(STREAM &o) const { |
373 | if (isNegative_) { |
374 | o << '-'; |
375 | } |
376 | o << "10**(" << exponent_ << ") * ...\n"; |
377 | for (int j{digits_}; --j >= 0;) { |
378 | std::string str{std::to_string(digit_[j])}; |
379 | o << std::string(20 - str.size(), ' ') << str << " [" << j << ']'; |
380 | if (j + 1 == digitLimit_) { |
381 | o << " (limit)"; |
382 | } |
383 | o << '\n'; |
384 | } |
385 | return o; |
386 | } |
387 | } |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #ifndef FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_ |
10 | #define FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_ |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | #include "flang/Common/bit-population-count.h" |
25 | #include "flang/Common/leading-zero-bit-count.h" |
26 | #include "flang/Common/uint128.h" |
27 | #include "flang/Decimal/binary-floating-point.h" |
28 | #include "flang/Decimal/decimal.h" |
29 | #include <cinttypes> |
30 | #include <limits> |
31 | #include <type_traits> |
32 | |
33 | namespace Fortran::decimal { |
34 | |
35 | static constexpr std::uint64_t TenToThe(int power) { |
36 | return power <= 0 ? 1 : 10 * TenToThe(power - 1); |
37 | } |
38 | |
39 | |
40 | |
41 | |
42 | template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber { |
43 | public: |
44 | using Real = BinaryFloatingPointNumber<PREC>; |
45 | static constexpr int log10Radix{LOG10RADIX}; |
46 | |
47 | private: |
48 | static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)}; |
49 | static constexpr int minDigitBits{ |
50 | 64 - common::LeadingZeroBitCount(uint64Radix)}; |
51 | using Digit = common::HostUnsignedIntType<minDigitBits>; |
52 | static constexpr Digit radix{uint64Radix}; |
53 | static_assert(radix < std::numeric_limits<Digit>::max() / 1000, |
54 | "radix is somehow too big"); |
55 | static_assert(radix > std::numeric_limits<Digit>::max() / 10000, |
56 | "radix is somehow too small"); |
57 | |
58 | |
59 | |
60 | static constexpr int minLog2AnyBit{ |
61 | -Real::exponentBias - Real::binaryPrecision}; |
62 | |
63 | |
64 | static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix}; |
65 | |
66 | public: |
67 | explicit BigRadixFloatingPointNumber( |
68 | enum FortranRounding rounding = RoundNearest) |
69 | : rounding_{rounding} {} |
70 | |
71 | |
72 | explicit BigRadixFloatingPointNumber( |
73 | Real, enum FortranRounding = RoundNearest); |
74 | |
75 | BigRadixFloatingPointNumber &SetToZero() { |
76 | isNegative_ = false; |
77 | digits_ = 0; |
78 | exponent_ = 0; |
79 | return *this; |
80 | } |
81 | |
82 | |
83 | ConversionToBinaryResult<PREC> ConvertToBinary(); |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | ConversionToBinaryResult<PREC> ConvertToBinary( |
91 | const char *&, const char *end = nullptr); |
92 | |
93 | |
94 | |
95 | |
96 | |
97 | |
98 | |
99 | ConversionToDecimalResult ConvertToDecimal( |
100 | char *, std::size_t, enum DecimalConversionFlags, int digits) const; |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | void Minimize( |
112 | BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more); |
113 | |
114 | template <typename STREAM> STREAM &Dump(STREAM &) const; |
115 | |
116 | private: |
117 | BigRadixFloatingPointNumber(const BigRadixFloatingPointNumber &that) |
118 | : digits_{that.digits_}, exponent_{that.exponent_}, |
119 | isNegative_{that.isNegative_}, rounding_{that.rounding_} { |
120 | for (int j{0}; j < digits_; ++j) { |
121 | digit_[j] = that.digit_[j]; |
122 | } |
123 | } |
124 | |
125 | bool IsZero() const { |
126 | |
127 | for (int j{0}; j < digits_; ++j) { |
128 | if (digit_[j] != 0) { |
129 | return false; |
130 | } |
131 | } |
132 | return true; |
133 | } |
134 | |
135 | |
136 | |
137 | |
138 | |
139 | bool IsFull() const { |
140 | return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10; |
141 | } |
142 | |
143 | |
144 | |
145 | template <typename UINT> UINT SetTo(UINT n) { |
146 | static_assert( |
147 | std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>); |
148 | SetToZero(); |
149 | while (n != 0) { |
150 | auto q{n / 10u}; |
151 | if (n != q * 10) { |
152 | break; |
153 | } |
154 | ++exponent_; |
155 | n = q; |
156 | } |
157 | if constexpr (sizeof n < sizeof(Digit)) { |
158 | if (n != 0) { |
159 | digit_[digits_++] = n; |
160 | } |
161 | return 0; |
162 | } else { |
163 | while (n != 0 && digits_ < digitLimit_) { |
164 | auto q{n / radix}; |
165 | digit_[digits_++] = static_cast<Digit>(n - q * radix); |
166 | n = q; |
167 | } |
168 | return n; |
169 | } |
170 | } |
171 | |
172 | int RemoveLeastOrderZeroDigits() { |
173 | int remove{0}; |
174 | if (digits_ > 0 && digit_[0] == 0) { |
175 | while (remove < digits_ && digit_[remove] == 0) { |
176 | ++remove; |
177 | } |
178 | if (remove >= digits_) { |
179 | digits_ = 0; |
180 | } else if (remove > 0) { |
181 | #if defined __GNUC__ && __GNUC__ < 8 |
182 | |
183 | |
184 | for (int j{0}; j + remove < digits_ && (j + remove < maxDigits); ++j) { |
185 | #else |
186 | for (int j{0}; j + remove < digits_; ++j) { |
187 | #endif |
188 | digit_[j] = digit_[j + remove]; |
189 | } |
190 | digits_ -= remove; |
191 | } |
192 | } |
193 | return remove; |
194 | } |
195 | |
196 | void RemoveLeadingZeroDigits() { |
197 | while (digits_ > 0 && digit_[digits_ - 1] == 0) { |
198 | --digits_; |
199 | } |
200 | } |
201 | |
202 | void Normalize() { |
203 | RemoveLeadingZeroDigits(); |
204 | exponent_ += RemoveLeastOrderZeroDigits() * log10Radix; |
205 | } |
206 | |
207 | |
208 | |
209 | template <int N> bool IsDivisibleBy() const { |
210 | static_assert(N > 1 && radix % N == 0, "bad modulus"); |
211 | return digits_ == 0 || (digit_[0] % N) == 0; |
212 | } |
213 | |
214 | template <unsigned DIVISOR> int DivideBy() { |
215 | Digit remainder{0}; |
216 | for (int j{digits_ - 1}; j >= 0; --j) { |
217 | Digit q{digit_[j] / DIVISOR}; |
218 | Digit nrem{digit_[j] - DIVISOR * q}; |
219 | digit_[j] = q + (radix / DIVISOR) * remainder; |
220 | remainder = nrem; |
221 | } |
222 | return remainder; |
223 | } |
224 | |
225 | void DivideByPowerOfTwo(int twoPow) { |
226 | Digit remainder{0}; |
227 | auto mask{(Digit{1} << twoPow) - 1}; |
228 | auto coeff{radix >> twoPow}; |
229 | for (int j{digits_ - 1}; j >= 0; --j) { |
230 | auto nrem{digit_[j] & mask}; |
231 | digit_[j] = (digit_[j] >> twoPow) + coeff * remainder; |
232 | remainder = nrem; |
233 | } |
234 | } |
235 | |
236 | |
237 | bool DivideByPowerOfTwoInPlace(int twoPow) { |
238 | if (digits_ > 0) { |
239 | while (twoPow > 0) { |
240 | int chunk{twoPow > log10Radix ? log10Radix : twoPow}; |
241 | if ((digit_[0] & ((Digit{1} << chunk) - 1)) == 0) { |
242 | DivideByPowerOfTwo(chunk); |
243 | twoPow -= chunk; |
244 | continue; |
245 | } |
246 | twoPow -= chunk; |
247 | if (digit_[digits_ - 1] >> chunk != 0) { |
248 | if (digits_ == digitLimit_) { |
249 | return true; |
250 | } |
251 | digit_[digits_++] = 0; |
252 | } |
253 | auto remainder{digit_[digits_ - 1]}; |
254 | exponent_ -= log10Radix; |
255 | auto coeff{radix >> chunk}; |
256 | auto mask{(Digit{1} << chunk) - 1}; |
257 | for (int j{digits_ - 1}; j >= 1; --j) { |
258 | digit_[j] = (digit_[j - 1] >> chunk) + coeff * remainder; |
259 | remainder = digit_[j - 1] & mask; |
260 | } |
261 | digit_[0] = coeff * remainder; |
262 | } |
263 | } |
264 | return false; |
265 | } |
266 | |
267 | int AddCarry(int position = 0, int carry = 1) { |
268 | for (; position < digits_; ++position) { |
269 | Digit v{digit_[position] + carry}; |
270 | if (v < radix) { |
271 | digit_[position] = v; |
272 | return 0; |
273 | } |
274 | digit_[position] = v - radix; |
275 | carry = 1; |
276 | } |
277 | if (digits_ < digitLimit_) { |
278 | digit_[digits_++] = carry; |
279 | return 0; |
280 | } |
281 | Normalize(); |
282 | if (digits_ < digitLimit_) { |
283 | digit_[digits_++] = carry; |
284 | return 0; |
285 | } |
286 | return carry; |
287 | } |
288 | |
289 | void Decrement() { |
290 | for (int j{0}; digit_[j]-- == 0; ++j) { |
| |
| 16 | | The expression is an uninitialized value. The computed value will also be garbage |
|
291 | digit_[j] = radix - 1; |
292 | } |
293 | } |
294 | |
295 | template <int N> int MultiplyByHelper(int carry = 0) { |
296 | for (int j{0}; j < digits_; ++j) { |
297 | auto v{N * digit_[j] + carry}; |
298 | carry = v / radix; |
299 | digit_[j] = v - carry * radix; |
300 | } |
301 | return carry; |
302 | } |
303 | |
304 | template <int N> int MultiplyBy(int carry = 0) { |
305 | if (int newCarry{MultiplyByHelper<N>(carry)}) { |
306 | return AddCarry(digits_, newCarry); |
307 | } else { |
308 | return 0; |
309 | } |
310 | } |
311 | |
312 | template <int N> int MultiplyWithoutNormalization() { |
313 | if (int carry{MultiplyByHelper<N>(0)}) { |
314 | if (digits_ < digitLimit_) { |
315 | digit_[digits_++] = carry; |
316 | return 0; |
317 | } else { |
318 | return carry; |
319 | } |
320 | } else { |
321 | return 0; |
322 | } |
323 | } |
324 | |
325 | void LoseLeastSignificantDigit(); |
326 | |
327 | void PushCarry(int carry) { |
328 | if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) { |
329 | LoseLeastSignificantDigit(); |
330 | digit_[digits_ - 1] += carry; |
331 | } else { |
332 | digit_[digits_++] = carry; |
333 | } |
334 | } |
335 | |
336 | |
337 | |
338 | |
339 | bool Mean(const BigRadixFloatingPointNumber &); |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | bool ParseNumber(const char *&, bool &inexact, const char *end); |
347 | |
348 | using Raw = typename Real::RawType; |
349 | constexpr Raw SignBit() const { return Raw{isNegative_} << (Real::bits - 1); } |
350 | constexpr Raw Infinity() const { |
351 | return (Raw{Real::maxExponent} << Real::significandBits) | SignBit(); |
352 | } |
353 | constexpr Raw NaN(bool isQuiet = true) { |
354 | return (Raw{Real::maxExponent} << Real::significandBits) | |
355 | (Raw{1} << (Real::significandBits - (isQuiet ? 1 : 2))) | SignBit(); |
356 | } |
357 | |
358 | Digit digit_[maxDigits]; |
359 | int digits_{0}; |
360 | int digitLimit_{maxDigits}; |
361 | int exponent_{0}; |
362 | bool isNegative_{false}; |
363 | enum FortranRounding rounding_ { RoundNearest }; |
364 | }; |
365 | } |
366 | #endif |