Break circular dependency between FIR dialect and utilities
[llvm-project.git] / flang / lib / Decimal / binary-to-decimal.cpp
blob7b31d02b292e48a0b87395d90aacf617973e615e
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 //===----------------------------------------------------------------------===//
9 #include "big-radix-floating-point.h"
10 #include "flang/Decimal/decimal.h"
11 #include <cassert>
12 #include <cfloat>
13 #include <string>
15 namespace Fortran::decimal {
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;
26 if (negative) {
27 x.Negate();
29 int twoPow{x.UnbiasedExponent()};
30 twoPow -= x.bits - 1;
31 if (!x.isImplicitMSB) {
32 ++twoPow;
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;
42 auto word{x.Fraction()};
43 word <<= lshift;
44 SetTo(word);
45 isNegative_ = negative;
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.
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_;
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>();
65 for (; twoPow >= 3; twoPow -= 3) {
66 // D * 10.**E * 2.**twoPow -> (D*(2**3)) * 10.**E * 2.**(twoPow-3)
67 overflow |= MultiplyBy<8>();
69 for (; twoPow > 0; --twoPow) {
70 // D * 10.**E * 2.**twoPow -> (2*D) * 10.**E * 2.**(twoPow-1)
71 overflow |= MultiplyBy<2>();
74 overflow |= DivideByPowerOfTwoInPlace(-twoPow);
75 assert(overflow == 0);
76 Normalize();
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};
86 char *start{buffer};
87 if (isNegative_) {
88 *start++ = '-';
89 } else if (flags & AlwaysSign) {
90 *start++ = '+';
92 if (IsZero()) {
93 *start++ = '0';
94 *start = '\0';
95 return {buffer, static_cast<std::size_t>(start - buffer), 0, Exact};
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];
116 while (sp > stack && sp[-1] == '0') {
117 --sp;
119 while (sp > stack) {
120 *p++ = *--sp;
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];
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;
142 char *end{start + maxDigits};
143 if (maxDigits == 0) {
144 p = end;
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;
169 p = end;
170 if (incr) {
171 while (p > start && p[-1] == '9') {
172 --p;
174 if (p == start) {
175 *p++ = '1';
176 ++expo;
177 } else {
178 ++p[-1];
182 *p = '\0';
183 return {buffer, static_cast<std::size_t>(p - buffer), expo, Inexact};
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;
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;
204 if (carry != 0) {
205 AddCarry(that.digits_, carry);
207 return DivideBy<2>() != 0;
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_;
217 if (more.exponent_ < leastExponent) {
218 leastExponent = more.exponent_;
220 while (exponent_ > leastExponent) {
221 --exponent_;
222 MultiplyBy<10>();
224 while (less.exponent_ > leastExponent) {
225 --less.exponent_;
226 less.MultiplyBy<10>();
228 while (more.exponent_ > leastExponent) {
229 --more.exponent_;
230 more.MultiplyBy<10>();
232 if (less.Mean(*this)) {
233 less.AddCarry(); // round up
235 if (!more.Mean(*this)) {
236 more.Decrement(); // round down
238 while (less.digits_ < more.digits_) {
239 less.digit_[less.digits_++] = 0;
241 while (more.digits_ < less.digits_) {
242 more.digit_[more.digits_++] = 0;
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;
250 if (same == digits) {
251 return;
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];
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_;
277 Normalize();
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};
294 } else {
295 using Big = BigRadixFloatingPointNumber<PREC>;
296 Big number{x, rounding};
297 if ((flags & Minimize) && !x.IsZero()) {
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()) {
311 more.Next();
313 number.Minimize(Big{less, rounding}, Big{more, rounding});
315 return number.ConvertToDecimal(buffer, size, flags, digits);
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>);
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));
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));
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));
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));
367 #endif
370 template <int PREC, int LOG10RADIX>
371 template <typename STREAM>
372 STREAM &BigRadixFloatingPointNumber<PREC, LOG10RADIX>::Dump(STREAM &o) const {
373 if (isNegative_) {
374 o << '-';
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)";
383 o << '\n';
385 return o;
387 } // namespace Fortran::decimal