|
| 1 | +//===--- SwiftDtoa.h ---------------------------------------------*- c -*-===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2018, 2020 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 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 | +//===---------------------------------------------------------------------===// |
| 76 | + |
| 77 | +#ifndef SWIFT_DTOA_H |
| 78 | +#define SWIFT_DTOA_H |
| 79 | + |
| 80 | +#define __STDC_WANT_IEC_60559_TYPES_EXT__ // FLT16_MAX |
| 81 | +#include <float.h> |
| 82 | +#include <stdbool.h> |
| 83 | +#include <stdint.h> |
| 84 | +#include <stdlib.h> |
| 85 | + |
| 86 | +// |
| 87 | +// IEEE 754 Binary16 support (also known as "half-precision") |
| 88 | +// |
| 89 | + |
| 90 | +// Enable this by default. |
| 91 | +// Force disable: -DSWIFT_DTOA_BINARY16_SUPPORT=0 |
| 92 | +#ifndef SWIFT_DTOA_BINARY16_SUPPORT |
| 93 | + #define SWIFT_DTOA_BINARY16_SUPPORT 1 |
| 94 | +#endif |
| 95 | + |
| 96 | +/// Does this platform support needs to pass _Float16 as a float in |
| 97 | +/// C function? |
| 98 | +#ifndef SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT |
| 99 | +// Windows does not define FLT16_MAX even though it supports _Float16 as argument. |
| 100 | +# if (!defined(FLT16_MAX) || defined(__wasm__)) && !defined(_WIN32) |
| 101 | +# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 1 |
| 102 | +# else |
| 103 | +# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 0 |
| 104 | +# endif |
| 105 | +#endif |
| 106 | + |
| 107 | +// |
| 108 | +// IEEE 754 Binary32 support (also known as "single-precision") |
| 109 | +// |
| 110 | + |
| 111 | +// Does "float" on this system use binary32 format? |
| 112 | +// (Almost all modern systems do this.) |
| 113 | +#if (FLT_RADIX == 2) && (FLT_MANT_DIG == 24) && (FLT_MIN_EXP == -125) && (FLT_MAX_EXP == 128) |
| 114 | + #define FLOAT_IS_BINARY32 1 |
| 115 | +#else |
| 116 | + #undef FLOAT_IS_BINARY32 |
| 117 | +#endif |
| 118 | + |
| 119 | +// We can format binary32 values even if the local C environment |
| 120 | +// does not support it. But `float` == binary32 almost everywhere, |
| 121 | +// so we enable it by default. |
| 122 | +// Force disable: -DSWIFT_DTOA_BINARY32_SUPPORT=0 |
| 123 | +#ifndef SWIFT_DTOA_BINARY32_SUPPORT |
| 124 | + #define SWIFT_DTOA_BINARY32_SUPPORT 1 |
| 125 | +#endif |
| 126 | + |
| 127 | +// |
| 128 | +// IEEE 754 Binary64 support (also known as "double-precision") |
| 129 | +// |
| 130 | + |
| 131 | +// Does "double" on this system use binary64 format? |
| 132 | +// (Almost all modern systems do this.) |
| 133 | +#if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024) |
| 134 | + #define DOUBLE_IS_BINARY64 1 |
| 135 | +#else |
| 136 | + #undef DOUBLE_IS_BINARY64 |
| 137 | +#endif |
| 138 | + |
| 139 | +// Does "long double" on this system use binary64 format? |
| 140 | +// (Windows, for example.) |
| 141 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 53) && (LDBL_MIN_EXP == -1021) && (LDBL_MAX_EXP == 1024) |
| 142 | + #define LONG_DOUBLE_IS_BINARY64 1 |
| 143 | +#else |
| 144 | + #undef LONG_DOUBLE_IS_BINARY64 |
| 145 | +#endif |
| 146 | + |
| 147 | +// We can format binary64 values even if the local C environment |
| 148 | +// does not support it. But `double` == binary64 almost everywhere, |
| 149 | +// so we enable it by default. |
| 150 | +// Force disable: -DSWIFT_DTOA_BINARY64_SUPPORT=0 |
| 151 | +#ifndef SWIFT_DTOA_BINARY64_SUPPORT |
| 152 | + #define SWIFT_DTOA_BINARY64_SUPPORT 1 |
| 153 | +#endif |
| 154 | + |
| 155 | +// |
| 156 | +// Intel x87 Float80 support |
| 157 | +// |
| 158 | + |
| 159 | +// Is "long double" on this system the same as Float80? |
| 160 | +// (macOS, Linux, and FreeBSD when running on x86 or x86_64 processors.) |
| 161 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 64) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384) |
| 162 | + #define LONG_DOUBLE_IS_FLOAT80 1 |
| 163 | +#else |
| 164 | + #undef LONG_DOUBLE_IS_FLOAT80 |
| 165 | +#endif |
| 166 | + |
| 167 | +// We can format float80 values even if the local C environment |
| 168 | +// does not support it. However, by default, we only enable it for |
| 169 | +// environments where float80 == long double. |
| 170 | +// Force enable: -DSWIFT_DTOA_FLOAT80_SUPPORT=1 |
| 171 | +// Force disable: -DSWIFT_DTOA_FLOAT80_SUPPORT=0 |
| 172 | +#ifndef SWIFT_DTOA_FLOAT80_SUPPORT |
| 173 | + #if LONG_DOUBLE_IS_FLOAT80 |
| 174 | + #define SWIFT_DTOA_FLOAT80_SUPPORT 1 |
| 175 | + #endif |
| 176 | +#endif |
| 177 | + |
| 178 | +// |
| 179 | +// IEEE 754 Binary128 support |
| 180 | +// |
| 181 | + |
| 182 | +// Is "long double" on this system the same as Binary128? |
| 183 | +// (Android on LP64 hardware.) |
| 184 | +#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 113) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384) |
| 185 | + #define LONG_DOUBLE_IS_BINARY128 1 |
| 186 | +#else |
| 187 | + #undef LONG_DOUBLE_IS_BINARY128 |
| 188 | +#endif |
| 189 | + |
| 190 | +// We can format binary128 values even if the local C environment |
| 191 | +// does not support it. However, by default, we only enable it for |
| 192 | +// environments where binary128 == long double. |
| 193 | +// Force enable: -DSWIFT_DTOA_BINARY128_SUPPORT=1 |
| 194 | +// Force disable: -DSWIFT_DTOA_BINARY128_SUPPORT=0 |
| 195 | +#ifndef SWIFT_DTOA_BINARY128_SUPPORT |
| 196 | + #if LONG_DOUBLE_IS_BINARY128 |
| 197 | + #define SWIFT_DTOA_BINARY128_SUPPORT 1 |
| 198 | + #endif |
| 199 | +#endif |
| 200 | + |
| 201 | +#ifdef __cplusplus |
| 202 | +extern "C" { |
| 203 | +#endif |
| 204 | + |
| 205 | +// Format a floating point value as an ASCII string |
| 206 | +// |
| 207 | +// Input: |
| 208 | +// * `d` is the number to be formatted |
| 209 | +// * `dest` is a buffer of length `length` |
| 210 | +// |
| 211 | +// Output: |
| 212 | +// * Return value is the length of the string placed into `dest` |
| 213 | +// or zero if the buffer is too small. |
| 214 | +// * For infinity, it copies "inf" or "-inf". |
| 215 | +// * For NaN, it outputs a Swift-style detailed dump, including |
| 216 | +// sign, signaling/quiet, and payload (if any). Typical output: |
| 217 | +// "nan", "-nan", "-snan(0x1234)". |
| 218 | +// * For zero, it outputs "0.0" or "-0.0" depending on the sign. |
| 219 | +// * The destination buffer is always null-terminated (even on error) |
| 220 | +// unless the length is zero. |
| 221 | +// |
| 222 | +// Note: If you want to customize the output for Infinity, zero, or |
| 223 | +// Nan, you can easily write a wrapper function that uses `fpclassify` |
| 224 | +// to identify those cases and only calls through to these functions |
| 225 | +// for normal and subnormal values. |
| 226 | +// |
| 227 | +// Guarantees: |
| 228 | +// |
| 229 | +// * Accurate. If you parse the result back to the same floating-point |
| 230 | +// format via an accurate algorithm (such as Clinger's algorithm), |
| 231 | +// the resulting value will be _exactly_ equal to the original value. |
| 232 | +// On most systems, this implies that using `strtod` to parse the |
| 233 | +// output of `swift_dtoa_optimal_double` will yield exactly the |
| 234 | +// original value. |
| 235 | +// |
| 236 | +// * Short. No other accurate result will have fewer digits. |
| 237 | +// |
| 238 | +// * Close. If there are multiple possible decimal forms that are |
| 239 | +// both accurate and short, the form computed here will be |
| 240 | +// closest to the original binary value. |
| 241 | +// |
| 242 | +// Naming: The `_p` forms take a `const void *` pointing to the value |
| 243 | +// in memory. These forms do not require any support from the local C |
| 244 | +// environment. In particular, they should work correctly even on |
| 245 | +// systems with no floating-point support. Forms ending in a C |
| 246 | +// floating-point type (e.g., "_float", "_double") are identical but |
| 247 | +// take the corresponding argument type. These forms obviously |
| 248 | +// require the C environment to support passing floating-point types as |
| 249 | +// function arguments. |
| 250 | + |
| 251 | +#if SWIFT_DTOA_BINARY16_SUPPORT |
| 252 | +size_t swift_dtoa_optimal_binary16_p(const void *, char *dest, size_t length); |
| 253 | +#if !SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT |
| 254 | +// If `_Float16` is defined, provide this convenience wrapper. |
| 255 | +size_t swift_dtoa_optimal_binary16(_Float16, char *dest, size_t length); |
| 256 | +#endif |
| 257 | +#endif |
| 258 | + |
| 259 | +#if SWIFT_DTOA_BINARY32_SUPPORT |
| 260 | +size_t swift_dtoa_optimal_binary32_p(const void *, char *dest, size_t length); |
| 261 | +#if FLOAT_IS_BINARY32 |
| 262 | +// If `float` happens to be binary32, define the convenience wrapper. |
| 263 | +size_t swift_dtoa_optimal_float(float, char *dest, size_t length); |
| 264 | +#endif |
| 265 | +#endif |
| 266 | + |
| 267 | +#if SWIFT_DTOA_BINARY64_SUPPORT |
| 268 | +size_t swift_dtoa_optimal_binary64_p(const void *, char *dest, size_t length); |
| 269 | +#if DOUBLE_IS_BINARY64 |
| 270 | +// If `double` happens to be binary64, define the convenience wrapper. |
| 271 | +size_t swift_dtoa_optimal_double(double, char *dest, size_t length); |
| 272 | +#endif |
| 273 | +#if LONG_DOUBLE_IS_BINARY64 |
| 274 | +// If `long double` happens to be binary64, define the convenience wrapper. |
| 275 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 276 | +#endif |
| 277 | +#endif |
| 278 | + |
| 279 | +#if SWIFT_DTOA_FLOAT80_SUPPORT |
| 280 | +// Universal entry point works on all platforms, regardless of |
| 281 | +// whether the local system has direct support for float80 |
| 282 | +size_t swift_dtoa_optimal_float80_p(const void *, char *dest, size_t length); |
| 283 | +#if LONG_DOUBLE_IS_FLOAT80 |
| 284 | +// If 'long double' happens to be float80, define a convenience wrapper. |
| 285 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 286 | +#endif |
| 287 | +#endif |
| 288 | + |
| 289 | +#if SWIFT_DTOA_BINARY128_SUPPORT |
| 290 | +// Universal entry point works on all platforms, regardless of |
| 291 | +// whether the local system has direct support for float80 |
| 292 | +size_t swift_dtoa_optimal_binary128_p(const void *, char *dest, size_t length); |
| 293 | +#if LONG_DOUBLE_IS_BINARY128 |
| 294 | +// If 'long double' happens to be binary128, define a convenience wrapper. |
| 295 | +size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length); |
| 296 | +#endif |
| 297 | +#endif |
| 298 | + |
| 299 | +#ifdef __cplusplus |
| 300 | +} |
| 301 | +#endif |
| 302 | +#endif |
0 commit comments