mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
2578 lines
102 KiB
Swift
2578 lines
102 KiB
Swift
//===--- FloatingPointToString.swift -------------------------*- Swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2018-2025 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
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
//
|
|
// Converts floating-point types to "optimal" text formats.
|
|
//
|
|
// The "optimal" form is one with a minimum number of significant
|
|
// digits which will parse to exactly the original value. This form
|
|
// is ideal for JSON serialization and general printing where you
|
|
// don't have specific requirements on the number of significant
|
|
// digits.
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
///
|
|
/// For binary16, this code uses a simple approach that is normally
|
|
/// implemented with variable-length arithmetic. However, due to the
|
|
/// limited range of binary16, this can be implemented with only
|
|
/// 32-bit integer arithmetic.
|
|
///
|
|
/// For other formats, we use a modified form of the Grisu2
|
|
/// algorithm from Florian Loitsch; "Printing Floating-Point Numbers
|
|
/// Quickly and Accurately with Integers", 2010.
|
|
/// https://doi.org/10.1145/1806596.1806623
|
|
///
|
|
/// Some of the Grisu2 modifications were suggested by the "Errol
|
|
/// paper": Marc Andrysco, Ranjit Jhala, Sorin Lerner; "Printing
|
|
/// Floating-Point Numbers: A Faster, Always Correct Method", 2016.
|
|
/// https://doi.org/10.1145/2837614.2837654
|
|
/// In particular, the Errol paper explored the impact of higher-precision
|
|
/// fixed-width arithmetic on Grisu2 and showed a way to rapidly test
|
|
/// the correctness of Grisu-style algorithms.
|
|
///
|
|
/// A few further improvements were inspired by the Ryu algorithm
|
|
/// from Ulf Anders; "Ryū: fast float-to-string conversion", 2018.
|
|
/// https://doi.org/10.1145/3296979.3192369
|
|
///
|
|
/// The full algorithm is extensively commented in the Float64 version
|
|
/// below; refer to that for details.
|
|
///
|
|
/// In summary, this implementation is:
|
|
///
|
|
/// * Fast. It uses only fixed-width integer arithmetic and has
|
|
/// constant memory requirements. For double-precision values on
|
|
/// 64-bit processors, it is competitive with Ryu. For double-precision
|
|
/// values on 32-bit processors, and higher-precision values on all
|
|
/// processors, it is considerably faster.
|
|
///
|
|
/// * Always Accurate. Except for NaNs, converting the decimal form
|
|
/// back to binary will always yield an equal value. For the IEEE
|
|
/// 754 formats, the round trip will produce exactly the same bit
|
|
/// pattern in memory. This assumes, of course, that the conversion
|
|
/// from text to binary uses a correctly-rounded algorithm such as
|
|
/// Clinger 1990 or Eisel-Lemire 2021.
|
|
///
|
|
/// * Always Short. This always selects an accurate result with the
|
|
/// minimum number of significant digits.
|
|
///
|
|
/// * Always Close. Among all accurate, short results, this always
|
|
/// chooses the result that is closest to the exact floating-point
|
|
/// value. (In case of an exact tie, it rounds the last digit even.)
|
|
///
|
|
/// Beyond the requirements above, the precise text form has been
|
|
/// tuned to try to maximize readability:
|
|
/// * Always include a '.' or an 'e' so the result is obviously
|
|
/// a floating-point value
|
|
/// * Exponential form always has 1 digit before the decimal point
|
|
/// * When present, a '.' is never the first or last character
|
|
/// * There is a consecutive range of integer values that can be
|
|
/// represented in any particular type (-2^54...2^54 for double).
|
|
/// We do not use exponential form for integral numbers in this
|
|
/// range.
|
|
/// * Generally follow existing practice: Don't use use exponential
|
|
/// form for fractional values bigger than 10^-4; always write at
|
|
/// least 2 digits for an exponent.
|
|
/// * Apart from the above, we do prefer shorter output.
|
|
|
|
/// Note: If you want to compare performance of this implementation
|
|
/// versus some others, keep in mind that this implementation does
|
|
/// deliberately sacrifice some performance. Any attempt to compare
|
|
/// the performance of this implementation to others should
|
|
/// try to compensate for the following:
|
|
/// * The output ergonomics described above do take some time.
|
|
/// It would be faster to always emit the form "123456e-78"
|
|
// (See `finishFormatting()`)
|
|
/// * The implementations in published papers generally include
|
|
/// large tables with every power of 10 computed out. We've
|
|
/// factored these tables down to conserve code size, which
|
|
/// requires some additional work to reconstruct the needed power
|
|
/// of 10. (See the `intervalContainingPowerOf10_*` functions)
|
|
|
|
///
|
|
/// This Swift implementation was ported from an earlier C version;
|
|
/// the output is exactly the same in all cases.
|
|
/// A few notes on the Swift transcription:
|
|
/// * We use MutableSpan<UTF8.CodeUnit> and MutableRawSpan to
|
|
/// identify blocks of working memory.
|
|
/// * We use unsafe/unchecked operations extensively, supported by
|
|
/// several years of analysis and testing of the original C
|
|
/// implementation to ensure that no unsafety actually occurs. For
|
|
/// Float32, that testing was exhaustive -- we verified all 4
|
|
/// billion possible Float32 values.
|
|
/// * The Swift code uses an idiom of building up to 8 digit characters
|
|
/// in a UInt64 and then writing the whole block to memory.
|
|
/// * The Swift version is slightly faster than the C version;
|
|
/// mostly thanks to various minor algorithmic tweaks that were
|
|
/// found during the translation process.
|
|
/// * Most of this file is annotated for SwiftStdlib 6.2
|
|
/// because it relies on UInt128, MutableSpan, and InlineArray.
|
|
///
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
// ================================================================
|
|
//
|
|
// Float16
|
|
//
|
|
// ================================================================
|
|
|
|
// Float16 is not currently supported on Intel macOS.
|
|
// (This will change once there's a fully-stable Float16
|
|
// ABI on that platform.)
|
|
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
|
|
|
|
// Support Legacy ABI on top of new implementation
|
|
@available(SwiftStdlib 6.2, *)
|
|
@_silgen_name("swift_float16ToString")
|
|
public func _float16ToStringImpl(
|
|
_ textBuffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UInt,
|
|
_ value: Float16,
|
|
_ debug: Bool
|
|
) -> UInt64 {
|
|
// Code below works with raw memory.
|
|
var buffer = unsafe MutableSpan<UTF8.CodeUnit>(
|
|
_unchecked: textBuffer,
|
|
count: Int(bufferLength))
|
|
let textRange = _Float16ToASCII(value: value, buffer: &buffer)
|
|
let textLength = textRange.upperBound - textRange.lowerBound
|
|
|
|
// Move the text to the start of the buffer
|
|
if textRange.lowerBound != 0 {
|
|
unsafe _memmove(
|
|
dest: textBuffer,
|
|
src: textBuffer + textRange.lowerBound,
|
|
size: UInt(truncatingIfNeeded: textLength))
|
|
}
|
|
return UInt64(truncatingIfNeeded: textLength)
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
internal func _Float16ToASCII(
|
|
value f: Float16,
|
|
buffer utf8Buffer: inout MutableSpan<UTF8.CodeUnit>
|
|
) -> Range<Int> {
|
|
// We need a MutableRawSpan in order to use wide store/load operations
|
|
precondition(utf8Buffer.count >= 32)
|
|
var buffer = utf8Buffer.mutableBytes
|
|
|
|
// Step 1: Handle various input cases:
|
|
let binaryExponent: Int
|
|
let significand: Float16.RawSignificand
|
|
let exponentBias = (1 << (Float16.exponentBitCount - 1)) - 2 // 14
|
|
if (f.exponentBitPattern == 0x1f) { // NaN or Infinity
|
|
if (f.isInfinite) {
|
|
return _infinity(buffer: &buffer, sign: f.sign)
|
|
} else { // f.isNaN
|
|
let quietBit =
|
|
(f.significandBitPattern >> (Float16.significandBitCount - 1)) & 1
|
|
let payloadMask = UInt16(1 &<< (Float16.significandBitCount - 2)) - 1
|
|
let payload16 = f.significandBitPattern & payloadMask
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: f.sign,
|
|
quiet: quietBit != 0,
|
|
payloadHigh: 0,
|
|
payloadLow: UInt64(truncatingIfNeeded:payload16))
|
|
}
|
|
} else if (f.exponentBitPattern == 0) {
|
|
if (f.isZero) {
|
|
return _zero(buffer: &buffer, sign: f.sign)
|
|
} else { // Subnormal
|
|
binaryExponent = 1 - exponentBias
|
|
significand = f.significandBitPattern &<< 2
|
|
}
|
|
} else { // normal
|
|
binaryExponent = Int(f.exponentBitPattern) &- exponentBias
|
|
let hiddenBit = Float16.RawSignificand(1) << Float16.significandBitCount
|
|
significand = (f.significandBitPattern &+ hiddenBit) &<< 2
|
|
}
|
|
|
|
// Step 2: Determine the exact target interval
|
|
let halfUlp: Float16.RawSignificand = 2
|
|
let quarterUlp = halfUlp >> 1
|
|
let upperMidpointExact =
|
|
significand &+ halfUlp
|
|
let lowerMidpointExact =
|
|
significand &- ((f.significandBitPattern == 0) ? quarterUlp : halfUlp)
|
|
|
|
var firstDigit = 1
|
|
var nextDigit = firstDigit
|
|
|
|
// Emit the text form differently depending on what range it's in.
|
|
// We use `storeBytes(of:toUncheckedByteOffset:as:)` for most of
|
|
// the output, but are careful to use the checked/safe form
|
|
// `storeBytes(of:toByteOffset:as:)` for the last byte so that we
|
|
// reliably crash if we overflow the provided buffer.
|
|
|
|
// Step 3: If it's < 10^-5, format as exponential form
|
|
if binaryExponent < -13 || (binaryExponent == -13 && significand < 0x1a38) {
|
|
var decimalExponent = -5
|
|
var u =
|
|
(UInt32(upperMidpointExact) << (28 - 13 &+ binaryExponent)) &* 100000
|
|
var l =
|
|
(UInt32(lowerMidpointExact) << (28 - 13 &+ binaryExponent)) &* 100000
|
|
var t =
|
|
(UInt32(significand) << (28 - 13 &+ binaryExponent)) &* 100000
|
|
let mask = (UInt32(1) << 28) - 1
|
|
if t < ((1 << 28) / 10) {
|
|
u &*= 100
|
|
l &*= 100
|
|
t &*= 100
|
|
decimalExponent &-= 2
|
|
}
|
|
if t < (1 << 28) {
|
|
u &*= 10
|
|
l &*= 10
|
|
t &*= 10
|
|
decimalExponent &-= 1
|
|
}
|
|
let uDigit = u >> 28
|
|
if uDigit == (l >> 28) {
|
|
// More than one digit, so write first digit, ".", then the rest
|
|
unsafe buffer.storeBytes(
|
|
of: 0x30 + UInt8(truncatingIfNeeded: uDigit),
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
unsafe buffer.storeBytes(
|
|
of: 0x2e,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
while true {
|
|
u = (u & mask) &* 10
|
|
l = (l & mask) &* 10
|
|
t = (t & mask) &* 10
|
|
let uDigit = u >> 28
|
|
if uDigit != (l >> 28) {
|
|
// Stop before emitting the last digit
|
|
break
|
|
}
|
|
unsafe buffer.storeBytes(
|
|
of: 0x30 &+ UInt8(truncatingIfNeeded: uDigit),
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
}
|
|
}
|
|
let digit = 0x30 &+ (t &+ (1 &<< 27)) >> 28
|
|
unsafe buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: digit),
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
unsafe buffer.storeBytes(
|
|
of: 0x65, // "e"
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
unsafe buffer.storeBytes(
|
|
of: 0x2d, // "-"
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
unsafe buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: -decimalExponent / 10 &+ 0x30),
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
// Last write on this branch, so use a safe checked store
|
|
buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: -decimalExponent % 10 &+ 0x30),
|
|
toByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
} else {
|
|
|
|
// Step 4: Greater than 10^-5, so use decimal format "123.45"
|
|
// (Note: Float16 is never big enough to need exponential for
|
|
// positive exponents)
|
|
// First, split into integer and fractional parts:
|
|
|
|
let intPart : Float16.RawSignificand
|
|
let fractionPart : Float16.RawSignificand
|
|
if binaryExponent < 13 {
|
|
intPart = significand >> (13 &- binaryExponent)
|
|
fractionPart = significand &- (intPart &<< (13 &- binaryExponent))
|
|
} else {
|
|
intPart = significand &<< (binaryExponent &- 13)
|
|
fractionPart = significand &- (intPart >> (binaryExponent &- 13))
|
|
}
|
|
|
|
// Step 5: Emit the integer part
|
|
let text = _intToEightDigits(UInt32(intPart))
|
|
unsafe buffer.storeBytes(
|
|
of: text,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt64.self)
|
|
nextDigit &+= 8
|
|
|
|
// Skip leading zeros
|
|
if intPart < 10 {
|
|
firstDigit &+= 7
|
|
} else if intPart < 100 {
|
|
firstDigit &+= 6
|
|
} else if intPart < 1000 {
|
|
firstDigit &+= 5
|
|
} else if intPart < 10000 {
|
|
firstDigit &+= 4
|
|
} else {
|
|
firstDigit &+= 3
|
|
}
|
|
|
|
// After the integer part comes a period...
|
|
unsafe buffer.storeBytes(
|
|
of: 0x2e,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
|
|
if fractionPart == 0 {
|
|
// Step 6: No fraction, so ".0" and we're done
|
|
// Last write on this branch, so use a checked store
|
|
buffer.storeBytes(
|
|
of: 0x30,
|
|
toByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
} else {
|
|
// Step 7: Emit the fractional part by repeatedly
|
|
// multiplying by 10 to produce successive digits:
|
|
var u = UInt32(upperMidpointExact) &<< (28 - 13 &+ binaryExponent)
|
|
var l = UInt32(lowerMidpointExact) &<< (28 - 13 &+ binaryExponent)
|
|
var t = UInt32(fractionPart) &<< (28 - 13 &+ binaryExponent)
|
|
let mask = (UInt32(1) << 28) - 1
|
|
var uDigit: UInt8 = 0
|
|
var lDigit: UInt8 = 0
|
|
while true {
|
|
u = (u & mask) &* 10
|
|
l = (l & mask) &* 10
|
|
uDigit = UInt8(truncatingIfNeeded: u >> 28)
|
|
lDigit = UInt8(truncatingIfNeeded: l >> 28)
|
|
if uDigit != lDigit {
|
|
t = (t & mask) &* 10
|
|
break
|
|
}
|
|
// This overflows, but we don't care at this point.
|
|
t &*= 10
|
|
unsafe buffer.storeBytes(
|
|
of: 0x30 &+ uDigit,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
}
|
|
t &+= 1 << 27
|
|
if (t & mask) == 0 { // Exactly 1/2
|
|
t = (t >> 28) & ~1 // Round last digit even
|
|
// Rounding `t` even can end up moving `t` below
|
|
// `l`. Detect and correct for this possibility.
|
|
// Exhaustive testing shows that the only input value
|
|
// affected by this is 0.015625 == 2^-6, which
|
|
// incorrectly prints as "0.01562" without this fix.
|
|
// With this, it prints correctly as "0.01563"
|
|
if t < lDigit || (t == lDigit && l > 0) {
|
|
t += 1
|
|
}
|
|
} else {
|
|
t >>= 28
|
|
}
|
|
// Last write on this branch, so use a checked store
|
|
buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: 0x30 + t),
|
|
toByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
}
|
|
}
|
|
if f.sign == .minus {
|
|
buffer.storeBytes(
|
|
of: 0x2d,
|
|
toByteOffset: firstDigit &- 1,
|
|
as: UInt8.self) // "-"
|
|
firstDigit &-= 1
|
|
}
|
|
return firstDigit..<nextDigit
|
|
}
|
|
#endif
|
|
|
|
// ================================================================
|
|
//
|
|
// Float32
|
|
//
|
|
// ================================================================
|
|
|
|
// Support Legacy ABI on top of new implementation
|
|
@_silgen_name("swift_float32ToString")
|
|
public func _float32ToStringImpl(
|
|
_ textBuffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UInt,
|
|
_ value: Float32,
|
|
_ debug: Bool
|
|
) -> UInt64 {
|
|
if #available(SwiftStdlib 6.2, *) {
|
|
// Code below works with raw memory.
|
|
var buffer = unsafe MutableSpan<UTF8.CodeUnit>(
|
|
_unchecked: textBuffer,
|
|
count: Int(bufferLength))
|
|
let textRange = _Float32ToASCII(value: value, buffer: &buffer)
|
|
let textLength = textRange.upperBound - textRange.lowerBound
|
|
|
|
// Move the text to the start of the buffer
|
|
if textRange.lowerBound != 0 {
|
|
unsafe _memmove(
|
|
dest: textBuffer,
|
|
src: textBuffer + textRange.lowerBound,
|
|
size: UInt(truncatingIfNeeded: textLength))
|
|
}
|
|
return UInt64(truncatingIfNeeded: textLength)
|
|
} else {
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
internal func _Float32ToASCII(
|
|
value f: Float32,
|
|
buffer utf8Buffer: inout MutableSpan<UTF8.CodeUnit>
|
|
) -> Range<Int> {
|
|
// Note: The algorithm here is the same as for Float64, only
|
|
// with narrower arithmetic. Refer to `_Float64ToASCII` for
|
|
// more detailed comments and explanation.
|
|
|
|
// We need a MutableRawSpan in order to use wide store/load operations
|
|
precondition(utf8Buffer.count >= 32)
|
|
var buffer = utf8Buffer.mutableBytes
|
|
|
|
// Step 1: Handle the special cases, decompose the input
|
|
|
|
let binaryExponent: Int
|
|
let significand: Float.RawSignificand
|
|
let exponentBias = (1 << (Float.exponentBitCount - 1)) - 2 // 126
|
|
if (f.exponentBitPattern == 0xff) {
|
|
if (f.isInfinite) {
|
|
return _infinity(buffer: &buffer, sign: f.sign)
|
|
} else { // f.isNaN
|
|
let quietBit =
|
|
(f.significandBitPattern >> (Float.significandBitCount - 1)) & 1
|
|
let payloadMask = UInt32(1 << (Float.significandBitCount - 2)) - 1
|
|
let payload32 = f.significandBitPattern & payloadMask
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: f.sign,
|
|
quiet: quietBit != 0,
|
|
payloadHigh: 0,
|
|
payloadLow: UInt64(truncatingIfNeeded:payload32))
|
|
}
|
|
} else if (f.exponentBitPattern == 0) {
|
|
if (f.isZero) {
|
|
return _zero(buffer: &buffer, sign: f.sign)
|
|
} else { // f.isSubnormal
|
|
binaryExponent = 1 - exponentBias
|
|
significand = f.significandBitPattern &<< Float.exponentBitCount
|
|
}
|
|
} else {
|
|
binaryExponent = Int(f.exponentBitPattern) &- exponentBias
|
|
significand =
|
|
((f.significandBitPattern &+ (1 << Float.significandBitCount))
|
|
&<< Float.exponentBitCount)
|
|
}
|
|
|
|
// Step 2: Determine the exact unscaled target interval
|
|
|
|
let halfUlp: Float.RawSignificand = 1 << (Float.exponentBitCount - 1)
|
|
let quarterUlp = halfUlp >> 1
|
|
let upperMidpointExact =
|
|
significand &+ halfUlp
|
|
let lowerMidpointExact =
|
|
significand &- ((f.significandBitPattern == 0) ? quarterUlp : halfUlp)
|
|
let isOddSignificand = ((f.significandBitPattern & 1) != 0)
|
|
|
|
// Step 3: Estimate the base 10 exponent
|
|
|
|
var base10Exponent = decimalExponentFor2ToThe(binaryExponent)
|
|
|
|
// Step 4: Compute power-of-10 scale factor
|
|
|
|
var powerOfTenRoundedDown: UInt64 = 0
|
|
var powerOfTenRoundedUp: UInt64 = 0
|
|
|
|
let bulkFirstDigits = 1
|
|
let powerOfTenExponent = _intervalContainingPowerOf10_Binary32(
|
|
p: -base10Exponent &+ bulkFirstDigits &- 1,
|
|
lower: &powerOfTenRoundedDown,
|
|
upper: &powerOfTenRoundedUp)
|
|
let extraBits = binaryExponent &+ powerOfTenExponent
|
|
|
|
// Step 5: Scale the interval (with rounding)
|
|
|
|
// Experimentally, 11 is as large as we can go here without
|
|
// introducing errors.
|
|
// We need 7 to generate 2 digits at a time below.
|
|
// 11 should allow us to generate 3 digits at a time, but
|
|
// that doesn't seem to be any faster.
|
|
let integerBits = 11
|
|
let fractionBits = 64 - integerBits
|
|
var u: UInt64
|
|
var l: UInt64
|
|
if isOddSignificand {
|
|
// Narrow the interval (odd significand)
|
|
let u1 = _multiply64x32RoundingDown(
|
|
powerOfTenRoundedDown,
|
|
upperMidpointExact)
|
|
u = u1 >> (integerBits - extraBits)
|
|
let l1 = _multiply64x32RoundingUp(
|
|
powerOfTenRoundedUp,
|
|
lowerMidpointExact)
|
|
let bias = UInt64((1 &<< (integerBits &- extraBits)) &- 1)
|
|
l = (l1 &+ bias) >> (integerBits &- extraBits)
|
|
} else {
|
|
// Widen the interval (even significand)
|
|
let u1 = _multiply64x32RoundingUp(
|
|
powerOfTenRoundedUp,
|
|
upperMidpointExact)
|
|
let bias = UInt64((1 &<< (integerBits &- extraBits)) &- 1)
|
|
u = (u1 &+ bias) >> (integerBits &- extraBits)
|
|
let l1 = _multiply64x32RoundingDown(
|
|
powerOfTenRoundedDown,
|
|
lowerMidpointExact)
|
|
l = l1 >> (integerBits &- extraBits)
|
|
}
|
|
|
|
// Step 6: Align first digit, adjust exponent
|
|
|
|
while u < (UInt64(1) &<< fractionBits) {
|
|
base10Exponent &-= 1
|
|
l &*= 10
|
|
u &*= 10
|
|
}
|
|
|
|
// Step 7: Generate decimal digits into the destination buffer
|
|
|
|
var t = u
|
|
var delta = u &- l
|
|
let fractionMask: UInt64 = (1 << fractionBits) - 1
|
|
|
|
// Write 8 leading zeros to the beginning of the buffer:
|
|
unsafe buffer.storeBytes(
|
|
of: 0x3030303030303030,
|
|
toUncheckedByteOffset: 0,
|
|
as: UInt64.self)
|
|
|
|
// Overwrite the first digit at index 7:
|
|
let firstDigit = 7
|
|
let digit = (t >> fractionBits) &+ 0x30
|
|
t &= fractionMask
|
|
unsafe buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: digit),
|
|
toUncheckedByteOffset: firstDigit,
|
|
as: UInt8.self)
|
|
var nextDigit = firstDigit &+ 1
|
|
|
|
// Generate 2 digits at a time...
|
|
while (delta &* 10) < ((t &* 10) & fractionMask) {
|
|
delta &*= 100
|
|
t &*= 100
|
|
let d12 = Int(truncatingIfNeeded: t >> fractionBits)
|
|
let text = unsafe asciiDigitTable[unchecked: d12]
|
|
unsafe buffer.storeBytes(
|
|
of: text,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt16.self)
|
|
nextDigit &+= 2
|
|
t &= fractionMask
|
|
}
|
|
|
|
// ... and a final single digit, if necessary
|
|
if delta < t {
|
|
delta &*= 10
|
|
t &*= 10
|
|
let text = 0x30 + UInt8(truncatingIfNeeded: t >> fractionBits)
|
|
unsafe buffer.storeBytes(
|
|
of: text,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
t &= fractionMask
|
|
}
|
|
|
|
// Adjust the final digit to be closer to the original value
|
|
let isBoundary = (f.significandBitPattern == 0)
|
|
if delta > t &+ (1 &<< fractionBits) {
|
|
let skew: UInt64
|
|
if isBoundary {
|
|
skew = delta &- delta / 3 &- t
|
|
} else {
|
|
skew = delta / 2 &- t
|
|
}
|
|
let one = UInt64(1) << (64 - integerBits)
|
|
let lastAccurateBit = UInt64(1) << 24
|
|
let fractionMask = (one - 1) & ~(lastAccurateBit - 1)
|
|
let oneHalf = one >> 1
|
|
var lastDigit = unsafe buffer.unsafeLoad(
|
|
fromUncheckedByteOffset: nextDigit &- 1,
|
|
as: UInt8.self)
|
|
if ((skew &+ (lastAccurateBit >> 1)) & fractionMask) == oneHalf {
|
|
// Skew is integer + 1/2, round even after adjustment
|
|
let adjust = skew >> (64 - integerBits)
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
lastDigit &= ~1
|
|
} else {
|
|
// Round nearest
|
|
let adjust = (skew &+ oneHalf) >> (64 - integerBits)
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
}
|
|
unsafe buffer.storeBytes(
|
|
of: lastDigit,
|
|
toUncheckedByteOffset: nextDigit &- 1,
|
|
as: UInt8.self)
|
|
}
|
|
|
|
// Step 8: Finish formatting
|
|
let forceExponential =
|
|
((binaryExponent > 25)
|
|
|| (binaryExponent == 25 && !isBoundary))
|
|
return _finishFormatting(
|
|
buffer: &buffer,
|
|
sign: f.sign,
|
|
firstDigit: firstDigit,
|
|
nextDigit: nextDigit,
|
|
forceExponential: forceExponential,
|
|
base10Exponent: base10Exponent)
|
|
}
|
|
|
|
// ================================================================
|
|
//
|
|
// Float64
|
|
//
|
|
// ================================================================
|
|
|
|
// Support Legacy ABI on top of new implementation
|
|
@_silgen_name("swift_float64ToString")
|
|
public func _float64ToStringImpl(
|
|
_ textBuffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UInt,
|
|
_ value: Float64,
|
|
_ debug: Bool
|
|
) -> UInt64 {
|
|
if #available(SwiftStdlib 6.2, *) {
|
|
// Code below works with raw memory.
|
|
var buffer = unsafe MutableSpan<UTF8.CodeUnit>(
|
|
_unchecked: textBuffer,
|
|
count: Int(bufferLength))
|
|
let textRange = _Float64ToASCII(value: value, buffer: &buffer)
|
|
let textLength = textRange.upperBound - textRange.lowerBound
|
|
|
|
// Move the text to the start of the buffer
|
|
if textRange.lowerBound != 0 {
|
|
unsafe _memmove(
|
|
dest: textBuffer,
|
|
src: textBuffer + textRange.lowerBound,
|
|
size: UInt(truncatingIfNeeded: textLength))
|
|
}
|
|
return UInt64(truncatingIfNeeded: textLength)
|
|
} else {
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
internal func _Float64ToASCII(
|
|
value d: Float64,
|
|
buffer utf8Buffer: inout MutableSpan<UTF8.CodeUnit>
|
|
) -> Range<Int> {
|
|
// We need a MutableRawSpan in order to use wide store/load operations
|
|
precondition(utf8Buffer.count >= 32)
|
|
var buffer = utf8Buffer.mutableBytes
|
|
|
|
//
|
|
// Step 1: Handle the special cases, decompose the input
|
|
//
|
|
let binaryExponent: Int
|
|
let significand: Double.RawSignificand
|
|
let exponentBias = (1 << (Double.exponentBitCount - 1)) - 2 // 1022
|
|
|
|
if (d.exponentBitPattern == 0x7ff) {
|
|
if (d.isInfinite) {
|
|
return _infinity(buffer: &buffer, sign: d.sign)
|
|
} else { // d.isNaN
|
|
let quietBit =
|
|
(d.significandBitPattern >> (Double.significandBitCount - 1)) & 1
|
|
let payloadMask = (UInt64(1) << (Double.significandBitCount - 2)) - 1
|
|
let payload64 = d.significandBitPattern & payloadMask
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: d.sign,
|
|
quiet: quietBit != 0,
|
|
payloadHigh: 0,
|
|
payloadLow: UInt64(truncatingIfNeeded:payload64))
|
|
}
|
|
} else if (d.exponentBitPattern == 0) {
|
|
if (d.isZero) {
|
|
return _zero(buffer: &buffer, sign: d.sign)
|
|
} else { // d.isSubnormal
|
|
binaryExponent = 1 - exponentBias
|
|
significand = d.significandBitPattern &<< Double.exponentBitCount
|
|
}
|
|
} else {
|
|
binaryExponent = Int(d.exponentBitPattern) &- exponentBias
|
|
significand =
|
|
((d.significandBitPattern &+ (1 << Double.significandBitCount))
|
|
&<< Double.exponentBitCount)
|
|
}
|
|
// The input has been decomposed as significand * 2^binaryExponent,
|
|
// where `significand` is a 64-bit fraction with the binary
|
|
// point at the far left.
|
|
|
|
// Step 2: Determine the exact unscaled target interval
|
|
|
|
// Grisu-style algorithms construct the shortest decimal digit
|
|
// sequence within a specific interval. To build the appropriate
|
|
// interval, we start by computing the midpoints between this
|
|
// floating-point value and the adjacent ones. Note that this
|
|
// step is an exact computation.
|
|
|
|
let halfUlp: Double.RawSignificand = 1 << (Double.exponentBitCount - 1)
|
|
let quarterUlp = halfUlp >> 1
|
|
let upperMidpointExact = significand &+ halfUlp
|
|
let lowerMidpointExact =
|
|
significand &- ((d.significandBitPattern == 0) ? quarterUlp : halfUlp)
|
|
let isOddSignificand = ((d.significandBitPattern & 1) != 0)
|
|
|
|
// Step 3: Estimate the base 10 exponent
|
|
|
|
// Grisu algorithms are based in part on a simple technique for
|
|
// generating a base-10 form for a binary floating-point number.
|
|
// Start with a binary floating-point number `f * 2^e` and then
|
|
// estimate the decimal exponent `p`. You can then rewrite your
|
|
// original number as:
|
|
//
|
|
// ```
|
|
// f * 2^e * 10^-p * 10^p
|
|
// ```
|
|
//
|
|
// The last term is part of our output, and a good estimate for
|
|
// `p` will ensure that `2^e * 10^-p` is close to 1. Multiplying
|
|
// the first three terms then yields a fraction suitable for
|
|
// producing the decimal digits. Here we use a very fast estimate
|
|
// of `p` that is never off by more than 1; we'll have
|
|
// opportunities later to correct any error.
|
|
|
|
var base10Exponent = decimalExponentFor2ToThe(binaryExponent)
|
|
|
|
// Step 4: Compute power-of-10 scale factor
|
|
|
|
// Compute `10^-p` to 128-bit precision. We generate
|
|
// both over- and under-estimates to ensure we can exactly
|
|
// bound the later use of these values.
|
|
// The `powerOfTenRounded{Up,Down}` values are 128-bit
|
|
// pure fractions with the decimal point at the far left.
|
|
|
|
var powerOfTenRoundedDown: UInt128 = 0
|
|
var powerOfTenRoundedUp: UInt128 = 0
|
|
|
|
// Note the extra factor of 10^bulkFirstDigits -- that will give
|
|
// us a headstart on digit generation later on. (In contrast, Ryu
|
|
// uses an extra factor of 10^17 here to get all the digits up
|
|
// front, but then has to back out any extra digits. Doing that
|
|
// with a 17-digit value requires 64-bit division, which is the
|
|
// root cause of Ryu's poor performance on 32-bit processors. We
|
|
// also might have to back out extra digits if 7 is too many, but
|
|
// will only need 32-bit division in that case.)
|
|
|
|
let bulkFirstDigits = 7
|
|
let bulkFirstDigitFactor: UInt32 = 1000000 // 10^(bulkFirstDigits - 1)
|
|
|
|
let powerOfTenExponent = _intervalContainingPowerOf10_Binary64(
|
|
p: -base10Exponent &+ bulkFirstDigits &- 1,
|
|
lower: &powerOfTenRoundedDown,
|
|
upper: &powerOfTenRoundedUp)
|
|
|
|
let extraBits = binaryExponent + powerOfTenExponent
|
|
|
|
// Step 5: Scale the interval (with rounding)
|
|
|
|
// As mentioned above, the final digit generation works
|
|
// with an interval, so we actually apply the scaling
|
|
// to the upper and lower midpoint values separately.
|
|
|
|
// As part of the scaling here, we'll switch from a pure
|
|
// fraction with zero bit integer portion and 128-bit fraction
|
|
// to a fixed-point form with 32 bits in the integer portion.
|
|
|
|
let integerBits = 32
|
|
let roundingBias =
|
|
UInt128((1 &<< UInt64(truncatingIfNeeded: integerBits &- extraBits)) &- 1)
|
|
var u: UInt128
|
|
var l: UInt128
|
|
if isOddSignificand {
|
|
// Case A: Narrow the interval (odd significand)
|
|
|
|
// Loitsch' original Grisu2 always rounds so as to narrow the
|
|
// interval. Since our digit generation will select a value
|
|
// within the scaled interval, narrowing the interval
|
|
// guarantees that we will find a digit sequence that converts
|
|
// back to the original value.
|
|
|
|
// This ensures accuracy but, as explained in Loitsch' paper,
|
|
// this carries a risk that there will be a shorter digit
|
|
// sequence outside of our narrowed interval that we will
|
|
// miss. This risk obviously gets lower with increased
|
|
// precision, but it wasn't until the Errol paper that anyone
|
|
// had a good way to test whether a particular implementation
|
|
// had sufficient precision. That paper shows a way to enumerate
|
|
// the worst-case numbers; those numbers that are extremely close
|
|
// to the mid-points between adjacent floating-point values.
|
|
// These are the values that might sit just outside of the
|
|
// narrowed interval. By testing these values, we can verify
|
|
// the correctness of our implementation.
|
|
|
|
// Multiply out the upper midpoint, rounding down...
|
|
let u1 = _multiply128x64RoundingDown(
|
|
powerOfTenRoundedDown,
|
|
upperMidpointExact)
|
|
// Account for residual binary exponent and adjust
|
|
// to the fixed-point format
|
|
u = u1 >> (integerBits - extraBits)
|
|
|
|
// Conversely for the lower midpoint...
|
|
let l1 = _multiply128x64RoundingUp(
|
|
powerOfTenRoundedUp,
|
|
lowerMidpointExact)
|
|
l = (l1 + roundingBias) >> (integerBits - extraBits)
|
|
} else {
|
|
// Case B: Widen the interval (even significand)
|
|
|
|
// As explained in Errol Theorem 6, in certain cases there is
|
|
// a short decimal representation at the exact boundary of the
|
|
// scaled interval. When such a number is converted back to
|
|
// binary, it will get rounded to the adjacent even
|
|
// significand.
|
|
|
|
// So when the significand is even, we round so as to widen
|
|
// the interval in order to ensure that the exact midpoints
|
|
// are considered. Of couse, this ensures that we find a
|
|
// short result but carries a risk of selecting a result
|
|
// outside of the exact scaled interval (which would be
|
|
// inaccurate).
|
|
// (This technique of rounding differently for even/odd significands
|
|
// seems to be new; I've not seen it described in any of the
|
|
// papers on floating-point printing.)
|
|
|
|
// The same testing approach described above (based on results
|
|
// in the Errol paper) also applies
|
|
// to this case.
|
|
|
|
let u1 = _multiply128x64RoundingUp(
|
|
powerOfTenRoundedUp,
|
|
upperMidpointExact)
|
|
u = (u1 &+ roundingBias) >> (integerBits - extraBits)
|
|
let l1 = _multiply128x64RoundingDown(
|
|
powerOfTenRoundedDown,
|
|
lowerMidpointExact)
|
|
l = l1 >> (integerBits - extraBits)
|
|
}
|
|
|
|
// Step 6: Align the first digit, adjust exponent
|
|
|
|
// Calculations above used an estimate for the power-of-ten scale.
|
|
// Here, we compensate for any error in that estimate by testing
|
|
// whether we have the expected number of digits in the integer
|
|
// portion and correcting as necessary. This also serves to
|
|
// prune leading zeros from subnormals.
|
|
|
|
// Except for subnormals, this loop never runs more than once.
|
|
// For subnormals, this might run as many as 16 times.
|
|
let minimumU = UInt128(bulkFirstDigitFactor) << (128 - integerBits)
|
|
while u < minimumU {
|
|
base10Exponent -= 1
|
|
l &*= 10
|
|
u &*= 10
|
|
}
|
|
|
|
// Step 7: Produce decimal digits
|
|
|
|
// One standard approach generates digits for the scaled upper and
|
|
// lower boundaries and stops at the first digit that
|
|
// differs. For example, note that 0.1234 is the shortest decimal
|
|
// between u = 0.123456 and l = 0.123345.
|
|
|
|
// Grisu optimizes this by generating digits for the upper bound
|
|
// (multiplying by 10 to isolate each digit) while simultaneously
|
|
// scaling the interval width `delta`. As we remove each digit
|
|
// from the upper bound, the remainder is the difference between
|
|
// the base-10 value generated so far and the true upper bound.
|
|
// When that remainder is less than the scaled width of the
|
|
// interval, we know the current digits specify a value within the
|
|
// target interval.
|
|
|
|
// The logic below actually blends three different digit-generation
|
|
// strategies:
|
|
// * The first digits are already in the integer portion of the
|
|
// fixed-point value, thanks to the `bulkFirstDigits` factor above.
|
|
// We can just break those down and write them out.
|
|
// * If we generated too many digits, we use a Ryu-inspired technique
|
|
// to backtrack.
|
|
// * If we generated too few digits (the usual case), we use an
|
|
// optimized form of the Grisu2 method to produce the remaining
|
|
// values.
|
|
|
|
//
|
|
// Generate digits and build the output.
|
|
//
|
|
|
|
// Generate digits for `t` with interval width `delta = u - l`
|
|
// As above, these are fixed-point with 32-bit integer, 96-bit fraction
|
|
var t = u
|
|
var delta = u &- l
|
|
let fractionMask = (UInt128(1) << 96) - 1
|
|
|
|
var nextDigit = 5
|
|
var firstDigit = nextDigit
|
|
unsafe buffer.storeBytes(
|
|
of: 0x3030303030303030 as UInt64,
|
|
toUncheckedByteOffset: 0,
|
|
as: UInt64.self)
|
|
|
|
// Our initial scaling gave us the first 7 digits already:
|
|
let d12345678 = UInt32(truncatingIfNeeded: t._high >> 32)
|
|
t &= fractionMask
|
|
|
|
if delta >= t {
|
|
// Oops! We have too many digits. Back out the extra ones to
|
|
// get the right answer. This is similar to Ryu, but since
|
|
// we've only produced seven digits, we only need 32-bit
|
|
// arithmetic here. (Ryu needs 64-bit arithmetic to back out
|
|
// digits, which severely compromises performance on 32-bit
|
|
// processors. The same problem occurs with Ryu for 128-bit
|
|
// floats on 64-bit processors.)
|
|
// A few notes:
|
|
// * Our target hardware always supports 32-bit hardware division,
|
|
// so this should be reasonably fast.
|
|
// * For small integers (like "2.0"), Ryu would have to back out 16
|
|
// digits; we only have to back out 6.
|
|
// * Very few double-precision values actually need fewer than 7
|
|
// digits. So this is rarely used except in workloads that
|
|
// specifically use double for small integers.
|
|
|
|
// Why this is critical for performance: In order to use the
|
|
// 8-digits-at-a-time optimization below, we need at least 30
|
|
// bits in the integer part of our fixed-point format above.
|
|
// If we only use bulkDigits = 1, that leaves only 128 - 30 =
|
|
// 98 bit accuracy for our scaling step, which isn't enough
|
|
// (experiments suggest that binary64 needs ~110 bits for
|
|
// correctness). So we have to use a large bulkDigits value
|
|
// to make full use of the 128-bit scaling above, which forces
|
|
// us to have some form of logic to handle the case of too
|
|
// many digits. The alternatives are either to use >128 bit
|
|
// arithmetic, or to back up and repeat the original scaling
|
|
// with bulkDigits = 1.
|
|
|
|
let uHigh = u._high
|
|
let lHigh = (l &+ UInt128(UInt64.max))._high
|
|
let tHigh: UInt64
|
|
if d.significand == 0 {
|
|
tHigh = (uHigh &+ lHigh &* 2) / 3
|
|
} else {
|
|
tHigh = (uHigh &+ lHigh) / 2
|
|
}
|
|
var u0 = UInt32(truncatingIfNeeded: uHigh >> (64 - integerBits))
|
|
var l0 = UInt32(truncatingIfNeeded: lHigh >> (64 - integerBits))
|
|
if lHigh & ((1 << (64 - integerBits)) - 1) != 0 {
|
|
l0 &+= 1
|
|
}
|
|
var t0 = UInt32(truncatingIfNeeded: tHigh >> (64 - integerBits))
|
|
var t0digits = 8
|
|
|
|
var u1 = u0 / 10
|
|
var l1 = (l0 &+ 9) / 10
|
|
var trailingZeros = (t == 0)
|
|
var droppedDigit = UInt32(
|
|
truncatingIfNeeded: ((tHigh &* 10) >> (64 - integerBits)) % 10)
|
|
while u1 >= l1 && u1 != 0 {
|
|
u0 = u1
|
|
l0 = l1
|
|
trailingZeros = trailingZeros && (droppedDigit == 0)
|
|
droppedDigit = t0 % 10
|
|
t0 /= 10
|
|
t0digits -= 1
|
|
u1 = u0 / 10
|
|
l1 = (l0 &+ 9) / 10
|
|
}
|
|
// Correct the final digit
|
|
if droppedDigit > 5 || (droppedDigit == 5 && !trailingZeros) { // > 0.5000
|
|
t0 &+= 1
|
|
} else if droppedDigit == 5 && trailingZeros { // == 0.5000
|
|
t0 &+= 1
|
|
t0 &= ~1
|
|
}
|
|
// t0 has t0digits digits. Write them out
|
|
let text = _intToEightDigits(t0) >> ((8 - t0digits) * 8)
|
|
buffer.storeBytes(
|
|
of: text,
|
|
toByteOffset: nextDigit,
|
|
as: UInt64.self)
|
|
nextDigit &+= t0digits
|
|
firstDigit &+= 1
|
|
} else {
|
|
// Our initial scaling did not produce too many digits. The
|
|
// `d12345678` value holds the first 7 digits (plus a leading
|
|
// zero). The remainder of this algorithm is basically just a
|
|
// heavily-optimized variation of Grisu2.
|
|
|
|
// Write out exactly 8 digits, assuming little-endian.
|
|
let chars = _intToEightDigits(d12345678)
|
|
unsafe buffer.storeBytes(
|
|
of: chars,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt64.self)
|
|
nextDigit &+= 8
|
|
firstDigit &+= 1
|
|
|
|
// >90% of random binary64 values need at least 15 digits.
|
|
// We have seven so there's probably at least 8 more, which
|
|
// we can grab all at once.
|
|
let TenToTheEighth = 100000000 as UInt128 // 10^(15-bulkFirstDigits)
|
|
let d0 = delta * TenToTheEighth
|
|
var t0 = t * TenToTheEighth
|
|
// The integer part of t0 is the next 8 digits
|
|
let next8Digits = UInt32(truncatingIfNeeded: t0._high >> 32)
|
|
t0 &= fractionMask
|
|
if d0 < t0 {
|
|
// We got 8 more digits! (So number is at least 15 digits)
|
|
// Write them out:
|
|
let chars = _intToEightDigits(next8Digits)
|
|
unsafe buffer.storeBytes(
|
|
of: chars,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt64.self)
|
|
nextDigit &+= 8
|
|
t = t0
|
|
delta = d0
|
|
}
|
|
|
|
// Generate remaining digits one at a time, following Grisu:
|
|
while (delta < t) {
|
|
delta &*= 10
|
|
t &*= 10
|
|
unsafe buffer.storeBytes(
|
|
of: UInt8(truncatingIfNeeded: t._high >> 32) &+ 0x30,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
t &= fractionMask
|
|
}
|
|
|
|
// Adjust the final digit to be closer to the original value.
|
|
// This accounts for the fact that sometimes there is more than
|
|
// one shortest digit sequence.
|
|
|
|
// For example, consider how the above would work if you had the
|
|
// value 0.1234 and computed u = 0.1257, l = 0.1211. The above
|
|
// digit generation works with `u`, so produces 0.125. But the
|
|
// values 0.122, 0.123, and 0.124 are just as short and 0.123 is
|
|
// therefore the best choice, since it's closest to the original
|
|
// value.
|
|
|
|
// We know delta and t are both less than 10.0 here, so we can
|
|
// shed some excess integer bits to simplify the following:
|
|
let adjustIntegerBits = 4 // Integer bits for "adjust" phase
|
|
let deltaHigh64 = UInt64(
|
|
truncatingIfNeeded: delta >> (64 - integerBits + adjustIntegerBits))
|
|
let tHigh64 = UInt64(
|
|
truncatingIfNeeded: t >> (64 - integerBits + adjustIntegerBits))
|
|
|
|
let one = UInt64(1) << (64 - adjustIntegerBits)
|
|
let adjustFractionMask = one - 1
|
|
let oneHalf = one >> 1
|
|
if deltaHigh64 >= tHigh64 &+ one {
|
|
// The `skew` is the difference between our
|
|
// computed digits and the original exact value.
|
|
var skew: UInt64
|
|
if (d.significandBitPattern == 0) {
|
|
skew = deltaHigh64 &- deltaHigh64 / 3 &- tHigh64
|
|
} else {
|
|
skew = deltaHigh64 / 2 &- tHigh64
|
|
}
|
|
|
|
var lastDigit = unsafe buffer.unsafeLoad(
|
|
fromUncheckedByteOffset: nextDigit - 1,
|
|
as: UInt8.self)
|
|
|
|
// We use the `skew` to figure out whether there's
|
|
// a better base-10 value than our current one.
|
|
if (skew & adjustFractionMask) == oneHalf {
|
|
// Difference is an integer + exactly 1/2, so ...
|
|
let adjust = skew >> (64 - adjustIntegerBits)
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
// ... we round the last digit even.
|
|
lastDigit &= ~1
|
|
} else {
|
|
let adjust = (skew + oneHalf) >> (64 - adjustIntegerBits)
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
}
|
|
buffer.storeBytes(
|
|
of: lastDigit,
|
|
toByteOffset: nextDigit - 1,
|
|
as: UInt8.self)
|
|
}
|
|
}
|
|
|
|
// Step 8: Finalize formatting by rearranging
|
|
// the digits and filling in decimal points,
|
|
// exponents, and zero padding.
|
|
let isBoundary = (d.significandBitPattern == 0)
|
|
let forceExponential =
|
|
((binaryExponent > 54) || (binaryExponent == 54 && !isBoundary))
|
|
return _finishFormatting(
|
|
buffer: &buffer,
|
|
sign: d.sign,
|
|
firstDigit: firstDigit,
|
|
nextDigit: nextDigit,
|
|
forceExponential: forceExponential,
|
|
base10Exponent: base10Exponent)
|
|
}
|
|
|
|
|
|
// ================================================================
|
|
//
|
|
// Float80
|
|
//
|
|
// ================================================================
|
|
|
|
// Float80 is only available on Intel x86/x86_64 processors on certain operating systems
|
|
// This matches the condition for the Float80 type
|
|
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)))) && (arch(i386) || arch(x86_64))
|
|
|
|
// Support Legacy ABI on top of new implementation
|
|
@_silgen_name("swift_float80ToString")
|
|
internal func _float80ToStringImpl(
|
|
_ textBuffer: UnsafeMutablePointer<UTF8.CodeUnit>,
|
|
_ bufferLength: UInt,
|
|
_ value: Float80,
|
|
_ debug: Bool
|
|
) -> UInt64 {
|
|
if #available(SwiftStdlib 6.2, *) {
|
|
// Code below works with raw memory.
|
|
var buffer = unsafe MutableSpan<UTF8.CodeUnit>(
|
|
_unchecked: textBuffer,
|
|
count: Int(bufferLength))
|
|
let textRange = _Float80ToASCII(value: value, buffer: &buffer)
|
|
let textLength = textRange.upperBound - textRange.lowerBound
|
|
|
|
// Move the text to the start of the buffer
|
|
if textRange.lowerBound != 0 {
|
|
unsafe _memmove(
|
|
dest: textBuffer,
|
|
src: textBuffer + textRange.lowerBound,
|
|
size: UInt(truncatingIfNeeded: textLength))
|
|
}
|
|
return UInt64(truncatingIfNeeded: textLength)
|
|
} else {
|
|
fatalError()
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
internal func _Float80ToASCII(
|
|
value f: Float80,
|
|
buffer utf8Buffer: inout MutableSpan<UTF8.CodeUnit>
|
|
) -> Range<Int> {
|
|
// We need a MutableRawSpan in order to use wide store/load operations
|
|
precondition(utf8Buffer.count >= 32)
|
|
var buffer = utf8Buffer.mutableBytes
|
|
|
|
// Step 1: Handle special cases, decompose the input
|
|
|
|
// The Intel 80-bit floating point format has some quirks that
|
|
// make this a lot more complex than the corresponding logic for
|
|
// the IEEE 754 portable formats.
|
|
|
|
// f.significandBitPattern is processed to try to mimic the
|
|
// semantics of IEEE portable formats. But for the following,
|
|
// we need the actual raw bits:
|
|
let rawSignificand = f._representation.explicitSignificand
|
|
let binaryExponent: Int
|
|
let significand: Float80.RawSignificand
|
|
let exponentBias = (1 << (Float80.exponentBitCount - 1)) - 2 // 16382
|
|
let isBoundary = f.significandBitPattern == 0
|
|
if f.exponentBitPattern == 0x7fff { // NaN or Infinity
|
|
// 80387 semantics and 80287 semantics differ somewhat;
|
|
// we follow 80387 semantics here.
|
|
// See: Wikipedia.org "Extended Precision"
|
|
// See: Intel's "Floating Point Reference Sheet"
|
|
// https://software.intel.com/content/dam/develop/external/us/en/documents/floating-point-reference-sheet.pdf
|
|
let selector = rawSignificand >> 62
|
|
let payload = rawSignificand & ((1 << 62) - 1)
|
|
switch selector {
|
|
case 0: // ∞ or snan on 287, invalid on 387
|
|
fallthrough
|
|
case 1: // Pseudo-NaN: snan on 287, invalid on 387
|
|
// Invalid patterns treated as plain "nan"
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: .plus,
|
|
quiet: true,
|
|
payloadHigh: 0,
|
|
payloadLow: payload)
|
|
case 2:
|
|
if payload == 0 { // snan on 287, ∞ on 387
|
|
return _infinity(buffer: &buffer, sign: f.sign)
|
|
} else { // snan on 287 and 387
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: f.sign,
|
|
quiet: false,
|
|
payloadHigh: 0,
|
|
payloadLow: payload)
|
|
}
|
|
case 3:
|
|
// Zero payload and sign bit set is "indefinite" (treated as qNaN here),
|
|
// otherwise qNaN on 387, sNaN on 287
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: f.sign,
|
|
quiet: true,
|
|
payloadHigh: 0,
|
|
payloadLow: payload)
|
|
default:
|
|
fatalError()
|
|
}
|
|
} else if f.exponentBitPattern == 0 {
|
|
if rawSignificand == 0 { // Zero
|
|
return _zero(buffer: &buffer, sign: f.sign)
|
|
} else { // subnormal
|
|
binaryExponent = 1 - exponentBias
|
|
significand = rawSignificand
|
|
}
|
|
} else if rawSignificand >> 63 == 1 { // Normal
|
|
binaryExponent = Int(bitPattern:f.exponentBitPattern) - exponentBias
|
|
significand = rawSignificand
|
|
} else {
|
|
return nan_details(
|
|
buffer: &buffer,
|
|
sign: .plus,
|
|
quiet: true,
|
|
payloadHigh: 0,
|
|
payloadLow: 0)
|
|
}
|
|
|
|
// Step 2: Determine the exact unscaled target interval
|
|
let halfUlp = UInt64(1) << 63
|
|
let quarterUlp = halfUlp >> 1
|
|
let threeQuarterUlp = halfUlp + quarterUlp
|
|
// Significand is the upper 64 bits of our 128-bit franction
|
|
// Upper midpoint adds 1/2 ULP:
|
|
let upperMidpointExact = UInt128(_low: halfUlp, _high: significand)
|
|
// Lower midpoint subtracts 1 ULP and then adds 1/2 or 3/4 ULP:
|
|
let lowerMidpointExact = UInt128(
|
|
_low: isBoundary ? threeQuarterUlp : halfUlp,
|
|
_high: significand - 1)
|
|
|
|
let forceExponential =
|
|
(binaryExponent > 65
|
|
|| (binaryExponent == 65 && !isBoundary))
|
|
return _backend_256bit(
|
|
buffer: &buffer,
|
|
upperMidpointExact: upperMidpointExact,
|
|
lowerMidpointExact: lowerMidpointExact,
|
|
sign: f.sign,
|
|
isBoundary: isBoundary,
|
|
isOddSignificand: (f.significandBitPattern & 1) != 0,
|
|
binaryExponent: binaryExponent,
|
|
forceExponential: forceExponential)
|
|
}
|
|
#endif
|
|
|
|
// ================================================================
|
|
//
|
|
// Float128
|
|
//
|
|
// ================================================================
|
|
|
|
#if false
|
|
// Note: We don't need _float128ToStringImpl, since that's only for
|
|
// backwards compatibility, and the legacy ABI never supported
|
|
// Float128.
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
internal func _Float128ToASCII(
|
|
value d: Float128,
|
|
buffer utf8Buffer: inout MutableSpan<UTF8.CodeUnit>
|
|
) -> Range<Int> {
|
|
// TODO: Write Me!
|
|
|
|
// Note: All the interesting parts are already implemented in _backend_256bit(...),
|
|
// so this can easily be implemented someday by just copyihng _Float80ToASCII
|
|
// and making the obvious changes. (See the introductory parts of
|
|
// _Float64ToASCII for the structure common to all IEEE 754 formats.)
|
|
}
|
|
#endif
|
|
|
|
// ================================================================
|
|
//
|
|
// Float80/Float128 common backend
|
|
//
|
|
// This uses 256-bit fixed-width arithmetic to efficiently compute the
|
|
// optimal form for a decomposed float80 or binary128 value. It is
|
|
// less heavily commented than the 128-bit Double implementation
|
|
// above; see that implementation for detailed explanation of the
|
|
// logic here.
|
|
//
|
|
// Float80 could be handled more efficiently with 192-bit fixed-width
|
|
// arithmetic. But the code size savings from sharing this logic
|
|
// between float80 and binary128 are substantial, and the resulting
|
|
// float80 performance is still much better than competing
|
|
// implementations.
|
|
//
|
|
// Also in the interest of code size savings, this eschews some of the
|
|
// optimizations used by the 128-bit Double implementation above.
|
|
// Those optimizations are simple to reintroduce if you're interested
|
|
// in further performance improvements.
|
|
//
|
|
// If you are interested in extreme code size, you can also use this
|
|
// backend for binary32 and binary64, eliminating the separate 128-bit
|
|
// implementation. That variation offers surprisingly reasonable
|
|
// performance overall.
|
|
//
|
|
// ================================================================
|
|
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !(os(macOS) || os(iOS) || os(watchOS) || os(tvOS)))) && (arch(i386) || arch(x86_64))
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _backend_256bit(
|
|
buffer: inout MutableRawSpan,
|
|
upperMidpointExact: UInt128,
|
|
lowerMidpointExact: UInt128,
|
|
sign: FloatingPointSign,
|
|
isBoundary: Bool,
|
|
isOddSignificand: Bool,
|
|
binaryExponent: Int,
|
|
forceExponential: Bool
|
|
) -> Range<Int> {
|
|
|
|
// Step 3: Estimate the base 10 exponent
|
|
var base10Exponent = decimalExponentFor2ToThe(binaryExponent)
|
|
|
|
// Step 4: Compute a power-of-10 scale factor
|
|
var powerOfTenRoundedDown = _UInt256()
|
|
var powerOfTenRoundedUp = _UInt256()
|
|
let powerOfTenExponent = _intervalContainingPowerOf10_Binary128(
|
|
p: -base10Exponent,
|
|
lower: &powerOfTenRoundedDown,
|
|
upper: &powerOfTenRoundedUp)
|
|
let extraBits = binaryExponent &+ powerOfTenExponent
|
|
|
|
// Step 5: Scale the interval (with rounding)
|
|
let integerBits = 14
|
|
let high64FractionBits = 64 - integerBits
|
|
var u: _UInt256
|
|
var l: _UInt256
|
|
if isOddSignificand {
|
|
// Narrow the interval (odd significand)
|
|
u = powerOfTenRoundedDown
|
|
u.multiplyRoundingDown(by: upperMidpointExact)
|
|
u.shiftRightRoundingDown(by: integerBits &- extraBits)
|
|
|
|
l = powerOfTenRoundedUp
|
|
l.multiplyRoundingUp(by: lowerMidpointExact)
|
|
l.shiftRightRoundingUp(by: integerBits &- extraBits)
|
|
} else {
|
|
// Widen the interval (even significand)
|
|
u = powerOfTenRoundedUp
|
|
u.multiplyRoundingUp(by: upperMidpointExact)
|
|
u.shiftRightRoundingUp(by: integerBits &- extraBits)
|
|
|
|
l = powerOfTenRoundedDown
|
|
l.multiplyRoundingDown(by: lowerMidpointExact)
|
|
l.shiftRightRoundingDown(by: integerBits &- extraBits)
|
|
}
|
|
|
|
// Step 6: Align first digit, adjust exponent
|
|
while u.high._high < (UInt64(1) << high64FractionBits) {
|
|
base10Exponent &-= 1
|
|
l.multiply(by: UInt32(10))
|
|
u.multiply(by: UInt32(10))
|
|
}
|
|
var t = u
|
|
var delta = u &- l
|
|
|
|
// Step 7: Generate digits
|
|
|
|
// Include 8 "0" characters at the beginning of the buffer
|
|
// for finishFormatting to use
|
|
buffer.storeBytes(
|
|
of: 0x3030303030303030,
|
|
toByteOffset: 0,
|
|
as: UInt64.self)
|
|
// Start writing digits just after that
|
|
let firstDigit = 8
|
|
var nextDigit = firstDigit
|
|
buffer.storeBytes(
|
|
of: 0x30 + UInt8(truncatingIfNeeded: t.extractIntegerPart(integerBits)),
|
|
toByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
|
|
// It would be nice to generate 8 digits at a time and take
|
|
// advantage of intToEightDigits, but our integer portion has only
|
|
// 14 bits. We can't make that bigger without either sacrificing
|
|
// too much precision for correct Float128 or folding the first
|
|
// digits into the scaling (as we do with Double) which would
|
|
// require a back-out phase here (as we do with Double).
|
|
|
|
// If there is at least one more digit possible...
|
|
if delta < t {
|
|
|
|
// Try grabbing four digits at a time
|
|
var d0 = delta
|
|
var t0 = t
|
|
d0.multiply(by: 10000)
|
|
t0.multiply(by: 10000)
|
|
var d1234 = t0.extractIntegerPart(integerBits)
|
|
while d0 < t0 {
|
|
let d12 = d1234 / 100
|
|
let d34 = d1234 % 100
|
|
unsafe buffer.storeBytes(
|
|
of: asciiDigitTable[Int(bitPattern:d12)],
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt16.self)
|
|
unsafe buffer.storeBytes(
|
|
of: asciiDigitTable[Int(bitPattern:d34)],
|
|
toUncheckedByteOffset: nextDigit &+ 2,
|
|
as: UInt16.self)
|
|
nextDigit &+= 4
|
|
t = t0
|
|
delta = d0
|
|
d0.multiply(by: 10000)
|
|
t0.multiply(by: 10000)
|
|
d1234 = t0.extractIntegerPart(integerBits)
|
|
}
|
|
|
|
// Finish by generating one digit at a time...
|
|
while delta < t {
|
|
delta.multiply(by: UInt32(10))
|
|
t.multiply(by: UInt32(10))
|
|
let digit = UInt8(truncatingIfNeeded: t.extractIntegerPart(integerBits))
|
|
unsafe buffer.storeBytes(
|
|
of: 0x30 &+ digit,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
}
|
|
}
|
|
|
|
// Adjust the final digit to be closer to the original value
|
|
// We've already consumed most of our available precision, and only
|
|
// need a couple of integer bits, so we can narrow down to
|
|
// 64 bits here.
|
|
let deltaHigh64 = delta.high._high
|
|
let tHigh64 = t.high._high
|
|
if deltaHigh64 >= tHigh64 &+ (UInt64(1) << high64FractionBits) {
|
|
let skew: UInt64
|
|
if isBoundary {
|
|
skew = deltaHigh64 &- deltaHigh64 / 3 &- tHigh64
|
|
} else {
|
|
skew = deltaHigh64 / 2 &- tHigh64
|
|
}
|
|
let one = UInt64(1) << high64FractionBits
|
|
let fractionMask = one - 1
|
|
let oneHalf = one >> 1
|
|
var lastDigit = unsafe buffer.unsafeLoad(
|
|
fromUncheckedByteOffset: nextDigit &- 1,
|
|
as: UInt8.self)
|
|
if (skew & fractionMask) == oneHalf {
|
|
let adjust = skew >> high64FractionBits
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
lastDigit &= ~1
|
|
} else {
|
|
let adjust = (skew + oneHalf) >> high64FractionBits
|
|
lastDigit &-= UInt8(truncatingIfNeeded: adjust)
|
|
}
|
|
buffer.storeBytes(
|
|
of: lastDigit,
|
|
toByteOffset: nextDigit &- 1,
|
|
as: UInt8.self)
|
|
}
|
|
|
|
return _finishFormatting(
|
|
buffer: &buffer,
|
|
sign: sign,
|
|
firstDigit: firstDigit,
|
|
nextDigit: nextDigit,
|
|
forceExponential: forceExponential,
|
|
base10Exponent: base10Exponent)
|
|
}
|
|
#endif
|
|
|
|
// ================================================================
|
|
//
|
|
// Common Helper functions
|
|
//
|
|
// ================================================================
|
|
|
|
// Code above computes the appropriate significant digits and stores
|
|
// them in `buffer` between `firstDigit` and `nextDigit`.
|
|
// `finishFormatting` converts this into the final text form,
|
|
// inserting decimal points, minus signs, exponents, etc, as
|
|
// necessary. To minimize the work here, this assumes that there are
|
|
// at least 5 unused bytes at the beginning of `buffer` before
|
|
// `firstDigit` and that those bytes are filled with `"0"` (0x30)
|
|
// characters.
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _finishFormatting(
|
|
buffer: inout MutableRawSpan,
|
|
sign: FloatingPointSign,
|
|
firstDigit: Int,
|
|
nextDigit: Int,
|
|
forceExponential: Bool,
|
|
base10Exponent: Int
|
|
) -> Range<Int> {
|
|
// Performance note: This could be made noticeably faster by
|
|
// writing the output consistently in exponential form with no
|
|
// decimal point, e.g., "31415926e-07". But the extra cost seems
|
|
// worthwhile to achieve "3.1415926" instead.
|
|
var firstDigit = firstDigit
|
|
var nextDigit = nextDigit
|
|
|
|
let digitCount = nextDigit &- firstDigit
|
|
if base10Exponent < -4 || forceExponential {
|
|
// Exponential form: "-1.23456789e+123"
|
|
// Rewrite "123456789" => "1.23456789" by moving the first
|
|
// digit to the left one byte and overwriting a period.
|
|
// (This is one reason we left empty space to the left of the digits.)
|
|
// We don't do this for single-digit significands: "1e+78", "5e-324"
|
|
if digitCount > 1 {
|
|
let t = unsafe buffer.unsafeLoad(
|
|
fromUncheckedByteOffset: firstDigit,
|
|
as: UInt8.self)
|
|
unsafe buffer.storeBytes(
|
|
of: 0x2e,
|
|
toUncheckedByteOffset: firstDigit,
|
|
as: UInt8.self)
|
|
firstDigit &-= 1
|
|
unsafe buffer.storeBytes(
|
|
of: t,
|
|
toUncheckedByteOffset: firstDigit,
|
|
as: UInt8.self)
|
|
}
|
|
// Append the exponent:
|
|
unsafe buffer.storeBytes(
|
|
of: 0x65, // "e"
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
var e = base10Exponent
|
|
let expSign: UInt8
|
|
if base10Exponent < 0 {
|
|
expSign = 0x2d // "-"
|
|
e = 0 &- e
|
|
} else {
|
|
expSign = 0x2b // "+"
|
|
}
|
|
unsafe buffer.storeBytes(
|
|
of: expSign,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
if e > 99 {
|
|
if e > 999 {
|
|
let d = asciiDigitTable[e / 100]
|
|
unsafe buffer.storeBytes(
|
|
of: d,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt16.self)
|
|
nextDigit &+= 2
|
|
} else {
|
|
let d = 0x30 &+ UInt8(truncatingIfNeeded: (e / 100))
|
|
unsafe buffer.storeBytes(
|
|
of: d,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt8.self)
|
|
nextDigit &+= 1
|
|
}
|
|
e = e % 100
|
|
}
|
|
let d = unsafe asciiDigitTable[unchecked: e]
|
|
buffer.storeBytes(
|
|
of: d,
|
|
toByteOffset: nextDigit,
|
|
as: UInt16.self)
|
|
nextDigit &+= 2
|
|
} else if base10Exponent < 0 {
|
|
// "-0.000123456789"
|
|
// We need up to 5 leading characters before the digits.
|
|
// Note that the formatters above all insert extra leading "0" characters
|
|
// to the beginning of the buffer, so we don't need to memset() here,
|
|
// just back up the start to include them...
|
|
firstDigit &+= base10Exponent - 1
|
|
// ... and then overwrite a decimal point to get "0." at the beginning
|
|
buffer.storeBytes(
|
|
of: 0x2e, // "."
|
|
toByteOffset: firstDigit &+ 1,
|
|
as: UInt8.self)
|
|
} else if base10Exponent &+ 1 < digitCount {
|
|
// "123456.789"
|
|
// We move the first digits forward one position
|
|
// so we can insert a decimal point in the middle.
|
|
// Note: This is the only case where we actually move
|
|
// more than one digit around in the buffer.
|
|
// TODO: Find out how to use C memmove() here
|
|
firstDigit &-= 1
|
|
for i in 0...(base10Exponent &+ 1) {
|
|
let t = unsafe buffer.unsafeLoad(
|
|
fromUncheckedByteOffset: firstDigit &+ i &+ 1,
|
|
as: UInt8.self)
|
|
unsafe buffer.storeBytes(
|
|
of: t,
|
|
toUncheckedByteOffset: firstDigit &+ i,
|
|
as: UInt8.self)
|
|
}
|
|
buffer.storeBytes(
|
|
of: 0x2e,
|
|
toByteOffset: firstDigit &+ base10Exponent &+ 1,
|
|
as: UInt8.self)
|
|
} else {
|
|
// "12345678900.0"
|
|
// Fill trailing zeros, put ".0" at the end
|
|
// so the result is obviously floating-point.
|
|
let zeroEnd = firstDigit &+ base10Exponent &+ 3
|
|
// TODO: Find out how to use C memset() here:
|
|
// Blast 8 "0" digits into the buffer
|
|
unsafe buffer.storeBytes(
|
|
of: 0x3030303030303030 as UInt64,
|
|
toUncheckedByteOffset: nextDigit,
|
|
as: UInt64.self)
|
|
// Add more "0" digits if needed...
|
|
// (Note: Can't use a standard range loop because nextDigit+8
|
|
// can legitimately be larger than zeroEnd here.)
|
|
var i = nextDigit + 8
|
|
while i < zeroEnd {
|
|
unsafe buffer.storeBytes(
|
|
of: 0x30,
|
|
toUncheckedByteOffset: i,
|
|
as: UInt8.self)
|
|
i &+= 1
|
|
}
|
|
nextDigit = zeroEnd
|
|
buffer.storeBytes(
|
|
of: 0x2e,
|
|
toByteOffset: nextDigit &- 2,
|
|
as: UInt8.self)
|
|
}
|
|
if sign == .minus {
|
|
buffer.storeBytes(
|
|
of: 0x2d, // "-"
|
|
toByteOffset: firstDigit &- 1,
|
|
as: UInt8.self)
|
|
firstDigit &-= 1
|
|
}
|
|
|
|
return unsafe Range(_uncheckedBounds: (lower: firstDigit, upper: nextDigit))
|
|
}
|
|
|
|
// Table with ASCII strings for all 2-digit decimal numbers.
|
|
// Stored as little-endian UInt16s for efficiency
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let asciiDigitTable: InlineArray<100, UInt16> = [
|
|
0x3030, 0x3130, 0x3230, 0x3330, 0x3430,
|
|
0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
|
|
0x3031, 0x3131, 0x3231, 0x3331, 0x3431,
|
|
0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
|
|
0x3032, 0x3132, 0x3232, 0x3332, 0x3432,
|
|
0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
|
|
0x3033, 0x3133, 0x3233, 0x3333, 0x3433,
|
|
0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
|
|
0x3034, 0x3134, 0x3234, 0x3334, 0x3434,
|
|
0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
|
|
0x3035, 0x3135, 0x3235, 0x3335, 0x3435,
|
|
0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
|
|
0x3036, 0x3136, 0x3236, 0x3336, 0x3436,
|
|
0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
|
|
0x3037, 0x3137, 0x3237, 0x3337, 0x3437,
|
|
0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
|
|
0x3038, 0x3138, 0x3238, 0x3338, 0x3438,
|
|
0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
|
|
0x3039, 0x3139, 0x3239, 0x3339, 0x3439,
|
|
0x3539, 0x3639, 0x3739, 0x3839, 0x3939
|
|
]
|
|
|
|
// The constants below assume we're on a little-endian processor
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _infinity(
|
|
buffer: inout MutableRawSpan,
|
|
sign: FloatingPointSign
|
|
) -> Range<Int> {
|
|
if sign == .minus {
|
|
buffer.storeBytes(
|
|
of: 0x666e692d, // "-inf"
|
|
toByteOffset: 0,
|
|
as: UInt32.self)
|
|
return 0..<4
|
|
} else {
|
|
buffer.storeBytes(
|
|
of: 0x00666e69, // "inf\0"
|
|
toByteOffset: 0,
|
|
as: UInt32.self)
|
|
return 0..<3
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _zero(
|
|
buffer: inout MutableRawSpan,
|
|
sign: FloatingPointSign
|
|
) -> Range<Int> {
|
|
if sign == .minus {
|
|
buffer.storeBytes(
|
|
of: 0x302e302d, // "-0.0"
|
|
toByteOffset: 0,
|
|
as: UInt32.self)
|
|
return 0..<4
|
|
} else {
|
|
buffer.storeBytes(
|
|
of: 0x00302e30, // "0.0\0"
|
|
toByteOffset: 0,
|
|
as: UInt32.self)
|
|
return 0..<3
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let hexdigits: InlineArray<16, UInt8> = [
|
|
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
|
0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
|
|
]
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _hexWithoutLeadingZeros(
|
|
buffer: inout MutableRawSpan,
|
|
offset: inout Int,
|
|
value: UInt64
|
|
) {
|
|
var shift = 60
|
|
while (shift > 0) && ((value >> shift) & 0xf == 0) {
|
|
shift -= 4
|
|
}
|
|
while shift >= 0 {
|
|
let d = hexdigits[Int(truncatingIfNeeded: (value >> shift) & 0xf)]
|
|
shift -= 4
|
|
buffer.storeBytes(
|
|
of: d,
|
|
toByteOffset: offset,
|
|
as: UInt8.self)
|
|
offset += 1
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _hexWithLeadingZeros(
|
|
buffer: inout MutableRawSpan,
|
|
offset: inout Int,
|
|
value: UInt64
|
|
) {
|
|
var shift = 60
|
|
while shift >= 0 {
|
|
let d = hexdigits[Int(truncatingIfNeeded: (value >> shift) & 0xf)]
|
|
shift -= 4
|
|
buffer.storeBytes(
|
|
of: d,
|
|
toByteOffset: offset,
|
|
as: UInt8.self)
|
|
offset += 1
|
|
}
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func nan_details(
|
|
buffer: inout MutableRawSpan,
|
|
sign: FloatingPointSign,
|
|
quiet: Bool,
|
|
payloadHigh: UInt64,
|
|
payloadLow: UInt64
|
|
) -> Range<Int> {
|
|
// value is a NaN of some sort
|
|
var i = 0
|
|
if sign == .minus {
|
|
buffer.storeBytes(
|
|
of: 0x2d, // "-"
|
|
toByteOffset: 0,
|
|
as: UInt8.self)
|
|
i = 1
|
|
}
|
|
if !quiet {
|
|
buffer.storeBytes(
|
|
of: 0x73, // "s"
|
|
toByteOffset: i,
|
|
as: UInt8.self)
|
|
i += 1
|
|
}
|
|
buffer.storeBytes(of: 0x6e, toByteOffset: i, as: UInt8.self) // "n"
|
|
buffer.storeBytes(of: 0x61, toByteOffset: i + 1, as: UInt8.self) // "a"
|
|
buffer.storeBytes(of: 0x6e, toByteOffset: i + 2, as: UInt8.self) // "n"
|
|
i += 3
|
|
if payloadHigh != 0 || payloadLow != 0 {
|
|
buffer.storeBytes(of: 0x28, toByteOffset: i, as: UInt8.self) // "("
|
|
i += 1
|
|
buffer.storeBytes(of: 0x30, toByteOffset: i, as: UInt8.self) // "0"
|
|
i += 1
|
|
buffer.storeBytes(of: 0x78, toByteOffset: i, as: UInt8.self) // "x"
|
|
i += 1
|
|
if payloadHigh == 0 {
|
|
_hexWithoutLeadingZeros(buffer: &buffer, offset: &i, value: payloadLow)
|
|
} else {
|
|
_hexWithoutLeadingZeros(buffer: &buffer, offset: &i, value: payloadHigh)
|
|
_hexWithLeadingZeros(buffer: &buffer, offset: &i, value: payloadLow)
|
|
}
|
|
buffer.storeBytes(of: 0x29, toByteOffset: i, as: UInt8.self) // ")"
|
|
i += 1
|
|
}
|
|
return 0..<i
|
|
}
|
|
|
|
// Convert an integer less than 10^8 into exactly 8 ASCII digits in a
|
|
// UInt64. Assuming little-endian, the resulting UInt64 can be stored
|
|
// directly to memory.
|
|
//
|
|
// This implementation is based on work by Paul Khuong:
|
|
// https://pvk.ca/Blog/2017/12/22/appnexus-common-framework-its-out-also-how-to-print-integers-faster/
|
|
@available(SwiftStdlib 6.2, *)
|
|
@inline(__always)
|
|
fileprivate func _intToEightDigits(_ n: UInt32) -> UInt64 {
|
|
// Break into two numbers of 4 decimal digits each
|
|
let div8 = n / 10000
|
|
let mod8 = n &- div8 &* 10000
|
|
let fours = UInt64(div8) | (UInt64(mod8) << 32)
|
|
|
|
// Break into 4 numbers of 2 decimal digits each
|
|
let mask100: UInt64 = 0x0000007f0000007f
|
|
let div4 = ((fours &* 10486) >> 20) & mask100
|
|
let mod4 = fours &- 100 &* div4
|
|
let pairs = div4 | (mod4 &<< 16)
|
|
|
|
// Break into 8 numbers of a single decimal digit each
|
|
let mask10: UInt64 = 0x000f000f000f000f
|
|
let div2 = ((pairs &* 103) >> 10) & mask10
|
|
let mod2 = pairs &- 10 &* div2
|
|
let singles = div2 | (mod2 &<< 8)
|
|
|
|
// Convert 8 digits to ASCII characters
|
|
return singles &+ 0x3030303030303030
|
|
}
|
|
|
|
// ================================================================
|
|
//
|
|
// Arithmetic Helpers
|
|
//
|
|
// The code above works with fixed-point values. Standard
|
|
// addition/subtraction/comparison works fine, but we need rounding
|
|
// control when multiplying such values.
|
|
//
|
|
// For exmaple, `multiply128x64RoundingDown` multiplies a 0.128
|
|
// fixed-point value by a 0.64 fixed-point fraction, returning a 0.128
|
|
// value that's been rounded down from the exact 192-bit result.
|
|
//
|
|
// ================================================================
|
|
|
|
@inline(__always)
|
|
fileprivate func _multiply64x32RoundingDown(
|
|
_ lhs: UInt64,
|
|
_ rhs: UInt32
|
|
) -> UInt64 {
|
|
let mask32 = UInt64(UInt32.max)
|
|
let t = ((lhs & mask32) * UInt64(rhs)) >> 32
|
|
return t + (lhs >> 32) * UInt64(rhs)
|
|
}
|
|
|
|
@inline(__always)
|
|
fileprivate func _multiply64x32RoundingUp(
|
|
_ lhs: UInt64,
|
|
_ rhs: UInt32
|
|
) -> UInt64 {
|
|
let mask32 = UInt64(UInt32.max)
|
|
let t = (((lhs & mask32) * UInt64(rhs)) + mask32) >> 32
|
|
return t + (lhs >> 32) * UInt64(rhs)
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
@inline(__always)
|
|
fileprivate func _multiply128x64RoundingDown(
|
|
_ lhs: UInt128,
|
|
_ rhs: UInt64
|
|
) -> UInt128 {
|
|
let lhsHigh = UInt128(truncatingIfNeeded: lhs._high)
|
|
let lhsLow = UInt128(truncatingIfNeeded: lhs._low)
|
|
let rhs128 = UInt128(truncatingIfNeeded: rhs)
|
|
return (lhsHigh &* rhs128) &+ ((lhsLow &* rhs128) >> 64)
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
@inline(__always)
|
|
fileprivate func _multiply128x64RoundingUp(
|
|
_ lhs: UInt128,
|
|
_ rhs: UInt64
|
|
) -> UInt128 {
|
|
let lhsHigh = UInt128(truncatingIfNeeded: lhs._high)
|
|
let lhsLow = UInt128(truncatingIfNeeded: lhs._low)
|
|
let rhs128 = UInt128(truncatingIfNeeded: rhs)
|
|
let h = lhsHigh &* rhs128
|
|
let l = lhsLow &* rhs128
|
|
let bias = (UInt128(1) << 64) &- 1
|
|
return h + ((l &+ bias) &>> 64)
|
|
}
|
|
|
|
// Custom 256-bit unsigned integer type, with various arithmetic
|
|
// helpers as methods.
|
|
// Used by 80- and 128-bit floating point formatting logic above...
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate struct _UInt256 {
|
|
var high: UInt128
|
|
var low: UInt128
|
|
|
|
init() {
|
|
self.high = 0
|
|
self.low = 0
|
|
}
|
|
|
|
init(high: UInt64, _ midHigh: UInt64, _ midLow: UInt64, low: UInt64) {
|
|
self.high = UInt128(_low: midHigh, _high: high)
|
|
self.low = UInt128(_low: low, _high: midLow)
|
|
}
|
|
|
|
init(high: UInt128, low: UInt128) {
|
|
self.high = high
|
|
self.low = low
|
|
}
|
|
|
|
mutating func shiftRightRoundingDown(by shift: Int) {
|
|
assert(shift < 32 && shift >= 0)
|
|
var t = UInt128(low._low >> shift)
|
|
t |= UInt128(low._high) &<< (64 - shift)
|
|
let newlow = t._low
|
|
t = UInt128(t._high)
|
|
t |= UInt128(high._low) &<< (64 - shift)
|
|
low = UInt128(_low: newlow, _high: t._low)
|
|
t = UInt128(t._high)
|
|
t |= UInt128(high._high) &<< (64 - shift)
|
|
high = t
|
|
}
|
|
|
|
mutating func shiftRightRoundingUp(by shift: Int) {
|
|
assert(shift < 32 && shift >= 0)
|
|
let bias = (UInt64(1) &<< shift) - 1
|
|
var t = UInt128((low._low + bias) >> shift)
|
|
t |= UInt128(low._high) &<< (64 - shift)
|
|
let newlow = t._low
|
|
t = UInt128(t._high)
|
|
t |= UInt128(high._low) &<< (64 - shift)
|
|
low = UInt128(_low: newlow, _high: t._low)
|
|
t = UInt128(t._high)
|
|
t |= UInt128(high._high) &<< (64 - shift)
|
|
high = t
|
|
}
|
|
|
|
mutating func multiply(by rhs: UInt32) {
|
|
var t = UInt128(low._low) &* UInt128(rhs)
|
|
let newlow = t._low
|
|
t = UInt128(t._high) &+ UInt128(low._high) &* UInt128(rhs)
|
|
low = UInt128(_low: newlow, _high: t._low)
|
|
t = UInt128(t._high) &+ UInt128(high._low) &* UInt128(rhs)
|
|
let newmidhigh = t._low
|
|
t = UInt128(t._high) &+ UInt128(high._high) &* UInt128(rhs)
|
|
high = UInt128(_low: newmidhigh, _high: t._low)
|
|
assert(t._high == 0)
|
|
}
|
|
|
|
mutating func multiplyRoundingDown(by rhs: UInt128) {
|
|
var current = UInt128(low._low) * UInt128(rhs._low)
|
|
|
|
current = UInt128(current._high)
|
|
var t = UInt128(low._low) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
var next = UInt128(t._high)
|
|
t = UInt128(low._high) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(low._high) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
next = UInt128(t._high)
|
|
t = UInt128(high._low) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
let newlow = current._low
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(high._low) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
next = UInt128(t._high)
|
|
t = UInt128(high._high) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
low = UInt128(_low: newlow, _high: current._low)
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(high._high) &* UInt128(rhs._high)
|
|
high = current + t
|
|
}
|
|
|
|
mutating func multiplyRoundingUp(by rhs: UInt128) {
|
|
var current = UInt128(low._low) &* UInt128(rhs._low)
|
|
current += UInt128(UInt64.max)
|
|
|
|
current = UInt128(current._high)
|
|
var t = UInt128(low._low) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
var next = UInt128(t._high)
|
|
t = UInt128(low._high) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
current += UInt128(UInt64.max)
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(low._high) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
next = UInt128(t._high)
|
|
t = UInt128(high._low) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
let newlow = current._low
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(high._low) &* UInt128(rhs._high)
|
|
current += UInt128(t._low)
|
|
next = UInt128(t._high)
|
|
t = UInt128(high._high) &* UInt128(rhs._low)
|
|
current += UInt128(t._low)
|
|
next += UInt128(t._high)
|
|
low = UInt128(_low: newlow, _high: current._low)
|
|
|
|
current = next + UInt128(current._high)
|
|
t = UInt128(high._high) &* UInt128(rhs._high)
|
|
high = current + t
|
|
}
|
|
|
|
mutating func extractIntegerPart(_ bits: Int) -> UInt {
|
|
assert(bits < 16)
|
|
let integral = high._high >> (64 &- bits)
|
|
high = UInt128(
|
|
_low: high._low,
|
|
_high: high._high &- (integral &<< (64 &- bits)))
|
|
return UInt(truncatingIfNeeded: integral)
|
|
}
|
|
|
|
static func &- (lhs: _UInt256, rhs: _UInt256) -> _UInt256 {
|
|
var t = UInt128(lhs.low._low) &+ UInt128(~rhs.low._low) &+ 1
|
|
let newlowlow = t._low
|
|
t = UInt128(t._high) &+ UInt128(lhs.low._high) &+ UInt128(~rhs.low._high)
|
|
let newlow = UInt128(_low: newlowlow, _high: t._low)
|
|
t = UInt128(t._high) &+ UInt128(lhs.high._low) &+ UInt128(~rhs.high._low)
|
|
let newhigh = UInt128(
|
|
_low: t._low,
|
|
_high: t._high &+ lhs.high._high &+ ~rhs.high._high)
|
|
return _UInt256(high: newhigh, low: newlow)
|
|
}
|
|
|
|
static func < (lhs: _UInt256, rhs: _UInt256) -> Bool {
|
|
return (lhs.high < rhs.high)
|
|
|| (lhs.high == rhs.high
|
|
&& lhs.low < rhs.low)
|
|
}
|
|
}
|
|
|
|
// ================================================================
|
|
//
|
|
// Powers of 10
|
|
//
|
|
// ================================================================
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
@inline(__always)
|
|
fileprivate func _intervalContainingPowerOf10_Binary32(
|
|
p: Int,
|
|
lower: inout UInt64,
|
|
upper: inout UInt64
|
|
) -> Int {
|
|
if p >= 0 {
|
|
let base = powersOf10_Exact128[p &* 2 &+ 1]
|
|
lower = base
|
|
if p < 28 {
|
|
upper = base
|
|
} else {
|
|
upper = base &+ 1
|
|
}
|
|
} else {
|
|
let base = powersOf10_negativeBinary32[p &+ 40]
|
|
lower = base
|
|
upper = base &+ 1
|
|
}
|
|
return binaryExponentFor10ToThe(p)
|
|
}
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
@inline(__always)
|
|
fileprivate func _intervalContainingPowerOf10_Binary64(
|
|
p: Int,
|
|
lower: inout UInt128,
|
|
upper: inout UInt128
|
|
) -> Int {
|
|
if p >= 0 && p <= 55 {
|
|
let upper64 = powersOf10_Exact128[p &* 2 &+ 1]
|
|
let lower64 = powersOf10_Exact128[p &* 2]
|
|
upper = UInt128(_low: lower64, _high: upper64)
|
|
lower = upper
|
|
return binaryExponentFor10ToThe(p)
|
|
}
|
|
|
|
let index = p &+ 400
|
|
let mainPower = index / 28
|
|
let baseHigh = powersOf10_Binary64[mainPower &* 2 &+ 1]
|
|
let baseLow = powersOf10_Binary64[mainPower &* 2]
|
|
let extraPower = index &- mainPower &* 28
|
|
let baseExponent = binaryExponentFor10ToThe(p &- extraPower)
|
|
|
|
if extraPower == 0 {
|
|
lower = UInt128(_low: baseLow, _high: baseHigh)
|
|
upper = lower &+ 1
|
|
return baseExponent
|
|
} else {
|
|
let extra = powersOf10_Exact128[extraPower &* 2 &+ 1]
|
|
lower = ((UInt128(truncatingIfNeeded:baseHigh)
|
|
&* UInt128(truncatingIfNeeded:extra))
|
|
&+ ((UInt128(truncatingIfNeeded:baseLow)
|
|
&* UInt128(truncatingIfNeeded:extra)) &>> 64))
|
|
upper = lower &+ 2
|
|
return baseExponent &+ binaryExponentFor10ToThe(extraPower)
|
|
}
|
|
}
|
|
|
|
@inline(__always)
|
|
fileprivate func binaryExponentFor10ToThe(_ p: Int) -> Int {
|
|
return Int(((Int64(p) &* 55732705) >> 24) &+ 1)
|
|
}
|
|
|
|
@inline(__always)
|
|
fileprivate func decimalExponentFor2ToThe(_ p: Int) -> Int {
|
|
return Int((Int64(p) &* 20201781) >> 26)
|
|
}
|
|
|
|
// Each of the constant values here have an implicit binary point at
|
|
// the extreme left and when not exact, are rounded _down_ from the
|
|
// exact values. For example, the first row of the first table says
|
|
// that:
|
|
//
|
|
// 0x0.8b61313bbabce2c6 x 2^-132
|
|
//
|
|
// is the result of rounding down the exact binary value of 10^-40 to
|
|
// 64 significant bits. The logic above uses these tables to compute
|
|
// bounds for the exact value of the power of 10.
|
|
|
|
// Note the binary exponent is not stored; it is computed by the
|
|
// `binaryExponentFor10ToThe(p)` function.
|
|
|
|
// This covers the negative powers of 10 for Float32.
|
|
// Positive powers of 10 come from the next table below.
|
|
// Table size: 320 bytes
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let powersOf10_negativeBinary32: InlineArray<_, UInt64> = [
|
|
0x8b61313bbabce2c6, // x 2^-132 ~= 10^-40
|
|
0xae397d8aa96c1b77, // x 2^-129 ~= 10^-39
|
|
0xd9c7dced53c72255, // x 2^-126 ~= 10^-38
|
|
0x881cea14545c7575, // x 2^-122 ~= 10^-37
|
|
0xaa242499697392d2, // x 2^-119 ~= 10^-36
|
|
0xd4ad2dbfc3d07787, // x 2^-116 ~= 10^-35
|
|
0x84ec3c97da624ab4, // x 2^-112 ~= 10^-34
|
|
0xa6274bbdd0fadd61, // x 2^-109 ~= 10^-33
|
|
0xcfb11ead453994ba, // x 2^-106 ~= 10^-32
|
|
0x81ceb32c4b43fcf4, // x 2^-102 ~= 10^-31
|
|
0xa2425ff75e14fc31, // x 2^-99 ~= 10^-30
|
|
0xcad2f7f5359a3b3e, // x 2^-96 ~= 10^-29
|
|
0xfd87b5f28300ca0d, // x 2^-93 ~= 10^-28
|
|
0x9e74d1b791e07e48, // x 2^-89 ~= 10^-27
|
|
0xc612062576589dda, // x 2^-86 ~= 10^-26
|
|
0xf79687aed3eec551, // x 2^-83 ~= 10^-25
|
|
0x9abe14cd44753b52, // x 2^-79 ~= 10^-24
|
|
0xc16d9a0095928a27, // x 2^-76 ~= 10^-23
|
|
0xf1c90080baf72cb1, // x 2^-73 ~= 10^-22
|
|
0x971da05074da7bee, // x 2^-69 ~= 10^-21
|
|
0xbce5086492111aea, // x 2^-66 ~= 10^-20
|
|
0xec1e4a7db69561a5, // x 2^-63 ~= 10^-19
|
|
0x9392ee8e921d5d07, // x 2^-59 ~= 10^-18
|
|
0xb877aa3236a4b449, // x 2^-56 ~= 10^-17
|
|
0xe69594bec44de15b, // x 2^-53 ~= 10^-16
|
|
0x901d7cf73ab0acd9, // x 2^-49 ~= 10^-15
|
|
0xb424dc35095cd80f, // x 2^-46 ~= 10^-14
|
|
0xe12e13424bb40e13, // x 2^-43 ~= 10^-13
|
|
0x8cbccc096f5088cb, // x 2^-39 ~= 10^-12
|
|
0xafebff0bcb24aafe, // x 2^-36 ~= 10^-11
|
|
0xdbe6fecebdedd5be, // x 2^-33 ~= 10^-10
|
|
0x89705f4136b4a597, // x 2^-29 ~= 10^-9
|
|
0xabcc77118461cefc, // x 2^-26 ~= 10^-8
|
|
0xd6bf94d5e57a42bc, // x 2^-23 ~= 10^-7
|
|
0x8637bd05af6c69b5, // x 2^-19 ~= 10^-6
|
|
0xa7c5ac471b478423, // x 2^-16 ~= 10^-5
|
|
0xd1b71758e219652b, // x 2^-13 ~= 10^-4
|
|
0x83126e978d4fdf3b, // x 2^-9 ~= 10^-3
|
|
0xa3d70a3d70a3d70a, // x 2^-6 ~= 10^-2
|
|
0xcccccccccccccccc, // x 2^-3 ~= 10^-1
|
|
]
|
|
|
|
// All the powers of 10 that can be represented exactly
|
|
// in 128 bits, represented as binary floating-point values
|
|
// using the same convention as in the previous table, only
|
|
// with 128 bit significands.
|
|
|
|
// This table is used in four places:
|
|
// * The high order 64 bits are used for positive powers of 10
|
|
// when converting Float32.
|
|
// * The full 128-bit value is used for 10^0 through 10^55 for Float64.
|
|
// * The first 28 entries are combined with the next table for
|
|
// all other Float64 values.
|
|
// * This is combined with the 256-bit table below for Float80/Float128
|
|
// support.
|
|
|
|
// Table size: 896 bytes
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let powersOf10_Exact128: InlineArray<_, UInt64> = [
|
|
// Low order ... high order
|
|
0x0000000000000000, 0x8000000000000000, // x 2^1 == 10^0 exactly
|
|
0x0000000000000000, 0xa000000000000000, // x 2^4 == 10^1 exactly
|
|
0x0000000000000000, 0xc800000000000000, // x 2^7 == 10^2 exactly
|
|
0x0000000000000000, 0xfa00000000000000, // x 2^10 == 10^3 exactly
|
|
0x0000000000000000, 0x9c40000000000000, // x 2^14 == 10^4 exactly
|
|
0x0000000000000000, 0xc350000000000000, // x 2^17 == 10^5 exactly
|
|
0x0000000000000000, 0xf424000000000000, // x 2^20 == 10^6 exactly
|
|
0x0000000000000000, 0x9896800000000000, // x 2^24 == 10^7 exactly
|
|
0x0000000000000000, 0xbebc200000000000, // x 2^27 == 10^8 exactly
|
|
0x0000000000000000, 0xee6b280000000000, // x 2^30 == 10^9 exactly
|
|
0x0000000000000000, 0x9502f90000000000, // x 2^34 == 10^10 exactly
|
|
0x0000000000000000, 0xba43b74000000000, // x 2^37 == 10^11 exactly
|
|
0x0000000000000000, 0xe8d4a51000000000, // x 2^40 == 10^12 exactly
|
|
0x0000000000000000, 0x9184e72a00000000, // x 2^44 == 10^13 exactly
|
|
0x0000000000000000, 0xb5e620f480000000, // x 2^47 == 10^14 exactly
|
|
0x0000000000000000, 0xe35fa931a0000000, // x 2^50 == 10^15 exactly
|
|
0x0000000000000000, 0x8e1bc9bf04000000, // x 2^54 == 10^16 exactly
|
|
0x0000000000000000, 0xb1a2bc2ec5000000, // x 2^57 == 10^17 exactly
|
|
0x0000000000000000, 0xde0b6b3a76400000, // x 2^60 == 10^18 exactly
|
|
0x0000000000000000, 0x8ac7230489e80000, // x 2^64 == 10^19 exactly
|
|
0x0000000000000000, 0xad78ebc5ac620000, // x 2^67 == 10^20 exactly
|
|
0x0000000000000000, 0xd8d726b7177a8000, // x 2^70 == 10^21 exactly
|
|
0x0000000000000000, 0x878678326eac9000, // x 2^74 == 10^22 exactly
|
|
0x0000000000000000, 0xa968163f0a57b400, // x 2^77 == 10^23 exactly
|
|
0x0000000000000000, 0xd3c21bcecceda100, // x 2^80 == 10^24 exactly
|
|
0x0000000000000000, 0x84595161401484a0, // x 2^84 == 10^25 exactly
|
|
0x0000000000000000, 0xa56fa5b99019a5c8, // x 2^87 == 10^26 exactly
|
|
0x0000000000000000, 0xcecb8f27f4200f3a, // x 2^90 == 10^27 exactly
|
|
0x4000000000000000, 0x813f3978f8940984, // x 2^94 == 10^28 exactly
|
|
0x5000000000000000, 0xa18f07d736b90be5, // x 2^97 == 10^29 exactly
|
|
0xa400000000000000, 0xc9f2c9cd04674ede, // x 2^100 == 10^30 exactly
|
|
0x4d00000000000000, 0xfc6f7c4045812296, // x 2^103 == 10^31 exactly
|
|
0xf020000000000000, 0x9dc5ada82b70b59d, // x 2^107 == 10^32 exactly
|
|
0x6c28000000000000, 0xc5371912364ce305, // x 2^110 == 10^33 exactly
|
|
0xc732000000000000, 0xf684df56c3e01bc6, // x 2^113 == 10^34 exactly
|
|
0x3c7f400000000000, 0x9a130b963a6c115c, // x 2^117 == 10^35 exactly
|
|
0x4b9f100000000000, 0xc097ce7bc90715b3, // x 2^120 == 10^36 exactly
|
|
0x1e86d40000000000, 0xf0bdc21abb48db20, // x 2^123 == 10^37 exactly
|
|
0x1314448000000000, 0x96769950b50d88f4, // x 2^127 == 10^38 exactly
|
|
0x17d955a000000000, 0xbc143fa4e250eb31, // x 2^130 == 10^39 exactly
|
|
0x5dcfab0800000000, 0xeb194f8e1ae525fd, // x 2^133 == 10^40 exactly
|
|
0x5aa1cae500000000, 0x92efd1b8d0cf37be, // x 2^137 == 10^41 exactly
|
|
0xf14a3d9e40000000, 0xb7abc627050305ad, // x 2^140 == 10^42 exactly
|
|
0x6d9ccd05d0000000, 0xe596b7b0c643c719, // x 2^143 == 10^43 exactly
|
|
0xe4820023a2000000, 0x8f7e32ce7bea5c6f, // x 2^147 == 10^44 exactly
|
|
0xdda2802c8a800000, 0xb35dbf821ae4f38b, // x 2^150 == 10^45 exactly
|
|
0xd50b2037ad200000, 0xe0352f62a19e306e, // x 2^153 == 10^46 exactly
|
|
0x4526f422cc340000, 0x8c213d9da502de45, // x 2^157 == 10^47 exactly
|
|
0x9670b12b7f410000, 0xaf298d050e4395d6, // x 2^160 == 10^48 exactly
|
|
0x3c0cdd765f114000, 0xdaf3f04651d47b4c, // x 2^163 == 10^49 exactly
|
|
0xa5880a69fb6ac800, 0x88d8762bf324cd0f, // x 2^167 == 10^50 exactly
|
|
0x8eea0d047a457a00, 0xab0e93b6efee0053, // x 2^170 == 10^51 exactly
|
|
0x72a4904598d6d880, 0xd5d238a4abe98068, // x 2^173 == 10^52 exactly
|
|
0x47a6da2b7f864750, 0x85a36366eb71f041, // x 2^177 == 10^53 exactly
|
|
0x999090b65f67d924, 0xa70c3c40a64e6c51, // x 2^180 == 10^54 exactly
|
|
0xfff4b4e3f741cf6d, 0xd0cf4b50cfe20765, // x 2^183 == 10^55 exactly
|
|
]
|
|
|
|
// Every 28th power of 10 across the full range of Double.
|
|
// Combined with a 64-bit exact power of 10 from the previous
|
|
// table, this lets us reconstruct a 128-bit lower bound for
|
|
// any power of 10 across the full range of double with a single
|
|
// 64-bit by 128-bit multiplication.
|
|
|
|
// The published algorithms generally use a full table here of
|
|
// 800 128-bit values (6400 bytes). Breaking it into two tables
|
|
// gives a significant code-size savings for a modest performance
|
|
// penalty.
|
|
|
|
// Table size: 464 bytes
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let powersOf10_Binary64: InlineArray<_, UInt64> = [
|
|
// low-order half, high-order half
|
|
0x3931b850df08e738, 0x95fe7e07c91efafa, // x 2^-1328 ~= 10^-400
|
|
0xba954f8e758fecb3, 0x9774919ef68662a3, // x 2^-1235 ~= 10^-372
|
|
0x9028bed2939a635c, 0x98ee4a22ecf3188b, // x 2^-1142 ~= 10^-344
|
|
0x47b233c92125366e, 0x9a6bb0aa55653b2d, // x 2^-1049 ~= 10^-316
|
|
0x4ee367f9430aec32, 0x9becce62836ac577, // x 2^-956 ~= 10^-288
|
|
0x6f773fc3603db4a9, 0x9d71ac8fada6c9b5, // x 2^-863 ~= 10^-260
|
|
0xc47bc5014a1a6daf, 0x9efa548d26e5a6e1, // x 2^-770 ~= 10^-232
|
|
0x80e8a40eccd228a4, 0xa086cfcd97bf97f3, // x 2^-677 ~= 10^-204
|
|
0xb8ada00e5a506a7c, 0xa21727db38cb002f, // x 2^-584 ~= 10^-176
|
|
0xc13e60d0d2e0ebba, 0xa3ab66580d5fdaf5, // x 2^-491 ~= 10^-148
|
|
0xc2974eb4ee658828, 0xa54394fe1eedb8fe, // x 2^-398 ~= 10^-120
|
|
0xcb4ccd500f6bb952, 0xa6dfbd9fb8e5b88e, // x 2^-305 ~= 10^-92
|
|
0x3f2398d747b36224, 0xa87fea27a539e9a5, // x 2^-212 ~= 10^-64
|
|
0xdde50bd1d5d0b9e9, 0xaa242499697392d2, // x 2^-119 ~= 10^-36
|
|
0xfdc20d2b36ba7c3d, 0xabcc77118461cefc, // x 2^-26 ~= 10^-8
|
|
0x0000000000000000, 0xad78ebc5ac620000, // x 2^67 == 10^20 exactly
|
|
0x9670b12b7f410000, 0xaf298d050e4395d6, // x 2^160 == 10^48 exactly
|
|
0x3b25a55f43294bcb, 0xb0de65388cc8ada8, // x 2^253 ~= 10^76
|
|
0x58edec91ec2cb657, 0xb2977ee300c50fe7, // x 2^346 ~= 10^104
|
|
0x29babe4598c311fb, 0xb454e4a179dd1877, // x 2^439 ~= 10^132
|
|
0x577b986b314d6009, 0xb616a12b7fe617aa, // x 2^532 ~= 10^160
|
|
0x0c11ed6d538aeb2f, 0xb7dcbf5354e9bece, // x 2^625 ~= 10^188
|
|
0x6d953e2bd7173692, 0xb9a74a0637ce2ee1, // x 2^718 ~= 10^216
|
|
0x9d6d1ad41abe37f1, 0xbb764c4ca7a4440f, // x 2^811 ~= 10^244
|
|
0x4b2d8644d8a74e18, 0xbd49d14aa79dbc82, // x 2^904 ~= 10^272
|
|
0xe0470a63e6bd56c3, 0xbf21e44003acdd2c, // x 2^997 ~= 10^300
|
|
0x505f522e53053ff2, 0xc0fe908895cf3b44, // x 2^1090 ~= 10^328
|
|
0xcca845ab2beafa9a, 0xc2dfe19c8c055535, // x 2^1183 ~= 10^356
|
|
0x1027fff56784f444, 0xc4c5e310aef8aa17, // x 2^1276 ~= 10^384
|
|
]
|
|
|
|
// Needed by 80- and 128-bit formatters above
|
|
|
|
// We could cut this in half by keeping only the positive powers and doing
|
|
// a single additional 256-bit multiplication by 10^-4984 to recover the negative powers.
|
|
|
|
// Table size: 5728 bytes
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate let powersOf10_Binary128: InlineArray<_, UInt64> = [
|
|
// Low-order ... high-order
|
|
0xaec2e6aff96b46ae, 0xf91044c2eff84750, 0x2b55c9e70e00c557, 0xb6536903bf8f2bda, // x 2^-16556 ~= 10^-4984
|
|
0xda1b3c3dd3889587, 0x73a7380aba84a6b1, 0xbddb2dfde3f8a6e3, 0xb9e5428330737362, // x 2^-16370 ~= 10^-4928
|
|
0xa2d23c57cfebb9ec, 0x9f165c039ead6d77, 0x88227fdfc13ab53d, 0xbd89006346a9a34d, // x 2^-16184 ~= 10^-4872
|
|
0x0333d510cf27e5a5, 0x4e3cc383eaa17b7b, 0xe05fe4207ca3d508, 0xc13efc51ade7df64, // x 2^-15998 ~= 10^-4816
|
|
0xff242c569bc1f539, 0x5c67ba58680c4cce, 0x3c55f3f947fef0e9, 0xc50791bd8dd72edb, // x 2^-15812 ~= 10^-4760
|
|
0xe4b75ae27bec50bf, 0x25b0419765fdfcdb, 0x0915564d8ab057ee, 0xc8e31de056f89c19, // x 2^-15626 ~= 10^-4704
|
|
0x548b1e80a94f3434, 0xe418e9217ce83755, 0x801e38463183fc88, 0xccd1ffc6bba63e21, // x 2^-15440 ~= 10^-4648
|
|
0x541950a0fdc2b4d9, 0xeea173da1f0eb7b4, 0xcfadf6b2aa7c4f43, 0xd0d49859d60d40a3, // x 2^-15254 ~= 10^-4592
|
|
0x7e64501be95ad76b, 0x451e855d8acef835, 0x9e601e707a2c3488, 0xd4eb4a687c0253e8, // x 2^-15068 ~= 10^-4536
|
|
0xdadd9645f360cb51, 0xf290163350ecb3eb, 0xa8edffdccfe4db4b, 0xd9167ab0c1965798, // x 2^-14882 ~= 10^-4480
|
|
0x7e447db3018ffbdf, 0x4fa1860c08a85923, 0xb17cd86e7fcece75, 0xdd568fe9ab559344, // x 2^-14696 ~= 10^-4424
|
|
0x61cd4655bf64d265, 0xb19fd88fe285b3bc, 0x1151250681d59705, 0xe1abf2cd11206610, // x 2^-14510 ~= 10^-4368
|
|
0xa5703f5ce7a619ec, 0x361243a84b55574d, 0x025a8e1e5dbb41d6, 0xe6170e21b2910457, // x 2^-14324 ~= 10^-4312
|
|
0xb93897a6cf5d3e61, 0x18746fcc6a190db9, 0x66e849253e5da0c2, 0xea984ec57de69f13, // x 2^-14138 ~= 10^-4256
|
|
0x309043d12ab5b0ac, 0x79c93cff11f09319, 0xf5a7800f23ef67b8, 0xef3023b80a732d93, // x 2^-13952 ~= 10^-4200
|
|
0xa3baa84c049b52b9, 0xbec466ee1b586342, 0x0e85fc7f4edbd3ca, 0xf3defe25478e074a, // x 2^-13766 ~= 10^-4144
|
|
0xd1f4628316b15c7a, 0xae16192410d3135e, 0x4268a54f70bd28c4, 0xf8a551706112897c, // x 2^-13580 ~= 10^-4088
|
|
0x9eb9296cc5749dba, 0x48324e275376dfdd, 0x5052e9289f0f2333, 0xfd83933eda772c0b, // x 2^-13394 ~= 10^-4032
|
|
0xff6aae669a5a0d8a, 0x24fed95087b9006e, 0x01b02378a405b421, 0x813d1dc1f0c754d6, // x 2^-13207 ~= 10^-3976
|
|
0xf993f18de00dc89b, 0x15617da021b89f92, 0xb782db1fc6aba49b, 0x83c4e245ed051dc1, // x 2^-13021 ~= 10^-3920
|
|
0xc6a0d64a712172b1, 0x2217669197ac1504, 0x4250be2eeba87d15, 0x86595584116caf3c, // x 2^-12835 ~= 10^-3864
|
|
0x0bdc0c67a220687b, 0x44a66a6d6fd6537b, 0x3f1f93f1943ca9b6, 0x88fab70d8b44952a, // x 2^-12649 ~= 10^-3808
|
|
0xb60b57164ad28122, 0xde5bd4572c25a830, 0x2c87f18b39478aa2, 0x8ba947b223e5783e, // x 2^-12463 ~= 10^-3752
|
|
0xbd59568efdb9bfee, 0x292f8f2c98d7f44c, 0x4054f5360249ebd1, 0x8e6549867da7d11a, // x 2^-12277 ~= 10^-3696
|
|
0x9fa0721e66791acc, 0x1789061d717d454c, 0xc1187fa0c18adbbe, 0x912effea7015b2c5, // x 2^-12091 ~= 10^-3640
|
|
0x982b64e953ac4e27, 0x45efb05f20cf48b3, 0x4b4de34e0ebc3e06, 0x9406af8f83fd6265, // x 2^-11905 ~= 10^-3584
|
|
0xa53f5950eec21dca, 0x3bd8754763bdbca1, 0xac73f0226eff5ea1, 0x96ec9e7f9004839b, // x 2^-11719 ~= 10^-3528
|
|
0x320e19f88f1161b7, 0x72e93fe0cce7cfd9, 0x2184706ea46a4c38, 0x99e11423765ec1d0, // x 2^-11533 ~= 10^-3472
|
|
0x491aba48dfc0e36e, 0xd3de560ee34022b2, 0xddadb80577b906bd, 0x9ce4594a044e0f1b, // x 2^-11347 ~= 10^-3416
|
|
0x06789d038697142f, 0x7a466a75be73db21, 0x60dbd8aa443b560f, 0x9ff6b82ef415d222, // x 2^-11161 ~= 10^-3360
|
|
0x40ed8056af76ac43, 0x08251c601e346456, 0x7401c6f091f87727, 0xa3187c82120dace6, // x 2^-10975 ~= 10^-3304
|
|
0x8c643ee307bffec6, 0xf369a11c6f66c05a, 0x4d5b32f713d7f476, 0xa649f36e8583e81a, // x 2^-10789 ~= 10^-3248
|
|
0xe32f5e080e36b4be, 0x3adf30ff2eb163d4, 0xb4b39dd9ddb8d317, 0xa98b6ba23e2300c7, // x 2^-10603 ~= 10^-3192
|
|
0x6b9d538c192cfb1b, 0x1c5af3bd4d2c60b5, 0xec41c1793d69d0d1, 0xacdd3555869159d1, // x 2^-10417 ~= 10^-3136
|
|
0x1adadaeedf7d699c, 0x71043692494aa743, 0x3ca5a7540d9d56c9, 0xb03fa252bd05a815, // x 2^-10231 ~= 10^-3080
|
|
0xec3e4e5fc6b03617, 0x47c9b16afe8fdf74, 0x92e1bc1fbb33f18d, 0xb3b305fe328e571f, // x 2^-10045 ~= 10^-3024
|
|
0x1d42fa68b12bdb23, 0xac46a7b3f2b4b34e, 0xa908fd4a88728b6a, 0xb737b55e31cdde04, // x 2^-9859 ~= 10^-2968
|
|
0x887dede507f2b618, 0x359a8fa0d014b9a7, 0x7c4c65d15c614c56, 0xbace07232df1c802, // x 2^-9673 ~= 10^-2912
|
|
0x504708e718b4b669, 0xfb4d9440822af452, 0xef84cc99cb4c5d17, 0xbe7653b01aae13e5, // x 2^-9487 ~= 10^-2856
|
|
0x5b7977525516bff0, 0x75913092420c9b35, 0xcfc147ade4843a24, 0xc230f522ee0a7fc2, // x 2^-9301 ~= 10^-2800
|
|
0xad5d11883cc1302b, 0x860a754894b9a0bc, 0x4668677d5f46c29b, 0xc5fe475d4cd35cff, // x 2^-9115 ~= 10^-2744
|
|
0x42032f9f971bfc07, 0x9fb576046ab35018, 0x474b3cb1fe1d6a7f, 0xc9dea80d6283a34c, // x 2^-8929 ~= 10^-2688
|
|
0xd3e7fbb72403a4dd, 0x8ca223055819af54, 0xd6ea3b733029ef0b, 0xcdd276b6e582284f, // x 2^-8743 ~= 10^-2632
|
|
0xba2431d885f2b7d9, 0xc9879fc42869f610, 0x3736730a9e47fef8, 0xd1da14bc489025ea, // x 2^-8557 ~= 10^-2576
|
|
0xa11edbcd65dd1844, 0xcb8edae81a295887, 0x3d24e68dc1027246, 0xd5f5e5681a4b9285, // x 2^-8371 ~= 10^-2520
|
|
0xa0f076652f69ad08, 0x9d19c341f5f42f2a, 0x742ab8f3864562c8, 0xda264df693ac3e30, // x 2^-8185 ~= 10^-2464
|
|
0x29f760ef115f2824, 0xe0ee47c041c9de0f, 0x8c119f3680212413, 0xde6bb59f56672cda, // x 2^-7999 ~= 10^-2408
|
|
0x8b90230b3409c9d3, 0x9d76eef2c1543e65, 0x43190b523f872b9c, 0xe2c6859f5c284230, // x 2^-7813 ~= 10^-2352
|
|
0xd44ce9993bc6611e, 0x777c9b2dfbede079, 0x2a0969bf88679396, 0xe7372943179706fc, // x 2^-7627 ~= 10^-2296
|
|
0xe8c5f5a63fd0fbd1, 0x0ccc12293f1d7a58, 0x131565be33dda91a, 0xebbe0df0c8201ac5, // x 2^-7441 ~= 10^-2240
|
|
0xdb97988dd6b776f4, 0xeb2106f435f7e1d5, 0xccfb1cc2ef1f44de, 0xf05ba3330181c750, // x 2^-7255 ~= 10^-2184
|
|
0x2fcbc8df94a1d54b, 0x796d0a8120801513, 0x5f8385b3a882ff4c, 0xf5105ac3681f2716, // x 2^-7069 ~= 10^-2128
|
|
0xc8700c11071a40f5, 0x23cb9e9df9331fe4, 0x166c15f456786c27, 0xf9dca895a3226409, // x 2^-6883 ~= 10^-2072
|
|
0x9589f4637a50cbb5, 0xea8242b0030e4a51, 0x6c656c3b1f2c9d91, 0xfec102e2857bc1f9, // x 2^-6697 ~= 10^-2016
|
|
0xc4be56c83349136c, 0x6188db81ac8e775d, 0xfa70b9a2ca60b004, 0x81def119b76837c8, // x 2^-6510 ~= 10^-1960
|
|
0xb85d39054658b363, 0xe7df06bc613fda21, 0x6a22490e8e9ec98b, 0x8469e0b6f2b8bd9b, // x 2^-6324 ~= 10^-1904
|
|
0x800b1e1349fef248, 0x469cfd2e6ca32a77, 0x69138459b0fa72d4, 0x87018eefb53c6325, // x 2^-6138 ~= 10^-1848
|
|
0xb62593291c768919, 0xc098e6ed0bfbd6f6, 0x6c83ad1260ff20f4, 0x89a63ba4c497b50e, // x 2^-5952 ~= 10^-1792
|
|
0x92ee7fce474479d3, 0xe02017175bf040c6, 0xd82ef2860273de8d, 0x8c5827f711735b46, // x 2^-5766 ~= 10^-1736
|
|
0x7b0e6375ca8c77d9, 0x5f07e1e10097d47f, 0x416d7f9ab1e67580, 0x8f17964dfc3961f2, // x 2^-5580 ~= 10^-1680
|
|
0xc8d869ed561af1ce, 0x8b6648e941de779b, 0x56700866b85d57fe, 0x91e4ca5db93dbfec, // x 2^-5394 ~= 10^-1624
|
|
0xfc04df783488a410, 0x64d1f15da2c146b1, 0x43cf71d5c4fd7868, 0x94c0092dd4ef9511, // x 2^-5208 ~= 10^-1568
|
|
0xfbaf03b48a965a64, 0x9b6122aa2b72a13c, 0x387898a6e22f821b, 0x97a9991fd8b3afc0, // x 2^-5022 ~= 10^-1512
|
|
0x50f7f7c13119aadd, 0xe415d8b25694250a, 0x8f8857e875e7774e, 0x9aa1c1f6110c0dd0, // x 2^-4836 ~= 10^-1456
|
|
0xce214403545fd685, 0xf36d1ad779b90e09, 0xa5c58d5f91a476d7, 0x9da8ccda75b341b5, // x 2^-4650 ~= 10^-1400
|
|
0x63ddfb68f971b0c5, 0x2822e38faf74b26e, 0x6e1f7f1642ebaac8, 0xa0bf0465b455e921, // x 2^-4464 ~= 10^-1344
|
|
0xf0d00cec9daf7444, 0x6bf3eea6f661a32a, 0xfad2be1679765f27, 0xa3e4b4a65e97b76a, // x 2^-4278 ~= 10^-1288
|
|
0x463b4ab4bd478f57, 0x6f6583b5b36d5426, 0x800cfab80c4e2eb1, 0xa71a2b283c14fba6, // x 2^-4092 ~= 10^-1232
|
|
0xef163df2fa96e983, 0xa825f32bc8f6b080, 0x850b0c5976b21027, 0xaa5fb6fbc115010b, // x 2^-3906 ~= 10^-1176
|
|
0x7db1b3f8e100eb43, 0x2862b1f61d64ddc3, 0x61363686961a41e5, 0xadb5a8bdaaa53051, // x 2^-3720 ~= 10^-1120
|
|
0xfd349cf00ba1e09a, 0x6d282fe1b7112879, 0xc6f075c4b81fc72d, 0xb11c529ec0d87268, // x 2^-3534 ~= 10^-1064
|
|
0xf7221741b221cf6f, 0x3739f15b06ac3c76, 0xb4e4be5b6455ef96, 0xb494086bbfea00c3, // x 2^-3348 ~= 10^-1008
|
|
0xc4e5a2f864c403bb, 0x6e33cdcda4367276, 0x24d256c540a50309, 0xb81d1f9569068d8e, // x 2^-3162 ~= 10^-952
|
|
0x276e3f0f67f0553b, 0x00de73d9d5be6974, 0x6d4aa5b50bb5dc0d, 0xbbb7ef38bb827f2d, // x 2^-2976 ~= 10^-896
|
|
0x51a34a3e674484ed, 0x1fb6069f8b26f840, 0x925624c0d7d93317, 0xbf64d0275747de70, // x 2^-2790 ~= 10^-840
|
|
0xcc775c8cb6de1dbc, 0x6d60d02eac6309ee, 0x8e5a2e5116baf191, 0xc3241cf0094a8e70, // x 2^-2604 ~= 10^-784
|
|
0x6023c8fa17d7b105, 0x069cf8f51d2e5e65, 0xb0560c246f90e9e8, 0xc6f631e782d57096, // x 2^-2418 ~= 10^-728
|
|
0x92c17acb2d08d5fd, 0xc26ffb8e81532725, 0x2ffff1289a804c5a, 0xcadb6d313c8736fc, // x 2^-2232 ~= 10^-672
|
|
0x47df78ab9e92897a, 0xc02b302a892b81dc, 0xa855e127113c887b, 0xced42ec885d9dbbe, // x 2^-2046 ~= 10^-616
|
|
0xdaf2dec03ec0c322, 0x72db3bc15b0c7014, 0xe00bad8dfc0d8c8e, 0xd2e0d889c213fd60, // x 2^-1860 ~= 10^-560
|
|
0xd3a04799e4473ac8, 0xa116409a2fdf1e9e, 0xc654d07271e6c39f, 0xd701ce3bd387bf47, // x 2^-1674 ~= 10^-504
|
|
0x5c8a5dc65d745a24, 0x2726c48a85389fa7, 0x84c663cee6b86e7c, 0xdb377599b6074244, // x 2^-1488 ~= 10^-448
|
|
0xd7ebc61ba77a9e66, 0x8bf77d4bc59b35b1, 0xcb285ceb2fed040d, 0xdf82365c497b5453, // x 2^-1302 ~= 10^-392
|
|
0x744ce999bfed213a, 0x363b1f2c568dc3e2, 0xfd1b1b2308169b25, 0xe3e27a444d8d98b7, // x 2^-1116 ~= 10^-336
|
|
0x6a40608fe10de7e7, 0xf910f9f648232f14, 0xd1b3400f8f9cff68, 0xe858ad248f5c22c9, // x 2^-930 ~= 10^-280
|
|
0x9bdbfc21260dd1ad, 0x4609ac5c7899ca36, 0xa4f8bf5635246428, 0xece53cec4a314ebd, // x 2^-744 ~= 10^-224
|
|
0xd88181aad19d7454, 0xf80f36174730ca34, 0xdc44e6c3cb279ac1, 0xf18899b1bc3f8ca1, // x 2^-558 ~= 10^-168
|
|
0xee19bfa6947f8e02, 0xaa09501d5954a559, 0x4d4617b5ff4a16d5, 0xf64335bcf065d37d, // x 2^-372 ~= 10^-112
|
|
0xebbc75a03b4d60e6, 0xac2e4f162cfad40a, 0xeed6e2f0f0d56712, 0xfb158592be068d2e, // x 2^-186 ~= 10^-56
|
|
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000, // x 2^1 == 10^0 exactly
|
|
0x0000000000000000, 0x2000000000000000, 0xbff8f10e7a8921a4, 0x82818f1281ed449f, // x 2^187 == 10^56 exactly
|
|
0x51775f71e92bf2f2, 0x74a7ef0198791097, 0x03e2cf6bc604ddb0, 0x850fadc09923329e, // x 2^373 ~= 10^112
|
|
0xb204b3d9686f55b5, 0xfb118fc9c217a1d2, 0x90fb44d2f05d0842, 0x87aa9aff79042286, // x 2^559 ~= 10^168
|
|
0xd7924bff833149fa, 0xbc10c5c5cda97c8d, 0x82bd6b70d99aaa6f, 0x8a5296ffe33cc92f, // x 2^745 ~= 10^224
|
|
0xa67d072d3c7fa14b, 0x7ec63730f500b406, 0xdb0b487b6423e1e8, 0x8d07e33455637eb2, // x 2^931 ~= 10^280
|
|
0x546f2a35dc367e47, 0x949063d8a46f0c0e, 0x213a4f0aa5e8a7b1, 0x8fcac257558ee4e6, // x 2^1117 ~= 10^336
|
|
0x50611a621c0ee3ae, 0x202d895116aa96be, 0x1c306f5d1b0b5fdf, 0x929b7871de7f22b9, // x 2^1303 ~= 10^392
|
|
0xffa6738a27dcf7a3, 0x3c11d8430d5c4802, 0xa7ea9c8838ce9437, 0x957a4ae1ebf7f3d3, // x 2^1489 ~= 10^448
|
|
0x5bf36c0f40bde99d, 0x284ba600ee9f6303, 0xbf1d49cacccd5e68, 0x9867806127ece4f4, // x 2^1675 ~= 10^504
|
|
0xa6e937834ed12e58, 0x73f26eb82f6b8066, 0x655494c5c95d77f2, 0x9b63610bb9243e46, // x 2^1861 ~= 10^560
|
|
0x0cd4b7660adc6930, 0x8f868688f8eb79eb, 0x02e008393fd60b55, 0x9e6e366733f85561, // x 2^2047 ~= 10^616
|
|
0x3efb9807d86d3c6a, 0x84c10a1d22f5adc5, 0x55e04dba4b3bd4dd, 0xa1884b69ade24964, // x 2^2233 ~= 10^672
|
|
0xf065089401df33b4, 0x1fc02370c451a755, 0x44b222741eb1ebbf, 0xa4b1ec80f47c84ad, // x 2^2419 ~= 10^728
|
|
0xa62d0da836fce7d5, 0x75933380ceb5048c, 0x1cf4a5c3bc09fa6f, 0xa7eb6799e8aec999, // x 2^2605 ~= 10^784
|
|
0x7a400df820f096c2, 0x802c4085068d2dd5, 0x3c4a575151b294dc, 0xab350c27feb90acc, // x 2^2791 ~= 10^840
|
|
0xf48b51375df06e86, 0x412fe9e72afd355e, 0x870a8d87239d8f35, 0xae8f2b2ce3d5dbe9, // x 2^2977 ~= 10^896
|
|
0x881883521930127c, 0xe53fd3fcb5b4df25, 0xdd929f09c3eff5ac, 0xb1fa17404a30e5e8, // x 2^3163 ~= 10^952
|
|
0x270cd9f1348eb326, 0x37ed82fe9c75fccf, 0x1931b583a9431d7e, 0xb5762497dbf17a9e, // x 2^3349 ~= 10^1008
|
|
0x8919b01a5b3d9ec1, 0x6a7669bdfc6f699c, 0xe30db03e0f8dd286, 0xb903a90f561d25e2, // x 2^3535 ~= 10^1064
|
|
0xf0461526b4201aa5, 0x7fe40defe17e55f5, 0x9eb5cb19647508c5, 0xbca2fc30cc19f090, // x 2^3721 ~= 10^1120
|
|
0xd67bf35422978bbf, 0x0dbb1c416ebe661f, 0x24bd4c00042ad125, 0xc054773d149bf26b, // x 2^3907 ~= 10^1176
|
|
0xdd093192ef5508d0, 0x6eac3085943ccc0f, 0x7ea30dbd7ea479e3, 0xc418753460cdcca9, // x 2^4093 ~= 10^1232
|
|
0xfe4ff20db6d25dc2, 0x5d5d5a9519e34a42, 0x764f4cf916b4dece, 0xc7ef52defe87b751, // x 2^4279 ~= 10^1288
|
|
0xd8adfb2e00494c5e, 0x72435286baf0e84e, 0xbeb7fbdc1cbe8b37, 0xcbd96ed6466cf081, // x 2^4465 ~= 10^1344
|
|
0xe07c1e4384f594af, 0x0c6b90b8874d5189, 0xdce472c619aa3f63, 0xcfd7298db6cb9672, // x 2^4651 ~= 10^1400
|
|
0x5dd902c68fa448cf, 0xea8d16bd9544e48e, 0xe47defc14a406e4f, 0xd3e8e55c3c1f43d0, // x 2^4837 ~= 10^1456
|
|
0x1223d79357bedca8, 0xeae6c2843752ac35, 0xb7157c60a24a0569, 0xd80f0685a81b2a81, // x 2^5023 ~= 10^1512
|
|
0xcff72d64bc79e429, 0xccc52c236decd778, 0xfb0b98f6bbc4f0cb, 0xdc49f3445824e360, // x 2^5209 ~= 10^1568
|
|
0x3731f76b905dffbb, 0x5e2bddd7d12a9e42, 0xc6c6c1764e047e15, 0xe09a13d30c2dba62, // x 2^5395 ~= 10^1624
|
|
0xeb58d8ef2ada7c09, 0xbc1a3b726b789947, 0x87e8dcfc09dbc33a, 0xe4ffd276eedce658, // x 2^5581 ~= 10^1680
|
|
0x249a5c06dc5d5db7, 0xa8f09440be97bfe6, 0xb1a3642a8da3cf4f, 0xe97b9b89d001dab3, // x 2^5767 ~= 10^1736
|
|
0xbf34ff7963028cd9, 0xc20578fa3851488b, 0x2d4070f33b21ab7b, 0xee0ddd84924ab88c, // x 2^5953 ~= 10^1792
|
|
0x002d0511317361d5, 0xd6919e041129a1a7, 0xa2bf0c63a814e04e, 0xf2b70909cd3fd35c, // x 2^6139 ~= 10^1848
|
|
0x1fa87f28acf1dcd2, 0xe7a0a88981d1a0f9, 0x08f13995cf9c2747, 0xf77790f0a48a45ce, // x 2^6325 ~= 10^1904
|
|
0x1b6ff8afbe589b72, 0xc851bb3f9aeb1211, 0x7a37993eb21444fa, 0xfc4fea4fd590b40a, // x 2^6511 ~= 10^1960
|
|
0xef23a4cbc039f0c2, 0xbb3f8498a972f18e, 0xb7b1ada9cdeba84d, 0x80a046447e3d49f1, // x 2^6698 ~= 10^2016
|
|
0x2cc44f2b602b6231, 0xf231f4b7996b7278, 0x0cc6866c5d69b2cb, 0x8324f8aa08d7d411, // x 2^6884 ~= 10^2072
|
|
0x822c97629a3a4c69, 0x8a9afcdbc940e6f9, 0x7fe2b4308dcbf1a3, 0x85b64a659077660e, // x 2^7070 ~= 10^2128
|
|
0xf66cfcf42d4896b0, 0x1f11852a20ed33c5, 0x1d73ef3eaac3c964, 0x88547abb1d8e5bd9, // x 2^7256 ~= 10^2184
|
|
0x63093ad0caadb06c, 0x31be1482014cdaf0, 0x1e34291b1ef566c7, 0x8affca2bd1f88549, // x 2^7442 ~= 10^2240
|
|
0xab50f69048738e9a, 0xa126c32ff4882be8, 0x9e9383d73d486881, 0x8db87a7c1e56d873, // x 2^7628 ~= 10^2296
|
|
0xe57e659432b0a73e, 0x47a0e15dfc7986b8, 0x9cc5ee51962c011a, 0x907eceba168949b3, // x 2^7814 ~= 10^2352
|
|
0x8a6ff950599f8ae5, 0xd1cbbb7d005a76d3, 0x413407cfeeac9743, 0x93530b43e5e2c129, // x 2^8000 ~= 10^2408
|
|
0xd4e6b6e847550caa, 0x56a3106227b87706, 0x7efa7d29c44e11b7, 0x963575ce63b6332d, // x 2^8186 ~= 10^2464
|
|
0xd835c90b09842263, 0xb69f01a641da2a42, 0x5a848859645d1c6f, 0x9926556bc8defe43, // x 2^8372 ~= 10^2520
|
|
0x9b0ae73c204ecd61, 0x0794fd5e5a51ac2f, 0x51edea897b34601f, 0x9c25f29286e9ddb6, // x 2^8558 ~= 10^2576
|
|
0x3130484fb0a61d89, 0x32b7105223a27365, 0xb50008d92529e91f, 0x9f3497244186fca4, // x 2^8744 ~= 10^2632
|
|
0x8cd036553f38a1e8, 0x5e997e9f45d7897d, 0xf09e780bcc8238d9, 0xa2528e74eaf101fc, // x 2^8930 ~= 10^2688
|
|
0xe1f8b43b08b5d0ef, 0xa0eaf3f62dc1777c, 0x3a5828869701a165, 0xa580255203f84b47, // x 2^9116 ~= 10^2744
|
|
0x3c7f62e3154fa708, 0x5786f3927eb15bd5, 0x8b231a70eb5444ce, 0xa8bdaa0a0064fa44, // x 2^9302 ~= 10^2800
|
|
0x1ebc24a19cd70a2a, 0x843fddd10c7006b8, 0xfa1bde1f473556a4, 0xac0b6c73d065f8cc, // x 2^9488 ~= 10^2856
|
|
0x46b6aae34cfd26fc, 0x00db7d919b136c68, 0x7730e00421da4d55, 0xaf69bdf68fc6a740, // x 2^9674 ~= 10^2912
|
|
0x1c4edcb83fc4c49d, 0x61c0edd56bbcb3e8, 0x7f959cb702329d14, 0xb2d8f1915ba88ca5, // x 2^9860 ~= 10^2968
|
|
0x428c840d247382fe, 0x9cc3b1569b1325a4, 0x40c3a071220f5567, 0xb6595be34f821493, // x 2^10046 ~= 10^3024
|
|
0xbeb82e734787ec63, 0xbeff12280d5a1676, 0x11c48d02b8326bd3, 0xb9eb5333aa272e9b, // x 2^10232 ~= 10^3080
|
|
0x302349e12f45c73f, 0xb494bcc96d53e49c, 0x566765461bd2f61b, 0xbd8f2f7a1ba47d6d, // x 2^10418 ~= 10^3136
|
|
0x5704ebf5f16946ce, 0x431388ec68ac7a26, 0xb889018e4f6e9a52, 0xc1454a673cb9b1ce, // x 2^10604 ~= 10^3192
|
|
0x5a30431166af9b23, 0x132d031fc1d1fec0, 0xf85333a94848659f, 0xc50dff6d30c3aefc, // x 2^10790 ~= 10^3248
|
|
0x7573d4b3ffe4ba3b, 0xf888498a40220657, 0x1a1aeae7cf8a9d3d, 0xc8e9abc872eb2bc1, // x 2^10976 ~= 10^3304
|
|
0xb5eaef7441511eb9, 0xc9cf998035a91664, 0x12e29f09d9061609, 0xccd8ae88cf70ad84, // x 2^11162 ~= 10^3360
|
|
0x73aed4f1908f4d01, 0x8c53e7beeca4578f, 0xdf7601457ca20b35, 0xd0db689a89f2f9b1, // x 2^11348 ~= 10^3416
|
|
0x5adbd55696e1cdd9, 0x4949d09424b87626, 0xcbdcd02f23cc7690, 0xd4f23ccfb1916df5, // x 2^11534 ~= 10^3472
|
|
0x3f500ccf4ea03593, 0x9b80aac81b50762a, 0x44289dd21b589d7a, 0xd91d8fe9a3d019cc, // x 2^11720 ~= 10^3528
|
|
0x134ca67a679b84ae, 0x8909e424a112a3cd, 0x95aa118ec1d08317, 0xdd5dc8a2bf27f3f7, // x 2^11906 ~= 10^3584
|
|
0xe89e3cf733d9ff40, 0x014344660a175c36, 0x72c4d2cad73b0a7b, 0xe1b34fb846321d04, // x 2^12092 ~= 10^3640
|
|
0x68c0a2c6c02dae9a, 0x0b11160a6edb5f57, 0xe20a88f1134f906d, 0xe61e8ff47461cda9, // x 2^12278 ~= 10^3696
|
|
0x47fa54906741561a, 0xaa13acba1e5511f5, 0xc7c91d5c341ed39d, 0xea9ff638c54554e1, // x 2^12464 ~= 10^3752
|
|
0x365460ed91271c24, 0xabe33496aff629b4, 0xf659ede2159a45ec, 0xef37f1886f4b6690, // x 2^12650 ~= 10^3808
|
|
0xe4cbf4acc7fba37f, 0x350e915f7055b1b8, 0x78d946bab954b82f, 0xf3e6f313130ef0ef, // x 2^12836 ~= 10^3864
|
|
0xe692accdfa5bd859, 0xf4d4d3202379829e, 0xc9b1474d8f89c269, 0xf8ad6e3fa030bd15, // x 2^13022 ~= 10^3920
|
|
0xeca0018ea3b8d1b4, 0xe878edb67072c26d, 0x6b1d2745340e7b14, 0xfd8bd8b770cb469e, // x 2^13208 ~= 10^3976
|
|
0xce5fec949ab87cf7, 0x0151dcd7a53488c3, 0xf22e502fcdd4bca2, 0x81415538ce493bd5, // x 2^13395 ~= 10^4032
|
|
0x5e1731fbff8c032e, 0xe752f53c2f8fa6c1, 0x7c1735fc3b813c8c, 0x83c92edf425b292d, // x 2^13581 ~= 10^4088
|
|
0xb552102ea83f47e6, 0xdf0fd2002ff6b3a3, 0x0367500a8e9a178f, 0x865db7a9ccd2839e, // x 2^13767 ~= 10^4144
|
|
0x76507bafe00ec873, 0x71b256ecd954434c, 0xc9ac50475e25293a, 0x88ff2f2bade74531, // x 2^13953 ~= 10^4200
|
|
0x5e2075ba289a360b, 0xac376f28b45e5acc, 0x0879b2e5f6ee8b1c, 0x8badd636cc48b341, // x 2^14139 ~= 10^4256
|
|
0xab87d85e6311e801, 0xb7f786d14d58173d, 0x2f33c652bd12fab7, 0x8e69eee1f23f2be5, // x 2^14325 ~= 10^4312
|
|
0x7fed9b68d77255be, 0x35dc241819de7182, 0xad6a6308a8e8b557, 0x9133bc8f2a130fe5, // x 2^14511 ~= 10^4368
|
|
0x728ae72899d4bd12, 0xe5413d9414142a55, 0x9dbaa465efe141a0, 0x940b83f23a55842a, // x 2^14697 ~= 10^4424
|
|
0x0f7740145246fb8f, 0x186ef2c39acb4103, 0x888c9ab2fc5b3437, 0x96f18b1742aad751, // x 2^14883 ~= 10^4480
|
|
0xd8bb0fba2183c6ef, 0xbf66d66cc34f0197, 0xba00864671d1053f, 0x99e6196979b978f1, // x 2^15069 ~= 10^4536
|
|
0x9b71ed2ceb790e49, 0x6faac32d59cc1f5d, 0x61d59d402aae4fea, 0x9ce977ba0ce3a0bd, // x 2^15255 ~= 10^4592
|
|
0xa0aa6d5e63991cfb, 0x19482fa0ac45669c, 0x803c1cd864033781, 0x9ffbf04722750449, // x 2^15441 ~= 10^4648
|
|
0x95a9949e04b8bff3, 0x900aa3c2f02ac9d4, 0xa28a151725a55e10, 0xa31dcec2fef14b30, // x 2^15627 ~= 10^4704
|
|
0x3acf9496dade0ce9, 0xbd8ecf923d23bec0, 0x5b8452af2302fe13, 0xa64f605b4e3352cd, // x 2^15813 ~= 10^4760
|
|
0x6204425d2b58e822, 0xdee162a8a1248550, 0x82b84cabc828bf93, 0xa990f3c09110c544, // x 2^15999 ~= 10^4816
|
|
0x091a2658e0639f32, 0x66fa2184cee0b861, 0x8d29dd5122e4278d, 0xace2d92db0390b59, // x 2^16185 ~= 10^4872
|
|
0x80acda113324758a, 0xded179c26d9ab828, 0x58f8fde02c03a6c6, 0xb045626fb50a35e7, // x 2^16371 ~= 10^4928
|
|
0x7128a8aad239ce8f, 0x8737bd250290cd5b, 0xd950102978dbd0ff, 0xb3b8e2eda91a232d, // x 2^16557 ~= 10^4984
|
|
]
|
|
|
|
@available(SwiftStdlib 6.2, *)
|
|
fileprivate func _intervalContainingPowerOf10_Binary128(
|
|
p: Int,
|
|
lower: inout _UInt256,
|
|
upper: inout _UInt256
|
|
) -> Int {
|
|
if p >= 0 && p <= 55 {
|
|
let exactLow = powersOf10_Exact128[p * 2]
|
|
let exactHigh = powersOf10_Exact128[p * 2 + 1]
|
|
lower = _UInt256(high: exactHigh, exactLow, 0, low: 0)
|
|
upper = lower
|
|
return binaryExponentFor10ToThe(p)
|
|
}
|
|
|
|
let index = p + 4984
|
|
let offset = (index / 56) * 4
|
|
lower = _UInt256(
|
|
high: powersOf10_Binary128[offset + 3],
|
|
powersOf10_Binary128[offset + 2],
|
|
powersOf10_Binary128[offset + 1],
|
|
low: powersOf10_Binary128[offset + 0])
|
|
let extraPower = index % 56
|
|
var e = binaryExponentFor10ToThe(p - extraPower)
|
|
|
|
if extraPower > 0 {
|
|
let extra = UInt128(
|
|
_low: powersOf10_Exact128[extraPower * 2],
|
|
_high: powersOf10_Exact128[extraPower * 2 + 1])
|
|
lower.multiplyRoundingDown(by: extra)
|
|
e += binaryExponentFor10ToThe(extraPower)
|
|
}
|
|
upper = lower
|
|
upper.low += 2
|
|
return e
|
|
}
|