|
2 | 2 | //
|
3 | 3 | // This source file is part of the Swift.org open source project
|
4 | 4 | //
|
5 |
| -// Copyright (c) 2018 Apple Inc. and the Swift project authors |
| 5 | +// Copyright (c) 2018, 2020 Apple Inc. and the Swift project authors |
6 | 6 | // Licensed under Apache License v2.0 with Runtime Library Exception
|
7 | 7 | //
|
8 | 8 | // See https://swift.org/LICENSE.txt for license information
|
9 | 9 | // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
10 | 10 | //
|
11 | 11 | //===---------------------------------------------------------------------===//
|
| 12 | +// |
| 13 | +/// About SwiftDtoa |
| 14 | +/// =============== |
| 15 | +/// |
| 16 | +/// SwiftDtoa is the C implementation that supports the `.description` |
| 17 | +/// and `.debugDescription` properties for the standard Swift |
| 18 | +/// floating-point types. These functions produce the "optimal form" |
| 19 | +/// for the binary floating point value. The optimal form is a |
| 20 | +/// decimal representation that satisfies the following properties: |
| 21 | +/// |
| 22 | +/// 1. Accurate. Parsing the value back to a binary floating-point |
| 23 | +/// value of the same precision will exactly yield the original |
| 24 | +/// value. For example, `Double(d.description) == d` for all `Double` |
| 25 | +/// values `d` (except for NaN values, of course). |
| 26 | +/// |
| 27 | +/// 2. Short. Of all accurate results, the returned value will |
| 28 | +/// contain the minimum number of significant digits. Note that |
| 29 | +/// this is not quite the same as C++ `to_chars` which promises the |
| 30 | +/// minimal number of characters. |
| 31 | +/// |
| 32 | +/// 3. Close. Of all accurate, short results, the value printed will |
| 33 | +/// be the one that is closest to the exact binary floating-point |
| 34 | +/// value. |
| 35 | +/// |
| 36 | +/// The optimal form is the ideal textual form for use in JSON and |
| 37 | +/// similar interchange formats because it is accurate, compact, and |
| 38 | +/// can be generated very quickly. It is also ideal for logging and |
| 39 | +/// debugging use; the accuracy guarantees that the result can be |
| 40 | +/// cut-and-pasted to obtain the exact original value, and the |
| 41 | +/// shortness property eliminates unnecessary digits that can be |
| 42 | +/// confusing to readers. |
| 43 | +/// |
| 44 | +/// Algorithms that produce such output have been known since at least |
| 45 | +/// 1990, when Steele and White published their Dragon4 algorithm. |
| 46 | +/// However, the earliest algorithms required high-precision |
| 47 | +/// arithmetic which limited their use. Starting in 2010 with the |
| 48 | +/// publication of Grisu3, there has been a surge of interest and |
| 49 | +/// there are now a number of algorithms that can produce optimal |
| 50 | +/// forms very quickly. This particular implementation is loosely |
| 51 | +/// based on Grisu2 but incorporates concepts from Errol and Ryu that |
| 52 | +/// make it significantly faster and ensure accuracy in all cases. |
| 53 | +/// |
| 54 | +/// About SwiftDtoa v1 |
| 55 | +/// ------------------ |
| 56 | +/// |
| 57 | +/// The first version of SwiftDtoa was committed to the Swift runtime |
| 58 | +/// in 2018. It supported Swift's Float, Double, and Float80 formats. |
| 59 | +/// |
| 60 | +/// About SwiftDtoa v1a |
| 61 | +/// ------------------- |
| 62 | +/// |
| 63 | +/// Version 1a of SwiftDtoa added support for Float16. |
| 64 | +/// |
| 65 | +/// About SwiftDtoa v2 |
| 66 | +/// ------------------ |
| 67 | +/// |
| 68 | +/// Version 2 of SwiftDtoa is a major overhaul with a number of |
| 69 | +/// algorithmic improvements to make it faster (especially for Float16 |
| 70 | +/// and Float80), smaller, and more portable (the code only requires |
| 71 | +/// C99 and makes no use of C or C++ floating-point facilities). It |
| 72 | +/// also includes experimental support for IEEE 754 quad-precision |
| 73 | +/// binary128 format, which is not currently supported by Swift. |
| 74 | +// |
| 75 | +//===---------------------------------------------------------------------===// |
12 | 76 |
|
13 | 77 | #ifndef SWIFT_DTOA_H
|
14 | 78 | #define SWIFT_DTOA_H
|
15 | 79 |
|
| 80 | +#include <float.h> |
16 | 81 | #include <stdbool.h>
|
17 | 82 | #include <stdint.h>
|
18 | 83 | #include <stdlib.h>
|
19 | 84 |
|
20 |
| -// This implementation strongly assumes that `float` is |
21 |
| -// IEEE 754 single-precision binary32 format and that |
22 |
| -// `double` is IEEE 754 double-precision binary64 format. |
23 |
| - |
24 |
| -// Essentially all modern platforms use IEEE 754 floating point |
25 |
| -// types now, so enable these by default: |
26 |
| -#define SWIFT_DTOA_FLOAT16_SUPPORT 1 |
27 |
| -#define SWIFT_DTOA_FLOAT_SUPPORT 1 |
28 |
| -#define SWIFT_DTOA_DOUBLE_SUPPORT 1 |
29 |
| - |
30 |
| -// This implementation assumes `long double` is Intel 80-bit extended format. |
31 |
| -#if defined(_WIN32) |
32 |
| - // Windows has `long double` == `double` on all platforms, so disable this. |
33 |
| - #undef SWIFT_DTOA_FLOAT80_SUPPORT |
34 |
| -#elif defined(__ANDROID__) |
35 |
| - // At least for now Float80 is disabled. See: https://github.com/apple/swift/pull/25502 |
36 |
| -#elif defined(__APPLE__) || defined(__linux__) || defined(__OpenBSD__) |
37 |
| - // macOS and Linux support Float80 on X86 hardware but not on ARM |
38 |
| - #if defined(__x86_64__) || defined(__i386) |
| 85 | +// |
| 86 | +// IEEE 754 Binary16 support (also known as "half-precision") |
| 87 | +// |
| 88 | + |
| 89 | +// Enable this by default. |
| 90 | +// Force disable: -DSWIFT_DTOA_BINARY16_SUPPORT=0 |
| 91 | +#ifndef SWIFT_DTOA_BINARY16_SUPPORT |
| 92 | + #define SWIFT_DTOA_BINARY16_SUPPORT 1 |
| 93 | +#endif |
| 94 | + |
| 95 | +// |
| 96 | +// IEEE 754 Binary32 support (also known as "single-precision") |
| 97 | +// |
| 98 | + |
| 99 | +// Does "float" on this system use binary32 format? |
| 100 | +// (Almost all modern systems do this.) |
| 101 | +#if (FLT_RADIX == 2) && (FLT_MANT_DIG == 24) && (FLT_MIN_EXP == -125) && (FLT_MAX_EXP == 128) |
| 102 | + #define FLOAT_IS_BINARY32 1 |
| 103 | +#else |
| 104 | + #undef FLOAT_IS_BINARY32 |
| 105 | +#endif |
| 106 | + |
| 107 | +// We can format binary32 values even if the local C environment |
| 108 | +// does not support it. But `float` == binary32 almost everywhere, |
| 109 | +// so we enable it by default. |
| 110 | +// Force disable: -DSWIFT_DTOA_BINARY32_SUPPORT=0 |
| 111 | +#ifndef SWIFT_DTOA_BINARY32_SUPPORT |
| 112 | + #define SWIFT_DTOA_BINARY32_SUPPORT 1 |
| 113 | +#endif |
| 114 | + |
| 115 | +// |
| 116 | +// IEEE 754 Binary64 support (also known as "double-precision") |
| 117 | +// |
| 118 | + |
| 119 | +// Does "double" on this system use binary64 format? |
| 120 | +// (Almost all modern systems do this.) |
| 121 | +#if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024) |
| 122 | + #define DOUBLE_IS_BINARY64 1 |
| 123 | +#else |
| 124 | + #undef DOUBLE_IS_BINARY64 |
| 125 | +#endif |
| 126 | + |
| 127 | +// Does "long double" on this system use binary64 format? |
| 128 | +// (Windows, for example.) |
| 129 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 53) && (LDBL_MIN_EXP == -1021) && (LDBL_MAX_EXP == 1024) |
| 130 | + #define LONG_DOUBLE_IS_BINARY64 1 |
| 131 | +#else |
| 132 | + #undef LONG_DOUBLE_IS_BINARY64 |
| 133 | +#endif |
| 134 | + |
| 135 | +// We can format binary64 values even if the local C environment |
| 136 | +// does not support it. But `double` == binary64 almost everywhere, |
| 137 | +// so we enable it by default. |
| 138 | +// Force disable: -DSWIFT_DTOA_BINARY64_SUPPORT=0 |
| 139 | +#ifndef SWIFT_DTOA_BINARY64_SUPPORT |
| 140 | + #define SWIFT_DTOA_BINARY64_SUPPORT 1 |
| 141 | +#endif |
| 142 | + |
| 143 | +// |
| 144 | +// Intel x87 Float80 support |
| 145 | +// |
| 146 | + |
| 147 | +// Is "long double" on this system the same as Float80? |
| 148 | +// (macOS, Linux, and FreeBSD when running on x86 or x86_64 processors.) |
| 149 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 64) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384) |
| 150 | + #define LONG_DOUBLE_IS_FLOAT80 1 |
| 151 | +#else |
| 152 | + #undef LONG_DOUBLE_IS_FLOAT80 |
| 153 | +#endif |
| 154 | + |
| 155 | +// We can format float80 values even if the local C environment |
| 156 | +// does not support it. However, by default, we only enable it for |
| 157 | +// environments where float80 == long double. |
| 158 | +// Force enable: -DSWIFT_DTOA_FLOAT80_SUPPORT=1 |
| 159 | +// Force disable: -DSWIFT_DTOA_FLOAT80_SUPPORT=0 |
| 160 | +#ifndef SWIFT_DTOA_FLOAT80_SUPPORT |
| 161 | + #if LONG_DOUBLE_IS_FLOAT80 |
39 | 162 | #define SWIFT_DTOA_FLOAT80_SUPPORT 1
|
40 | 163 | #endif
|
41 | 164 | #endif
|
42 | 165 |
|
| 166 | +// |
| 167 | +// IEEE 754 Binary128 support |
| 168 | +// |
| 169 | + |
| 170 | +// Is "long double" on this system the same as Binary128? |
| 171 | +// (Android on LP64 hardware.) |
| 172 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 113) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384) |
| 173 | + #define LONG_DOUBLE_IS_BINARY128 1 |
| 174 | +#else |
| 175 | + #undef LONG_DOUBLE_IS_BINARY128 |
| 176 | +#endif |
| 177 | + |
| 178 | +// We can format binary128 values even if the local C environment |
| 179 | +// does not support it. However, by default, we only enable it for |
| 180 | +// environments where binary128 == long double. |
| 181 | +// Force enable: -DSWIFT_DTOA_BINARY128_SUPPORT=1 |
| 182 | +// Force disable: -DSWIFT_DTOA_BINARY128_SUPPORT=0 |
| 183 | +#ifndef SWIFT_DTOA_BINARY128_SUPPORT |
| 184 | + #if LONG_DOUBLE_IS_BINARY128 |
| 185 | + #define SWIFT_DTOA_BINARY128_SUPPORT 1 |
| 186 | + #endif |
| 187 | +#endif |
| 188 | + |
43 | 189 | #ifdef __cplusplus
|
44 | 190 | extern "C" {
|
45 | 191 | #endif
|
46 | 192 |
|
47 |
| -#if SWIFT_DTOA_DOUBLE_SUPPORT |
48 |
| -// Compute the optimal decimal digits and exponent for a double. |
| 193 | +// Format a floating point value as an ASCII string |
49 | 194 | //
|
50 | 195 | // Input:
|
51 |
| -// * `d` is the number to be decomposed |
52 |
| -// * `digits` is an array of `digits_length` |
53 |
| -// * `decimalExponent` is a pointer to an `int` |
| 196 | +// * `d` is the number to be formatted |
| 197 | +// * `dest` is a buffer of length `length` |
54 | 198 | //
|
55 | 199 | // Ouput:
|
56 |
| -// * `digits` will receive the decimal digits |
57 |
| -// * `decimalExponent` will receive the decimal exponent |
58 |
| -// * function returns the number of digits generated |
59 |
| -// * the sign of the input number is ignored |
| 200 | +// * Return value is the length of the string placed into `dest` |
| 201 | +// or zero if the buffer is too small. |
| 202 | +// * For infinity, it copies "inf" or "-inf". |
| 203 | +// * For NaN, it outputs a Swift-style detailed dump, including |
| 204 | +// sign, signaling/quiet, and payload (if any). Typical output: |
| 205 | +// "nan", "-nan", "-snan(0x1234)". |
| 206 | +// * For zero, it outputs "0.0" or "-0.0" depending on the sign. |
| 207 | +// * The destination buffer is always null-terminated (even on error) |
| 208 | +// unless the length is zero. |
| 209 | +// |
| 210 | +// Note: If you want to customize the output for Infinity, zero, or |
| 211 | +// Nan, you can easily write a wrapper function that uses `fpclassify` |
| 212 | +// to identify those cases and only calls through to these functions |
| 213 | +// for normal and subnormal values. |
60 | 214 | //
|
61 | 215 | // Guarantees:
|
62 | 216 | //
|
63 |
| -// * Accurate. If you parse the result back to a double via an accurate |
64 |
| -// algorithm (such as Clinger's algorithm), the resulting double will |
65 |
| -// be exactly equal to the original value. On most systems, this |
66 |
| -// implies that using `strtod` to parse the output of |
67 |
| -// `swift_format_double` will yield exactly the original value. |
| 217 | +// * Accurate. If you parse the result back to the same floating-point |
| 218 | +// format via an accurate algorithm (such as Clinger's algorithm), |
| 219 | +// the resulting value will be _exactly_ equal to the original value. |
| 220 | +// On most systems, this implies that using `strtod` to parse the |
| 221 | +// output of `swift_dtoa_optimal_double` will yield exactly the |
| 222 | +// original value. |
68 | 223 | //
|
69 | 224 | // * Short. No other accurate result will have fewer digits.
|
70 | 225 | //
|
71 | 226 | // * Close. If there are multiple possible decimal forms that are
|
72 | 227 | // both accurate and short, the form computed here will be
|
73 | 228 | // closest to the original binary value.
|
74 | 229 | //
|
75 |
| -// Notes: |
76 |
| -// |
77 |
| -// If the input value is infinity or NaN, or `digits_length < 17`, the |
78 |
| -// function returns zero and generates no ouput. |
79 |
| -// |
80 |
| -// If the input value is zero, it will return `decimalExponent = 0` and |
81 |
| -// a single digit of value zero. |
82 |
| -// |
83 |
| -int swift_decompose_double(double d, |
84 |
| - int8_t *digits, size_t digits_length, int *decimalExponent); |
| 230 | +// Naming: The `_p` forms take a `const void *` pointing to the value |
| 231 | +// in memory. These forms do not require any support from the local C |
| 232 | +// environment. In particular, they should work correctly even on |
| 233 | +// systems with no floating-point support. Forms ending in a C |
| 234 | +// floating-point type (e.g., "_float", "_double") are identical but |
| 235 | +// take the corresponding argument type. These forms obviously |
| 236 | +// require the C environment to support passing floating-point types as |
| 237 | +// function arguments. |
85 | 238 |
|
86 |
| -// Format a double as an ASCII string. |
87 |
| -// |
88 |
| -// For infinity, it outputs "inf" or "-inf". |
89 |
| -// |
90 |
| -// For NaN, it outputs a Swift-style detailed dump, including |
91 |
| -// sign, signaling/quiet, and payload (if any). Typical output: |
92 |
| -// "nan", "-nan", "-snan(0x1234)". |
93 |
| -// |
94 |
| -// For zero, it outputs "0.0" or "-0.0" depending on the sign. |
95 |
| -// |
96 |
| -// For other values, it uses `swift_decompose_double` to compute the |
97 |
| -// digits, then uses either `swift_format_decimal` or |
98 |
| -// `swift_format_exponential` to produce an ASCII string depending on |
99 |
| -// the magnitude of the value. |
100 |
| -// |
101 |
| -// In all cases, it returns the number of ASCII characters actually |
102 |
| -// written, or zero if the buffer was too small. |
103 |
| -size_t swift_format_double(double, char *dest, size_t length); |
| 239 | +#if SWIFT_DTOA_BINARY16_SUPPORT |
| 240 | +size_t swift_dtoa_optimal_binary16_p(const void *, char *dest, size_t length); |
104 | 241 | #endif
|
105 | 242 |
|
106 |
| -#if SWIFT_DTOA_FLOAT16_SUPPORT |
107 |
| -// See swift_decompose_double. `digits_length` must be at least 5. |
108 |
| -int swift_decompose_float16(const __fp16 *f, |
109 |
| - int8_t *digits, size_t digits_length, int *decimalExponent); |
110 |
| -// See swift_format_double. |
111 |
| -size_t swift_format_float16(const __fp16 *, char *dest, size_t length); |
| 243 | +#if SWIFT_DTOA_BINARY32_SUPPORT |
| 244 | +size_t swift_dtoa_optimal_binary32_p(const void *, char *dest, size_t length); |
| 245 | +#if FLOAT_IS_BINARY32 |
| 246 | +// If `float` happens to be binary32, define the convenience wrapper. |
| 247 | +size_t swift_dtoa_optimal_float(float, char *dest, size_t length); |
| 248 | +#endif |
112 | 249 | #endif
|
113 | 250 |
|
114 |
| -#if SWIFT_DTOA_FLOAT_SUPPORT |
115 |
| -// See swift_decompose_double. `digits_length` must be at least 9. |
116 |
| -int swift_decompose_float(float f, |
117 |
| - int8_t *digits, size_t digits_length, int *decimalExponent); |
118 |
| -// See swift_format_double. |
119 |
| -size_t swift_format_float(float, char *dest, size_t length); |
| 251 | +#if SWIFT_DTOA_BINARY64_SUPPORT |
| 252 | +size_t swift_dtoa_optimal_binary64_p(const void *, char *dest, size_t length); |
| 253 | +#if DOUBLE_IS_BINARY64 |
| 254 | +// If `double` happens to be binary64, define the convenience wrapper. |
| 255 | +size_t swift_dtoa_optimal_double(double, char *dest, size_t length); |
| 256 | +#endif |
| 257 | +#if LONG_DOUBLE_IS_BINARY64 |
| 258 | +// If `long double` happens to be binary64, define the convenience wrapper. |
| 259 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 260 | +#endif |
120 | 261 | #endif
|
121 | 262 |
|
122 | 263 | #if SWIFT_DTOA_FLOAT80_SUPPORT
|
123 |
| -// See swift_decompose_double. `digits_length` must be at least 21. |
124 |
| -int swift_decompose_float80(long double f, |
125 |
| - int8_t *digits, size_t digits_length, int *decimalExponent); |
126 |
| -// See swift_format_double. |
127 |
| -size_t swift_format_float80(long double, char *dest, size_t length); |
128 |
| -#endif |
129 |
| - |
130 |
| -// Generate an ASCII string from the raw exponent and digit information |
131 |
| -// as generated by `swift_decompose_double`. Returns the number of |
132 |
| -// bytes actually used. If `dest` was not big enough, these functions |
133 |
| -// return zero. The generated string is always terminated with a zero |
134 |
| -// byte unless `length` was zero. |
135 |
| - |
136 |
| -// "Exponential" form uses common exponential format, e.g., "-1.234e+56" |
137 |
| -// The exponent always has a sign and at least two digits. The |
138 |
| -// generated string is never longer than `digits_count + 9` bytes, |
139 |
| -// including the trailing zero byte. |
140 |
| -size_t swift_format_exponential(char *dest, size_t length, |
141 |
| - bool negative, const int8_t *digits, int digits_count, int decimalExponent); |
142 |
| - |
143 |
| -// "Decimal" form writes the value without using exponents. This |
144 |
| -// includes cases such as "0.000001234", "123.456", and "123456000.0". |
145 |
| -// Note that the result always has a decimal point with at least one |
146 |
| -// digit before and one digit after. The generated string is never |
147 |
| -// longer than `digits_count + abs(exponent) + 4` bytes, including the |
148 |
| -// trailing zero byte. |
149 |
| -size_t swift_format_decimal(char *dest, size_t length, |
150 |
| - bool negative, const int8_t *digits, int digits_count, int decimalExponent); |
| 264 | +// Universal entry point works on all platforms, regardless of |
| 265 | +// whether the local system has direct support for float80 |
| 266 | +size_t swift_dtoa_optimal_float80_p(const void *, char *dest, size_t length); |
| 267 | +#if LONG_DOUBLE_IS_FLOAT80 |
| 268 | +// If 'long double' happens to be float80, define a convenience wrapper. |
| 269 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 270 | +#endif |
| 271 | +#endif |
| 272 | + |
| 273 | +#if SWIFT_DTOA_BINARY128_SUPPORT |
| 274 | +// Universal entry point works on all platforms, regardless of |
| 275 | +// whether the local system has direct support for float80 |
| 276 | +size_t swift_dtoa_optimal_binary128_p(const void *, char *dest, size_t length); |
| 277 | +#if LONG_DOUBLE_IS_BINARY128 |
| 278 | +// If 'long double' happens to be binary128, define a convenience wrapper. |
| 279 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 280 | +#endif |
| 281 | +#endif |
151 | 282 |
|
152 | 283 | #ifdef __cplusplus
|
153 | 284 | }
|
|
0 commit comments