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