mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
WebAssembly does not support _Float16 type, so we need to guard the use of the type. Unfortunately, Clang does not provide a good way to detect the support of _Float16 type at compile time, so just disable for wasm targets.
303 lines
11 KiB
C
303 lines
11 KiB
C
//===--- SwiftDtoa.h ---------------------------------------------*- c -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2018, 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
//
|
|
/// About SwiftDtoa
|
|
/// ===============
|
|
///
|
|
/// SwiftDtoa is the C implementation that supports the `.description`
|
|
/// and `.debugDescription` properties for the standard Swift
|
|
/// floating-point types. These functions produce the "optimal form"
|
|
/// for the binary floating point value. The optimal form is a
|
|
/// decimal representation that satisfies the following properties:
|
|
///
|
|
/// 1. Accurate. Parsing the value back to a binary floating-point
|
|
/// value of the same precision will exactly yield the original
|
|
/// value. For example, `Double(d.description) == d` for all `Double`
|
|
/// values `d` (except for NaN values, of course).
|
|
///
|
|
/// 2. Short. Of all accurate results, the returned value will
|
|
/// contain the minimum number of significant digits. Note that
|
|
/// this is not quite the same as C++ `to_chars` which promises the
|
|
/// minimal number of characters.
|
|
///
|
|
/// 3. Close. Of all accurate, short results, the value printed will
|
|
/// be the one that is closest to the exact binary floating-point
|
|
/// value.
|
|
///
|
|
/// The optimal form is the ideal textual form for use in JSON and
|
|
/// similar interchange formats because it is accurate, compact, and
|
|
/// can be generated very quickly. It is also ideal for logging and
|
|
/// debugging use; the accuracy guarantees that the result can be
|
|
/// cut-and-pasted to obtain the exact original value, and the
|
|
/// shortness property eliminates unnecessary digits that can be
|
|
/// confusing to readers.
|
|
///
|
|
/// Algorithms that produce such output have been known since at least
|
|
/// 1990, when Steele and White published their Dragon4 algorithm.
|
|
/// However, the earliest algorithms required high-precision
|
|
/// arithmetic which limited their use. Starting in 2010 with the
|
|
/// publication of Grisu3, there has been a surge of interest and
|
|
/// there are now a number of algorithms that can produce optimal
|
|
/// forms very quickly. This particular implementation is loosely
|
|
/// based on Grisu2 but incorporates concepts from Errol and Ryu that
|
|
/// make it significantly faster and ensure accuracy in all cases.
|
|
///
|
|
/// About SwiftDtoa v1
|
|
/// ------------------
|
|
///
|
|
/// The first version of SwiftDtoa was committed to the Swift runtime
|
|
/// in 2018. It supported Swift's Float, Double, and Float80 formats.
|
|
///
|
|
/// About SwiftDtoa v1a
|
|
/// -------------------
|
|
///
|
|
/// Version 1a of SwiftDtoa added support for Float16.
|
|
///
|
|
/// About SwiftDtoa v2
|
|
/// ------------------
|
|
///
|
|
/// Version 2 of SwiftDtoa is a major overhaul with a number of
|
|
/// algorithmic improvements to make it faster (especially for Float16
|
|
/// and Float80), smaller, and more portable (the code only requires
|
|
/// C99 and makes no use of C or C++ floating-point facilities). It
|
|
/// also includes experimental support for IEEE 754 quad-precision
|
|
/// binary128 format, which is not currently supported by Swift.
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_DTOA_H
|
|
#define SWIFT_DTOA_H
|
|
|
|
#define __STDC_WANT_IEC_60559_TYPES_EXT__ // FLT16_MAX
|
|
#include <float.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
//
|
|
// IEEE 754 Binary16 support (also known as "half-precision")
|
|
//
|
|
|
|
// Enable this by default.
|
|
// Force disable: -DSWIFT_DTOA_BINARY16_SUPPORT=0
|
|
#ifndef SWIFT_DTOA_BINARY16_SUPPORT
|
|
#define SWIFT_DTOA_BINARY16_SUPPORT 1
|
|
#endif
|
|
|
|
/// Does this platform support needs to pass _Float16 as a float in
|
|
/// C function?
|
|
#ifndef SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT
|
|
// Windows does not define FLT16_MAX even though it supports _Float16 as argument.
|
|
# if (!defined(FLT16_MAX) || defined(__wasm__)) && !defined(_WIN32)
|
|
# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 1
|
|
# else
|
|
# define SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT 0
|
|
# endif
|
|
#endif
|
|
|
|
//
|
|
// IEEE 754 Binary32 support (also known as "single-precision")
|
|
//
|
|
|
|
// Does "float" on this system use binary32 format?
|
|
// (Almost all modern systems do this.)
|
|
#if (FLT_RADIX == 2) && (FLT_MANT_DIG == 24) && (FLT_MIN_EXP == -125) && (FLT_MAX_EXP == 128)
|
|
#define FLOAT_IS_BINARY32 1
|
|
#else
|
|
#undef FLOAT_IS_BINARY32
|
|
#endif
|
|
|
|
// We can format binary32 values even if the local C environment
|
|
// does not support it. But `float` == binary32 almost everywhere,
|
|
// so we enable it by default.
|
|
// Force disable: -DSWIFT_DTOA_BINARY32_SUPPORT=0
|
|
#ifndef SWIFT_DTOA_BINARY32_SUPPORT
|
|
#define SWIFT_DTOA_BINARY32_SUPPORT 1
|
|
#endif
|
|
|
|
//
|
|
// IEEE 754 Binary64 support (also known as "double-precision")
|
|
//
|
|
|
|
// Does "double" on this system use binary64 format?
|
|
// (Almost all modern systems do this.)
|
|
#if (FLT_RADIX == 2) && (DBL_MANT_DIG == 53) && (DBL_MIN_EXP == -1021) && (DBL_MAX_EXP == 1024)
|
|
#define DOUBLE_IS_BINARY64 1
|
|
#else
|
|
#undef DOUBLE_IS_BINARY64
|
|
#endif
|
|
|
|
// Does "long double" on this system use binary64 format?
|
|
// (Windows, for example.)
|
|
#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 53) && (LDBL_MIN_EXP == -1021) && (LDBL_MAX_EXP == 1024)
|
|
#define LONG_DOUBLE_IS_BINARY64 1
|
|
#else
|
|
#undef LONG_DOUBLE_IS_BINARY64
|
|
#endif
|
|
|
|
// We can format binary64 values even if the local C environment
|
|
// does not support it. But `double` == binary64 almost everywhere,
|
|
// so we enable it by default.
|
|
// Force disable: -DSWIFT_DTOA_BINARY64_SUPPORT=0
|
|
#ifndef SWIFT_DTOA_BINARY64_SUPPORT
|
|
#define SWIFT_DTOA_BINARY64_SUPPORT 1
|
|
#endif
|
|
|
|
//
|
|
// Intel x87 Float80 support
|
|
//
|
|
|
|
// Is "long double" on this system the same as Float80?
|
|
// (macOS, Linux, and FreeBSD when running on x86 or x86_64 processors.)
|
|
#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 64) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384)
|
|
#define LONG_DOUBLE_IS_FLOAT80 1
|
|
#else
|
|
#undef LONG_DOUBLE_IS_FLOAT80
|
|
#endif
|
|
|
|
// We can format float80 values even if the local C environment
|
|
// does not support it. However, by default, we only enable it for
|
|
// environments where float80 == long double.
|
|
// Force enable: -DSWIFT_DTOA_FLOAT80_SUPPORT=1
|
|
// Force disable: -DSWIFT_DTOA_FLOAT80_SUPPORT=0
|
|
#ifndef SWIFT_DTOA_FLOAT80_SUPPORT
|
|
#if LONG_DOUBLE_IS_FLOAT80
|
|
#define SWIFT_DTOA_FLOAT80_SUPPORT 1
|
|
#endif
|
|
#endif
|
|
|
|
//
|
|
// IEEE 754 Binary128 support
|
|
//
|
|
|
|
// Is "long double" on this system the same as Binary128?
|
|
// (Android on LP64 hardware.)
|
|
#if (FLT_RADIX == 2) && (LDBL_MANT_DIG == 113) && (LDBL_MIN_EXP == -16381) && (LDBL_MAX_EXP == 16384)
|
|
#define LONG_DOUBLE_IS_BINARY128 1
|
|
#else
|
|
#undef LONG_DOUBLE_IS_BINARY128
|
|
#endif
|
|
|
|
// We can format binary128 values even if the local C environment
|
|
// does not support it. However, by default, we only enable it for
|
|
// environments where binary128 == long double.
|
|
// Force enable: -DSWIFT_DTOA_BINARY128_SUPPORT=1
|
|
// Force disable: -DSWIFT_DTOA_BINARY128_SUPPORT=0
|
|
#ifndef SWIFT_DTOA_BINARY128_SUPPORT
|
|
#if LONG_DOUBLE_IS_BINARY128
|
|
#define SWIFT_DTOA_BINARY128_SUPPORT 1
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Format a floating point value as an ASCII string
|
|
//
|
|
// Input:
|
|
// * `d` is the number to be formatted
|
|
// * `dest` is a buffer of length `length`
|
|
//
|
|
// Output:
|
|
// * Return value is the length of the string placed into `dest`
|
|
// or zero if the buffer is too small.
|
|
// * For infinity, it copies "inf" or "-inf".
|
|
// * For NaN, it outputs a Swift-style detailed dump, including
|
|
// sign, signaling/quiet, and payload (if any). Typical output:
|
|
// "nan", "-nan", "-snan(0x1234)".
|
|
// * For zero, it outputs "0.0" or "-0.0" depending on the sign.
|
|
// * The destination buffer is always null-terminated (even on error)
|
|
// unless the length is zero.
|
|
//
|
|
// Note: If you want to customize the output for Infinity, zero, or
|
|
// Nan, you can easily write a wrapper function that uses `fpclassify`
|
|
// to identify those cases and only calls through to these functions
|
|
// for normal and subnormal values.
|
|
//
|
|
// Guarantees:
|
|
//
|
|
// * Accurate. If you parse the result back to the same floating-point
|
|
// format via an accurate algorithm (such as Clinger's algorithm),
|
|
// the resulting value will be _exactly_ equal to the original value.
|
|
// On most systems, this implies that using `strtod` to parse the
|
|
// output of `swift_dtoa_optimal_double` will yield exactly the
|
|
// original value.
|
|
//
|
|
// * Short. No other accurate result will have fewer digits.
|
|
//
|
|
// * Close. If there are multiple possible decimal forms that are
|
|
// both accurate and short, the form computed here will be
|
|
// closest to the original binary value.
|
|
//
|
|
// Naming: The `_p` forms take a `const void *` pointing to the value
|
|
// in memory. These forms do not require any support from the local C
|
|
// environment. In particular, they should work correctly even on
|
|
// systems with no floating-point support. Forms ending in a C
|
|
// floating-point type (e.g., "_float", "_double") are identical but
|
|
// take the corresponding argument type. These forms obviously
|
|
// require the C environment to support passing floating-point types as
|
|
// function arguments.
|
|
|
|
#if SWIFT_DTOA_BINARY16_SUPPORT
|
|
size_t swift_dtoa_optimal_binary16_p(const void *, char *dest, size_t length);
|
|
#if !SWIFT_DTOA_PASS_FLOAT16_AS_FLOAT
|
|
// If `_Float16` is defined, provide this convenience wrapper.
|
|
size_t swift_dtoa_optimal_binary16(_Float16, char *dest, size_t length);
|
|
#endif
|
|
#endif
|
|
|
|
#if SWIFT_DTOA_BINARY32_SUPPORT
|
|
size_t swift_dtoa_optimal_binary32_p(const void *, char *dest, size_t length);
|
|
#if FLOAT_IS_BINARY32
|
|
// If `float` happens to be binary32, define the convenience wrapper.
|
|
size_t swift_dtoa_optimal_float(float, char *dest, size_t length);
|
|
#endif
|
|
#endif
|
|
|
|
#if SWIFT_DTOA_BINARY64_SUPPORT
|
|
size_t swift_dtoa_optimal_binary64_p(const void *, char *dest, size_t length);
|
|
#if DOUBLE_IS_BINARY64
|
|
// If `double` happens to be binary64, define the convenience wrapper.
|
|
size_t swift_dtoa_optimal_double(double, char *dest, size_t length);
|
|
#endif
|
|
#if LONG_DOUBLE_IS_BINARY64
|
|
// If `long double` happens to be binary64, define the convenience wrapper.
|
|
size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length);
|
|
#endif
|
|
#endif
|
|
|
|
#if SWIFT_DTOA_FLOAT80_SUPPORT
|
|
// Universal entry point works on all platforms, regardless of
|
|
// whether the local system has direct support for float80
|
|
size_t swift_dtoa_optimal_float80_p(const void *, char *dest, size_t length);
|
|
#if LONG_DOUBLE_IS_FLOAT80
|
|
// If 'long double' happens to be float80, define a convenience wrapper.
|
|
size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length);
|
|
#endif
|
|
#endif
|
|
|
|
#if SWIFT_DTOA_BINARY128_SUPPORT
|
|
// Universal entry point works on all platforms, regardless of
|
|
// whether the local system has direct support for float80
|
|
size_t swift_dtoa_optimal_binary128_p(const void *, char *dest, size_t length);
|
|
#if LONG_DOUBLE_IS_BINARY128
|
|
// If 'long double' happens to be binary128, define a convenience wrapper.
|
|
size_t swift_dtoa_optimal_long_double(long double, char *dest, size_t length);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|