Bug Summary

File:build/source/flang/lib/Decimal/big-radix-floating-point.h
Warning:line 290, column 20
The expression is an uninitialized value. The computed value will also be garbage

Annotated Source Code

Press '?' to see keyboard shortcuts

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

/build/source/flang/lib/Decimal/binary-to-decimal.cpp

1//===-- lib/Decimal/binary-to-decimal.cpp ---------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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
15namespace Fortran::decimal {
16
17template <int PREC, int LOG10RADIX>
18BigRadixFloatingPointNumber<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 // The significand is now encoded in *this as an integer (D) and
48 // decimal exponent (E): x = D * 10.**E * 2.**twoPow
49 // twoPow can be positive or negative.
50 // The goal now is to get twoPow up or down to zero, leaving us with
51 // only decimal digits and decimal exponent. This is done by
52 // fast multiplications and divisions of D by 2 and 5.
53
54 // (5*D) * 10.**E * 2.**twoPow -> D * 10.**(E+1) * 2.**(twoPow-1)
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 // D * 10.**E * 2.**twoPow -> (D*(2**9)) * 10.**E * 2.**(twoPow-9)
63 overflow |= MultiplyBy<512>();
64 }
65 for (; twoPow >= 3; twoPow -= 3) {
66 // D * 10.**E * 2.**twoPow -> (D*(2**3)) * 10.**E * 2.**(twoPow-3)
67 overflow |= MultiplyBy<8>();
68 }
69 for (; twoPow > 0; --twoPow) {
70 // D * 10.**E * 2.**twoPow -> (2*D) * 10.**E * 2.**(twoPow-1)
71 overflow |= MultiplyBy<2>();
72 }
73
74 overflow |= DivideByPowerOfTwoInPlace(-twoPow);
75 assert(overflow == 0)(static_cast <bool> (overflow == 0) ? void (0) : __assert_fail
("overflow == 0", "flang/lib/Decimal/binary-to-decimal.cpp",
75, __extension__ __PRETTY_FUNCTION__))
;
76 Normalize();
77}
78
79template <int PREC, int LOG10RADIX>
80ConversionToDecimalResult
81BigRadixFloatingPointNumber<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 // Treat the MSD specially: don't emit leading zeroes.
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 // Adjust exponent so the effective decimal point is to
136 // the left of the first digit.
137 int expo = exponent_ + p - start;
138 // Trim trailing zeroes.
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 // Apply a digit limit, possibly with rounding.
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
187template <int PREC, int LOG10RADIX>
188bool 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
210template <int PREC, int LOG10RADIX>
211void BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Minimize(
212 BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more) {
213 int leastExponent{exponent_};
214 if (less.exponent_ < leastExponent
6.1
'leastExponent' is <= field 'exponent_'
6.1
'leastExponent' is <= field 'exponent_'
) {
7
Taking false branch
215 leastExponent = less.exponent_;
216 }
217 if (more.exponent_ < leastExponent
7.1
'leastExponent' is <= field 'exponent_'
7.1
'leastExponent' is <= field 'exponent_'
) {
8
Taking false branch
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)) {
12
Taking false branch
233 less.AddCarry(); // round up
234 }
235 if (!more.Mean(*this)) {
13
Taking true branch
236 more.Decrement(); // round down
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
280template <int PREC>
281ConversionToDecimalResult ConvertToDecimal(char *buffer, std::size_t size,
282 enum DecimalConversionFlags flags, int digits,
283 enum FortranRounding rounding, BinaryFloatingPointNumber<PREC> x) {
284 if (x.IsNaN()) {
1
Taking false branch
285 return {"NaN", 3, 0, Invalid};
286 } else if (x.IsInfinite()) {
2
Taking false branch
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
4
Taking true branch
298 // To emit the fewest decimal digits necessary to represent the value
299 // in such a way that decimal-to-binary conversion to the same format
300 // with a fixed assumption about rounding will return the same binary
301 // value, we also perform binary-to-decimal conversion on the two
302 // binary values immediately adjacent to this one, use them to identify
303 // the bounds of the range of decimal values that will map back to the
304 // original binary value, and find a (not necessary unique) shortest
305 // decimal sequence in that range.
306 using Binary = typename Big::Real;
307 Binary less{x};
308 less.Previous();
309 Binary more{x};
310 if (!x.IsMaximalFiniteMagnitude()) {
5
Taking true branch
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
319template ConversionToDecimalResult ConvertToDecimal<8>(char *, std::size_t,
320 enum DecimalConversionFlags, int, enum FortranRounding,
321 BinaryFloatingPointNumber<8>);
322template ConversionToDecimalResult ConvertToDecimal<11>(char *, std::size_t,
323 enum DecimalConversionFlags, int, enum FortranRounding,
324 BinaryFloatingPointNumber<11>);
325template ConversionToDecimalResult ConvertToDecimal<24>(char *, std::size_t,
326 enum DecimalConversionFlags, int, enum FortranRounding,
327 BinaryFloatingPointNumber<24>);
328template ConversionToDecimalResult ConvertToDecimal<53>(char *, std::size_t,
329 enum DecimalConversionFlags, int, enum FortranRounding,
330 BinaryFloatingPointNumber<53>);
331template ConversionToDecimalResult ConvertToDecimal<64>(char *, std::size_t,
332 enum DecimalConversionFlags, int, enum FortranRounding,
333 BinaryFloatingPointNumber<64>);
334template ConversionToDecimalResult ConvertToDecimal<113>(char *, std::size_t,
335 enum DecimalConversionFlags, int, enum FortranRounding,
336 BinaryFloatingPointNumber<113>);
337
338extern "C" {
339ConversionToDecimalResult 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
346ConversionToDecimalResult 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_DIG64 == 64
354ConversionToDecimalResult 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_DIG64 == 113
361ConversionToDecimalResult 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
370template <int PREC, int LOG10RADIX>
371template <typename STREAM>
372STREAM &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} // namespace Fortran::decimal

/build/source/flang/lib/Decimal/big-radix-floating-point.h

1//===-- lib/Decimal/big-radix-floating-point.h ------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_
10#define FORTRAN_DECIMAL_BIG_RADIX_FLOATING_POINT_H_
11
12// This is a helper class for use in floating-point conversions between
13// binary and decimal representations. It holds a multiple-precision
14// integer value using digits of a radix that is a large even power of ten
15// (10,000,000,000,000,000 by default, 10**16). These digits are accompanied
16// by a signed exponent that denotes multiplication by a power of ten.
17// The effective radix point is to the right of the digits (i.e., they do
18// not represent a fraction).
19//
20// The operations supported by this class are limited to those required
21// for conversions between binary and decimal representations; it is not
22// a general-purpose facility.
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
33namespace Fortran::decimal {
34
35static constexpr std::uint64_t TenToThe(int power) {
36 return power <= 0 ? 1 : 10 * TenToThe(power - 1);
37}
38
39// 10**(LOG10RADIX + 3) must be < 2**wordbits, and LOG10RADIX must be
40// even, so that pairs of decimal digits do not straddle Digits.
41// So LOG10RADIX must be 16 or 6.
42template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
43public:
44 using Real = BinaryFloatingPointNumber<PREC>;
45 static constexpr int log10Radix{LOG10RADIX};
46
47private:
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 // The base-2 logarithm of the least significant bit that can arise
59 // in a subnormal IEEE floating-point number.
60 static constexpr int minLog2AnyBit{
61 -Real::exponentBias - Real::binaryPrecision};
62
63 // The number of Digits needed to represent the smallest subnormal.
64 static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};
65
66public:
67 explicit BigRadixFloatingPointNumber(
68 enum FortranRounding rounding = RoundNearest)
69 : rounding_{rounding} {}
70
71 // Converts a binary floating point value.
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 // Converts decimal floating-point to binary.
83 ConversionToBinaryResult<PREC> ConvertToBinary();
84
85 // Parses and converts to binary. Handles leading spaces,
86 // "NaN", & optionally-signed "Inf". Does not skip internal
87 // spaces.
88 // The argument is a reference to a pointer that is left
89 // pointing to the first character that wasn't parsed.
90 ConversionToBinaryResult<PREC> ConvertToBinary(
91 const char *&, const char *end = nullptr);
92
93 // Formats a decimal floating-point number to a user buffer.
94 // May emit "NaN" or "Inf", or an possibly-signed integer.
95 // No decimal point is written, but if it were, it would be
96 // after the last digit; the effective decimal exponent is
97 // returned as part of the result structure so that it can be
98 // formatted by the client.
99 ConversionToDecimalResult ConvertToDecimal(
100 char *, std::size_t, enum DecimalConversionFlags, int digits) const;
101
102 // Discard decimal digits not needed to distinguish this value
103 // from the decimal encodings of two others (viz., the nearest binary
104 // floating-point numbers immediately below and above this one).
105 // The last decimal digit may not be uniquely determined in all
106 // cases, and will be the mean value when that is so (e.g., if
107 // last decimal digit values 6-8 would all work, it'll be a 7).
108 // This minimization necessarily assumes that the value will be
109 // emitted and read back into the same (or less precise) format
110 // with default rounding to the nearest value.
111 void Minimize(
112 BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more);
113
114 template <typename STREAM> STREAM &Dump(STREAM &) const;
115
116private:
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 // Don't assume normalization.
127 for (int j{0}; j < digits_; ++j) {
128 if (digit_[j] != 0) {
129 return false;
130 }
131 }
132 return true;
133 }
134
135 // Predicate: true when 10*value would cause a carry.
136 // (When this happens during decimal-to-binary conversion,
137 // there are more digits in the input string than can be
138 // represented precisely.)
139 bool IsFull() const {
140 return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
141 }
142
143 // Sets *this to an unsigned integer value.
144 // Returns any remainder.
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__4 && __GNUC__4 < 8
182 // (&& j + remove < maxDigits) was added to avoid GCC < 8 build failure
183 // on -Werror=array-bounds. This can be removed if -Werror is disable.
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 // This limited divisibility test only works for even divisors of the radix,
208 // which is fine since it's only ever used with 2 and 5.
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) { // twoPow <= log10Radix
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 // Returns true on overflow
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; // overflow
250 }
251 digit_[digits_++] = 0;
252 }
253 auto remainder{digit_[digits_ - 1]};
254 exponent_ -= log10Radix;
255 auto coeff{radix >> chunk}; // precise; radix is (5*2)**log10Radix
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; // no overflow
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) {
15
'j' initialized to 0
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; // i.e., v % 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(); // with rounding
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 // Adds another number and then divides by two.
337 // Assumes same exponent and sign.
338 // Returns true when the the result has effectively been rounded down.
339 bool Mean(const BigRadixFloatingPointNumber &);
340
341 // Parses a floating-point number; leaves the pointer reference
342 // argument pointing at the next character after what was recognized.
343 // The "end" argument can be left null if the caller is sure that the
344 // string is properly terminated with an addressable character that
345 // can't be in a valid floating-point character.
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]; // in little-endian order: digit_[0] is LSD
359 int digits_{0}; // # of elements in digit_[] array; zero when zero
360 int digitLimit_{maxDigits}; // precision clamp
361 int exponent_{0}; // signed power of ten
362 bool isNegative_{false};
363 enum FortranRounding rounding_ { RoundNearest };
364};
365} // namespace Fortran::decimal
366#endif