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