• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*===-- include/flang/Decimal/decimal.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 
10 /* C and C++ API for binary-to/from-decimal conversion package. */
11 
12 #ifndef FORTRAN_DECIMAL_DECIMAL_H_
13 #define FORTRAN_DECIMAL_DECIMAL_H_
14 
15 #include <stddef.h>
16 
17 #ifdef __cplusplus
18 // Binary-to-decimal conversions (formatting) produce a sequence of decimal
19 // digit characters in a NUL-terminated user-supplied buffer that constitute
20 // a decimal fraction (or zero), accompanied by a decimal exponent that
21 // you'll get to adjust and format yourself.  There can be a leading sign
22 // character.
23 // Negative zero is "-0".  The result can also be "NaN", "Inf", "+Inf",
24 // or "-Inf".
25 // If the conversion can't fit in the user-supplied buffer, a null pointer
26 // is returned.
27 
28 #include "binary-floating-point.h"
29 namespace Fortran::decimal {
30 #endif /* C++ */
31 
32 enum ConversionResultFlags {
33   Exact = 0,
34   Overflow = 1,
35   Inexact = 2,
36   Invalid = 4,
37 };
38 
39 struct ConversionToDecimalResult {
40   const char *str; /* may not be original buffer pointer; null if overflow */
41   size_t length; /* does not include NUL terminator */
42   int decimalExponent; /* assuming decimal point to the left of first digit */
43   enum ConversionResultFlags flags;
44 };
45 
46 enum FortranRounding {
47   RoundNearest, /* RN and RP */
48   RoundUp, /* RU */
49   RoundDown, /* RD */
50   RoundToZero, /* RZ - no rounding */
51   RoundCompatible, /* RC: like RN, but ties go away from 0 */
52 };
53 
54 /* The "minimize" flag causes the fewest number of output digits
55  * to be emitted such that reading them back into the same binary
56  * floating-point format with RoundNearest will return the same
57  * value.
58  */
59 enum DecimalConversionFlags {
60   Minimize = 1, /* Minimize # of digits */
61   AlwaysSign = 2, /* emit leading '+' if not negative */
62 };
63 
64 /*
65  * When allocating decimal conversion output buffers, use the maximum
66  * number of significant decimal digits in the representation of the
67  * least nonzero value, and add this extra space for a sign, a NUL, and
68  * some extra due to the library working internally in base 10**16
69  * and computing its output size in multiples of 16.
70  */
71 #define EXTRA_DECIMAL_CONVERSION_SPACE (1 + 1 + 2 * 16 - 1)
72 
73 #ifdef __cplusplus
74 template <int PREC>
75 ConversionToDecimalResult ConvertToDecimal(char *, size_t,
76     DecimalConversionFlags, int digits, enum FortranRounding rounding,
77     BinaryFloatingPointNumber<PREC> x);
78 
79 extern template ConversionToDecimalResult ConvertToDecimal<8>(char *, size_t,
80     enum DecimalConversionFlags, int, enum FortranRounding,
81     BinaryFloatingPointNumber<8>);
82 extern template ConversionToDecimalResult ConvertToDecimal<11>(char *, size_t,
83     enum DecimalConversionFlags, int, enum FortranRounding,
84     BinaryFloatingPointNumber<11>);
85 extern template ConversionToDecimalResult ConvertToDecimal<24>(char *, size_t,
86     enum DecimalConversionFlags, int, enum FortranRounding,
87     BinaryFloatingPointNumber<24>);
88 extern template ConversionToDecimalResult ConvertToDecimal<53>(char *, size_t,
89     enum DecimalConversionFlags, int, enum FortranRounding,
90     BinaryFloatingPointNumber<53>);
91 extern template ConversionToDecimalResult ConvertToDecimal<64>(char *, size_t,
92     enum DecimalConversionFlags, int, enum FortranRounding,
93     BinaryFloatingPointNumber<64>);
94 extern template ConversionToDecimalResult ConvertToDecimal<113>(char *, size_t,
95     enum DecimalConversionFlags, int, enum FortranRounding,
96     BinaryFloatingPointNumber<113>);
97 
98 template <int PREC> struct ConversionToBinaryResult {
99   BinaryFloatingPointNumber<PREC> binary;
100   enum ConversionResultFlags flags { Exact };
101 };
102 
103 template <int PREC>
104 ConversionToBinaryResult<PREC> ConvertToBinary(
105     const char *&, enum FortranRounding = RoundNearest);
106 
107 extern template ConversionToBinaryResult<8> ConvertToBinary<8>(
108     const char *&, enum FortranRounding);
109 extern template ConversionToBinaryResult<11> ConvertToBinary<11>(
110     const char *&, enum FortranRounding);
111 extern template ConversionToBinaryResult<24> ConvertToBinary<24>(
112     const char *&, enum FortranRounding);
113 extern template ConversionToBinaryResult<53> ConvertToBinary<53>(
114     const char *&, enum FortranRounding);
115 extern template ConversionToBinaryResult<64> ConvertToBinary<64>(
116     const char *&, enum FortranRounding);
117 extern template ConversionToBinaryResult<113> ConvertToBinary<113>(
118     const char *&, enum FortranRounding);
119 } // namespace Fortran::decimal
120 extern "C" {
121 #define NS(x) Fortran::decimal::x
122 #else /* C++ */
123 #define NS(x) x
124 #endif /* C++ */
125 
126 struct NS(ConversionToDecimalResult)
127     ConvertFloatToDecimal(char *, size_t, enum NS(DecimalConversionFlags),
128         int digits, enum NS(FortranRounding), float);
129 struct NS(ConversionToDecimalResult)
130     ConvertDoubleToDecimal(char *, size_t, enum NS(DecimalConversionFlags),
131         int digits, enum NS(FortranRounding), double);
132 #if __x86_64__ && !defined(_MSC_VER)
133 struct NS(ConversionToDecimalResult)
134     ConvertLongDoubleToDecimal(char *, size_t, enum NS(DecimalConversionFlags),
135         int digits, enum NS(FortranRounding), long double);
136 #endif
137 
138 enum NS(ConversionResultFlags)
139     ConvertDecimalToFloat(const char **, float *, enum NS(FortranRounding));
140 enum NS(ConversionResultFlags)
141     ConvertDecimalToDouble(const char **, double *, enum NS(FortranRounding));
142 #if __x86_64__ && !defined(_MSC_VER)
143 enum NS(ConversionResultFlags) ConvertDecimalToLongDouble(
144     const char **, long double *, enum NS(FortranRounding));
145 #endif
146 #undef NS
147 #ifdef __cplusplus
148 } // extern "C"
149 #endif
150 #endif
151