comparison flang/lib/Decimal/big-radix-floating-point.h @ 173:0572611fdcc8 llvm10 llvm12

reorgnization done
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 11:55:54 +0900
parents
children 2e18cbf3894f
comparison
equal deleted inserted replaced
172:9fbae9c8bf63 173:0572611fdcc8
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
13 // between binary 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/Common/unsigned-const-division.h"
28 #include "flang/Decimal/binary-floating-point.h"
29 #include "flang/Decimal/decimal.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <cinttypes>
32 #include <limits>
33 #include <type_traits>
34
35 namespace Fortran::decimal {
36
37 static constexpr std::uint64_t TenToThe(int power) {
38 return power <= 0 ? 1 : 10 * TenToThe(power - 1);
39 }
40
41 // 10**(LOG10RADIX + 3) must be < 2**wordbits, and LOG10RADIX must be
42 // even, so that pairs of decimal digits do not straddle Digits.
43 // So LOG10RADIX must be 16 or 6.
44 template <int PREC, int LOG10RADIX = 16> class BigRadixFloatingPointNumber {
45 public:
46 using Real = BinaryFloatingPointNumber<PREC>;
47 static constexpr int log10Radix{LOG10RADIX};
48
49 private:
50 static constexpr std::uint64_t uint64Radix{TenToThe(log10Radix)};
51 static constexpr int minDigitBits{
52 64 - common::LeadingZeroBitCount(uint64Radix)};
53 using Digit = common::HostUnsignedIntType<minDigitBits>;
54 static constexpr Digit radix{uint64Radix};
55 static_assert(radix < std::numeric_limits<Digit>::max() / 1000,
56 "radix is somehow too big");
57 static_assert(radix > std::numeric_limits<Digit>::max() / 10000,
58 "radix is somehow too small");
59
60 // The base-2 logarithm of the least significant bit that can arise
61 // in a subnormal IEEE floating-point number.
62 static constexpr int minLog2AnyBit{
63 -Real::exponentBias - Real::binaryPrecision};
64
65 // The number of Digits needed to represent the smallest subnormal.
66 static constexpr int maxDigits{3 - minLog2AnyBit / log10Radix};
67
68 public:
69 explicit BigRadixFloatingPointNumber(
70 enum FortranRounding rounding = RoundDefault)
71 : rounding_{rounding} {}
72
73 // Converts a binary floating point value.
74 explicit BigRadixFloatingPointNumber(
75 Real, enum FortranRounding = RoundDefault);
76
77 BigRadixFloatingPointNumber &SetToZero() {
78 isNegative_ = false;
79 digits_ = 0;
80 exponent_ = 0;
81 return *this;
82 }
83
84 // Converts decimal floating-point to binary.
85 ConversionToBinaryResult<PREC> ConvertToBinary();
86
87 // Parses and converts to binary. Handles leading spaces,
88 // "NaN", & optionally-signed "Inf". Does not skip internal
89 // spaces.
90 // The argument is a reference to a pointer that is left
91 // pointing to the first character that wasn't parsed.
92 ConversionToBinaryResult<PREC> ConvertToBinary(const char *&);
93
94 // Formats a decimal floating-point number to a user buffer.
95 // May emit "NaN" or "Inf", or an possibly-signed integer.
96 // No decimal point is written, but if it were, it would be
97 // after the last digit; the effective decimal exponent is
98 // returned as part of the result structure so that it can be
99 // formatted by the client.
100 ConversionToDecimalResult ConvertToDecimal(
101 char *, std::size_t, enum DecimalConversionFlags, int digits) const;
102
103 // Discard decimal digits not needed to distinguish this value
104 // from the decimal encodings of two others (viz., the nearest binary
105 // floating-point numbers immediately below and above this one).
106 // The last decimal digit may not be uniquely determined in all
107 // cases, and will be the mean value when that is so (e.g., if
108 // last decimal digit values 6-8 would all work, it'll be a 7).
109 // This minimization necessarily assumes that the value will be
110 // emitted and read back into the same (or less precise) format
111 // with default rounding to the nearest value.
112 void Minimize(
113 BigRadixFloatingPointNumber &&less, BigRadixFloatingPointNumber &&more);
114
115 llvm::raw_ostream &Dump(llvm::raw_ostream &) const;
116
117 private:
118 BigRadixFloatingPointNumber(const BigRadixFloatingPointNumber &that)
119 : digits_{that.digits_}, exponent_{that.exponent_},
120 isNegative_{that.isNegative_}, rounding_{that.rounding_} {
121 for (int j{0}; j < digits_; ++j) {
122 digit_[j] = that.digit_[j];
123 }
124 }
125
126 bool IsZero() const {
127 // Don't assume normalization.
128 for (int j{0}; j < digits_; ++j) {
129 if (digit_[j] != 0) {
130 return false;
131 }
132 }
133 return true;
134 }
135
136 // Predicate: true when 10*value would cause a carry.
137 // (When this happens during decimal-to-binary conversion,
138 // there are more digits in the input string than can be
139 // represented precisely.)
140 bool IsFull() const {
141 return digits_ == digitLimit_ && digit_[digits_ - 1] >= radix / 10;
142 }
143
144 // Sets *this to an unsigned integer value.
145 // Returns any remainder.
146 template <typename UINT> UINT SetTo(UINT n) {
147 static_assert(
148 std::is_same_v<UINT, common::uint128_t> || std::is_unsigned_v<UINT>);
149 SetToZero();
150 while (n != 0) {
151 auto q{common::DivideUnsignedBy<UINT, 10>(n)};
152 if (n != q * 10) {
153 break;
154 }
155 ++exponent_;
156 n = q;
157 }
158 if constexpr (sizeof n < sizeof(Digit)) {
159 if (n != 0) {
160 digit_[digits_++] = n;
161 }
162 return 0;
163 } else {
164 while (n != 0 && digits_ < digitLimit_) {
165 auto q{common::DivideUnsignedBy<UINT, radix>(n)};
166 digit_[digits_++] = static_cast<Digit>(n - q * radix);
167 n = q;
168 }
169 return n;
170 }
171 }
172
173 int RemoveLeastOrderZeroDigits() {
174 int remove{0};
175 if (digits_ > 0 && digit_[0] == 0) {
176 while (remove < digits_ && digit_[remove] == 0) {
177 ++remove;
178 }
179 if (remove >= digits_) {
180 digits_ = 0;
181 } else if (remove > 0) {
182 for (int j{0}; j + remove < digits_; ++j) {
183 digit_[j] = digit_[j + remove];
184 }
185 digits_ -= remove;
186 }
187 }
188 return remove;
189 }
190
191 void RemoveLeadingZeroDigits() {
192 while (digits_ > 0 && digit_[digits_ - 1] == 0) {
193 --digits_;
194 }
195 }
196
197 void Normalize() {
198 RemoveLeadingZeroDigits();
199 exponent_ += RemoveLeastOrderZeroDigits() * log10Radix;
200 }
201
202 // This limited divisibility test only works for even divisors of the radix,
203 // which is fine since it's only ever used with 2 and 5.
204 template <int N> bool IsDivisibleBy() const {
205 static_assert(N > 1 && radix % N == 0, "bad modulus");
206 return digits_ == 0 || (digit_[0] % N) == 0;
207 }
208
209 template <unsigned DIVISOR> int DivideBy() {
210 Digit remainder{0};
211 for (int j{digits_ - 1}; j >= 0; --j) {
212 Digit q{common::DivideUnsignedBy<Digit, DIVISOR>(digit_[j])};
213 Digit nrem{digit_[j] - DIVISOR * q};
214 digit_[j] = q + (radix / DIVISOR) * remainder;
215 remainder = nrem;
216 }
217 return remainder;
218 }
219
220 int DivideByPowerOfTwo(int twoPow) { // twoPow <= LOG10RADIX
221 int remainder{0};
222 for (int j{digits_ - 1}; j >= 0; --j) {
223 Digit q{digit_[j] >> twoPow};
224 int nrem = digit_[j] - (q << twoPow);
225 digit_[j] = q + (radix >> twoPow) * remainder;
226 remainder = nrem;
227 }
228 return remainder;
229 }
230
231 int AddCarry(int position = 0, int carry = 1) {
232 for (; position < digits_; ++position) {
233 Digit v{digit_[position] + carry};
234 if (v < radix) {
235 digit_[position] = v;
236 return 0;
237 }
238 digit_[position] = v - radix;
239 carry = 1;
240 }
241 if (digits_ < digitLimit_) {
242 digit_[digits_++] = carry;
243 return 0;
244 }
245 Normalize();
246 if (digits_ < digitLimit_) {
247 digit_[digits_++] = carry;
248 return 0;
249 }
250 return carry;
251 }
252
253 void Decrement() {
254 for (int j{0}; digit_[j]-- == 0; ++j) {
255 digit_[j] = radix - 1;
256 }
257 }
258
259 template <int N> int MultiplyByHelper(int carry = 0) {
260 for (int j{0}; j < digits_; ++j) {
261 auto v{N * digit_[j] + carry};
262 carry = common::DivideUnsignedBy<Digit, radix>(v);
263 digit_[j] = v - carry * radix; // i.e., v % radix
264 }
265 return carry;
266 }
267
268 template <int N> int MultiplyBy(int carry = 0) {
269 if (int newCarry{MultiplyByHelper<N>(carry)}) {
270 return AddCarry(digits_, newCarry);
271 } else {
272 return 0;
273 }
274 }
275
276 template <int N> int MultiplyWithoutNormalization() {
277 if (int carry{MultiplyByHelper<N>(0)}) {
278 if (digits_ < digitLimit_) {
279 digit_[digits_++] = carry;
280 return 0;
281 } else {
282 return carry;
283 }
284 } else {
285 return 0;
286 }
287 }
288
289 void LoseLeastSignificantDigit(); // with rounding
290
291 void PushCarry(int carry) {
292 if (digits_ == maxDigits && RemoveLeastOrderZeroDigits() == 0) {
293 LoseLeastSignificantDigit();
294 digit_[digits_ - 1] += carry;
295 } else {
296 digit_[digits_++] = carry;
297 }
298 }
299
300 // Adds another number and then divides by two.
301 // Assumes same exponent and sign.
302 // Returns true when the the result has effectively been rounded down.
303 bool Mean(const BigRadixFloatingPointNumber &);
304
305 bool ParseNumber(const char *&, bool &inexact);
306
307 using Raw = typename Real::RawType;
308 constexpr Raw SignBit() const { return Raw{isNegative_} << (Real::bits - 1); }
309 constexpr Raw Infinity() const {
310 return (Raw{Real::maxExponent} << Real::significandBits) | SignBit();
311 }
312 static constexpr Raw NaN() {
313 return (Raw{Real::maxExponent} << Real::significandBits) |
314 (Raw{1} << (Real::significandBits - 2));
315 }
316
317 Digit digit_[maxDigits]; // in little-endian order: digit_[0] is LSD
318 int digits_{0}; // # of elements in digit_[] array; zero when zero
319 int digitLimit_{maxDigits}; // precision clamp
320 int exponent_{0}; // signed power of ten
321 bool isNegative_{false};
322 enum FortranRounding rounding_ { RoundDefault };
323 };
324 } // namespace Fortran::decimal
325 #endif