//===--- FloatingPointToString.swift -------------------------*- Swift -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2018-2026 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, logging, debugging, and any general printing where you don't // have specific UI requirements. // // Because it doesn't have to support an arbitrary number of output // digits, this format can be generated _much_ faster than the // `printf` `%e`/`%f`/`%g` forms, which makes it even more ideal for // JSON, logging, and general output. // //===---------------------------------------------------------------------===// /// /// This code has used a variety of different algorithms over the years, all /// generating exactly identical output. The current implementation starts /// with a floating-point value `s * 2^e` where s and e are both integers. We /// compute /// ``` /// p = ceil(e * log10(2)) /// ``` /// and then do a fixed-precision multiply /// ``` /// (s + 1/2) * 2^e * 10^-p /// ``` /// with different rounding depending on whether the original /// `s` is even or odd. /// /// * About 40% of the time, the integer portion of this last value is /// precisely the integer significand of the optimal base-10 /// representation we want. We only need to convert this integer to /// digits with a fast integer conversion algorithm, such as the /// one below based on work by Paul Khuong. /// /// * The remaining 60% of the time, we need to generate a single /// additional digit (with correct rounding). /// /// The description above omits many key details, of course. A more complete /// description appears in the extensive comments for the Float32 implementation /// below. (The other implementations below use essentially the same approach, /// only with fewer comments.) /// /// The implementation draws inspiration from the following papers: /// /// ------------ /// Raffaello Guilietti; "The Schubfach way to render doubles", 2021. /// Published online. /// /// Credit: Guilietti computes the power-of-10 scaling factor based on /// the width of the rounding interval in order to obtain a /// nearly-final result from the initial scaling, avoiding the need /// for per-digit iteration. /// ------------ /// Florian Loitsch; "Printing Floating-Point Numbers Quickly and /// Accurately with Integers", 2010. /// https://doi.org/10.1145/1806596.1806623 /// /// Credit: Our test for whether the initial digits give us a value in /// the rounding interval is from Loitsch' Grisu algorithm. The logic /// to generate an additional digit when needed is also based on Grisu. /// ------------ /// Marc Andrysco, Ranjit Jhala, Sorin Lerner; "Printing Floating-Point /// Numbers: A Faster, Always Correct Method", 2016. /// https://doi.org/10.1145/2837614.2837654 /// /// Credit: Andrysco, Jhala, and Lerner explored the impact of /// higher precision arithmetic on Grisu-style algorithms and /// provided a robust way to test implementations of such algorithms /// for correctness. /// ------------ /// TODO: Cite vitaut's exploration of Schubfach variants? /// /// In short, this implementation is: /// /// * Fast. It uses only fixed-width integer arithmetic and has /// constant memory requirements. On an Apple M4 processor, /// _Float64ToASCII can convert a Float64 into text in about 10ns. /// /// * Always Round-trip 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, Eisel-Lemire 2021, or that /// used in FloatingPointFromString.swift.) /// /// * 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 to achieve other goals. /// Any attempt to compare the performance of this implementation /// to others should consider the following: /// * The output ergonomics described above do take some time. /// It would be faster to always emit an integer significand /// followed by an exponent (e.g., "123456e-78"). /// * 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 `_powerOf10_*()` functions) /// * Compare code size as well as performance. Our Float64 /// implementation here is a little over 3kiB compiled, _including_ /// the supporting data tables. (Most published implementations /// require twice that just for their supporting tables.) /// // ---------------------------------------------------------------------------- // ================================================================ // // Float16 // // ================================================================ #if (os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64) // Float16 is not currently supported on Intel x86_64 macOS, // (including macCatalyst on x86_64) but this symbol somehow got // exported there. // This preserves that export. // Note: Other platforms that don't support Float16 should // NOT export this. @available(SwiftStdlib 5.3, *) @_silgen_name("swift_float16ToString") public func _float16ToStringImpl( _ textBuffer: UnsafeMutablePointer, _ bufferLength: UInt, _ value: Float, _ debug: Bool ) -> UInt64 { fatalError() } #else // Support Legacy ABI on top of new implementation @available(SwiftStdlib 5.3, *) @_silgen_name("swift_float16ToString") public func _float16ToStringImpl( _ textBuffer: UnsafeMutablePointer, _ bufferLength: UInt, _ value: Float16, _ debug: Bool ) -> UInt64 { // Code below works with raw memory. var buffer = unsafe MutableSpan( _unchecked: textBuffer, count: Int(bufferLength)) for i in 0..(repeating:0x30)` // Notes on the implementation here: This implementation writes out // all integer values in non-exponential form. This is technically // not "optimal". For example, "65504.0" shows 5 significant digits, // even though the 3 significant digits of "6.55e+04" is sufficient. // But that just looks silly. // // As a side-effect of the above, we end up handling integer values as // a special case, so the general path only has to deal with values // whose binary exponent is negative. This means they are handled by // multiplying by a positive power of ten, which can be done exactly // with integer arithmetic due to the small range of Float16. @available(SwiftStdlib 5.3, *) internal func _Float16ToASCII( value f: Float16, buffer utf8Buffer: inout MutableSpan ) -> Range { // We need a MutableRawSpan in order to use wide store/load operations assert(utf8Buffer.count >= 24) var buffer = utf8Buffer.mutableBytes let significandBitCount = Float16.significandBitCount + 1 // 11 let exponentBias = Int(bitPattern: Float16._exponentBias) - 1 + significandBitCount // 14 + 11 = 25 let binaryExponent: Int let significand: Float16.RawSignificand // Step 1: Handle the special cases, decompose the input if f.exponentBitPattern == Float16._infinityExponent { if (f.isInfinite) { return _infinity(buffer: &buffer, sign: f.sign) } else { // f.isNaN let quietBit = f.significandBitPattern & Float16._quietNaNMask let payload = f.significandBitPattern & (Float16._significandMask &>> 2) return nan_details( buffer: &buffer, sign: f.sign, quiet: quietBit != 0, payloadHigh: 0, payloadLow: UInt64(truncatingIfNeeded:payload)) } } else if f.exponentBitPattern == 0 { if (f.isZero) { return _zero(buffer: &buffer, sign: f.sign) } else { // f.isSubnormal significand = f.significandBitPattern binaryExponent = 1 &- exponentBias } } else { // Normal let b = Int(f.exponentBitPattern) &- exponentBias let implicitBit = Float16.RawSignificand(1) << Float16.significandBitCount let s = f.significandBitPattern &+ implicitBit if b > 0 { // Special handling for integer values, as described above. let base10Significand = UInt32(s) &<< b let digits = _intToEightDecimalDigits(base10Significand) var start = 1 buffer.storeBytes( of: digits &+ 0x3030303030303030, toByteOffset: start, as: UInt64.self) var end = start + 8 // Trim leading zeros and insert `-` if appropriate: start += digits.trailingZeroBitCount / 8 if f.sign == .minus { buffer.storeBytes( of: 0x2d, // "-" toByteOffset: start &- 1, as: UInt8.self) start &-= 1 } // Add ".0" at end buffer.storeBytes( of: 0x2e, // "." toByteOffset: end, as: UInt8.self) end += 2 return start..> 8 var base10Power = Int(truncatingIfNeeded: roundedBase10Power) // Step 3: Look up power-of-10 scale factor let powerOfTen = UInt64(powersOf10_Float16[0 &- base10Power]) // Step 4: Scale the interval (with rounding) // If significand is odd, we need to narrow the interval let narrowInterval = f.significandBitPattern & 1 // Scale 1 binary ULP var scaledBinaryUlp = powerOfTen &<< (32 &+ binaryExponent) scaledBinaryUlp &+= 2 &- 4 &* UInt64(narrowInterval) // We'll use 32.32 fixed point from here on... let fractionBits = 32 let fractionMask = (UInt64(1) << fractionBits) - 1 let oneHalf = UInt64(1) << (fractionBits - 1) // Scaled upper limit of the rounding interval let u0 = powerOfTen &* UInt64(significand) let u1 = u0 &<< (32 &+ binaryExponent) let upperBound = u1 &+ (scaledBinaryUlp >> 1) var base10Significand = UInt32(truncatingIfNeeded: upperBound >> fractionBits) let delta = upperBound & fractionMask // Scaled distance from the value above to the lower bound // of the rounding interval. var intervalWidth = scaledBinaryUlp if f.significandBitPattern == 0 { intervalWidth &-= intervalWidth >> 2 } // Step 6: Compute one more decimal digit if necessary if intervalWidth < delta { // Adjust intervalWidth and delta to measure from the // actual target value to the lower bound of the rounding // interval. (Up to this point, they've measured from the upper // bound of the rounding interval.) let halfUlp = scaledBinaryUlp &* 5 var delta = delta &* 10 &- halfUlp intervalWidth = intervalWidth &* 10 &- halfUlp // Compute the additional digit var digit = UInt8(truncatingIfNeeded: delta >> fractionBits) delta &= fractionMask // Note that `digit` is the largest value below the target value; // `digit + 1` is the smallest value above the target value. We // want to select whichever is closer to the target value. let greater = unsafe unsafeBitCast(delta > oneHalf, to: UInt8.self) // If they're equally close, pick the even one let greaterOrEqual = unsafe unsafeBitCast(delta >= oneHalf, to: UInt8.self) // If the lower one is not in the interval, choose the higher one let outOfInterval = unsafe unsafeBitCast(delta > intervalWidth, to: UInt8.self) digit &+= greater | (greaterOrEqual & digit) | outOfInterval // Add the new digit into the base10Significand base10Significand = base10Significand &* 10 &+ UInt32(digit) base10Power &-= 1 } // Step 7: Convert the digits and write them out... var digits = _intToEightDecimalDigits(base10Significand) let trailingZeros = digits.leadingZeroBitCount / 8 digits &<<= trailingZeros * 8 base10Power &+= trailingZeros let startOffset = 6 buffer.storeBytes( of: digits &+ 0x3030303030303030, toByteOffset: startOffset, as: UInt64.self) let firstDigit = startOffset &+ digits.trailingZeroBitCount / 8 let nextDigit = startOffset &+ 8 // Step 8: Finish formatting return _finishFormatting( buffer: &buffer, sign: f.sign, firstDigit: firstDigit, nextDigit: nextDigit, forceExponential: false, base10Power: base10Power) } fileprivate let powersOf10_Float16: _InlineArray<_, UInt32> = [ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 ] #endif // ================================================================ // // Float32 // // ================================================================ // Support Legacy ABI on top of new implementation @_silgen_name("swift_float32ToString") @usableFromInline internal func _float32ToStringImpl( _ textBuffer: UnsafeMutablePointer, _ bufferLength: UInt, _ value: Float32, _ debug: Bool ) -> UInt64 { // Code below works with raw memory. var buffer = unsafe MutableSpan( _unchecked: textBuffer, count: Int(bufferLength)) for i in 0..(repeating:0x30)` internal func _Float32ToASCII( value f: Float32, buffer utf8Buffer: inout MutableSpan ) -> Range { // We need a MutableRawSpan in order to use wide store/load operations assert(utf8Buffer.count >= 24) var buffer = utf8Buffer.mutableBytes let significandBitCount = Float.significandBitCount + 1 // 24 let exponentBias = Int(bitPattern: Float32._exponentBias) - 1 + significandBitCount // 126 + 24 let binaryExponent: Int let significand: Float.RawSignificand // Step 1: Decompose the input, handle the special cases if f.exponentBitPattern == Float32._infinityExponent { if (f.isInfinite) { return _infinity(buffer: &buffer, sign: f.sign) } else { // f.isNaN let quietBit = f.significandBitPattern & Float32._quietNaNMask let payload = f.significandBitPattern & (Float32._significandMask &>> 2) return nan_details( buffer: &buffer, sign: f.sign, quiet: quietBit != 0, payloadHigh: 0, payloadLow: UInt64(truncatingIfNeeded:payload)) } } else if f.exponentBitPattern == 0 { if (f.isZero) { return _zero(buffer: &buffer, sign: f.sign) } else { // f.isSubnormal significand = f.significandBitPattern binaryExponent = 1 &- exponentBias } } else { // Normal let implicitBit = Float.RawSignificand(1) << Float.significandBitCount significand = f.significandBitPattern &+ implicitBit binaryExponent = Int(f.exponentBitPattern) &- exponentBias } // Step 2: Compute the base 10 exponent to match the rounding interval // Following Schubfach, let RI = the width of the rounding interval // Compute base10Power such that // 10^base10Power > RI > 10^(base10Power - 1) // This guarantees: // * AT MOST one multiple of 10^base10Power in our rounding interval // So if we find one, it's unique and we're done! // * AT LEAST one multiple of 10^(base10Power-1) in that interval. // So if we don't find a multiple of 10^base10Power, then // we're certain to find a solution with just one more digit. // In the common case where RI = 2^e exactly, this implies that: // base10Power = ceiling(e * log10(2)) // For an exact power of 2, the rounding interval is 25% narrower, so // base10Power = ceiling(e * log10(2) + log10(0.75)) let maybeLogThreeQuarters = (f.significandBitPattern == 0 ? Int64(-536607787) : Int64(0)) let rawBase10Power = Int64(binaryExponent) &* 1292913986 &+ maybeLogThreeQuarters let roundedBase10Power = (rawBase10Power &+ 0xffffffff) &>> 32 var base10Power = Int(truncatingIfNeeded: roundedBase10Power) // Step 3: Look up power-of-10 scale factor // To obtain a binary floating-point value for the power of 10, look // up the significand in a table and compute the corresponding // exponent. The power of 10 is then: // powerOfTen * 2^powerOfTenExponent let powerOfTen = powersOf10_Float32[33 &- base10Power] let powerOfTenExponent = binaryExponentFor10ToThe(0 &- base10Power) // Step 4: Scale the interval (with rounding) // We compute `upperBound` the upper bound of the rounding interval and // `intervalWidth` the width, both scaled by 10^(-base10Power) // After scaling, we need enough integer bits to represent the // scaled significand. The worst case is the asymmetric case: then // 10^p > 3/4 * 2^e, so the maximum possible value of 2^e 10^-p is // 4/3, which means we'll need one more bit than the binary // significand. let integerBits = significandBitCount + 1 let fractionBits = 64 - integerBits let fractionMask = (UInt64(1) << fractionBits) - 1 let oneHalf = UInt64(1) << (fractionBits - 1) // If the significand is even, we want to widen the interval by // rounding up the upper midpoint and increasing intervalWidth. // Conversely if the significand is odd. This ensures that the // exact endpoints of the rounding interval are handled correctly. let narrowInterval = f.significandBitPattern & 1 // Scale one binary ULP let align = integerBits &- (binaryExponent &+ powerOfTenExponent) var scaledBinaryUlp = powerOfTen &>> align // Widen or narrow the Ulp estimate -- this will flow through // to the other places we need even/odd adjustments. scaledBinaryUlp &+= 3 &- 6 &* UInt64(narrowInterval) // Scaled upper bound of the rounding interval let mask32 = UInt64(UInt32.max) let low = (powerOfTen & mask32) &* UInt64(significand) let high = (powerOfTen &>> 32) &* UInt64(significand) // (high << 32) + low is the 96-bit intermediate value. Combine and // align to 64 bit fixed-point, and add 1/2 ULP for the upper bound. let upperBound = ((low &>> align) &+ (high &<< (32 &- align)) &+ (scaledBinaryUlp &>> 1)) // Width of the scaled rounding interval // In the non-power-of-two case, the rounding interval has width 1 ULP. var intervalWidth = scaledBinaryUlp if f.significandBitPattern == 0 { // In the power-of-two case, the interval is 3/4 ULP. intervalWidth &-= intervalWidth &>> 2 } // Step 5: Emit most of the decimal digits into the destination buffer // firstDigit starts at 6 to give us room to insert an initial minus // sign and/or leading zeros. This is used by the ergonomic formatting // logic done in `finishFormatting()`. var firstDigit = 6 var nextDigit = firstDigit // Split the scaled upperBound into the integer part // (initial base-10 significand) and fraction `delta` (distance // between that significand and the upper bound of the // interval). let base10Significand = UInt32(truncatingIfNeeded: upperBound &>> fractionBits) var delta = upperBound & fractionMask // Convert the digits we have so far and write them out... We could // delay this and fold an extra digit (if necessary) into the // base10Significand. That would work because a UInt32 can hold any // 9-digit integer. It would allow us to mimic the Float16 // structure above, where this entire function basically just // converts a pair of integers (significand, binaryExponent) into // another pair of integers (base10Significand, base10Power) and // then at the end converts that pair of integers into a textual // representation. // But if we do the conversion here, we know we don't have more than // 8 digits, which eliminates the need for extra fussing to conditionally // support up to 9 digits later on. let digits = _intToEightDecimalDigits(base10Significand) buffer.storeBytes( of: digits + 0x3030303030303030, toByteOffset: firstDigit, as: UInt64.self) nextDigit &+= 8 // Trim leading zero digits // (Little-endian assumption means that the _trailing_ // zero digits in `digits` are the most-significant ones.) firstDigit &+= digits.trailingZeroBitCount / 8 // Step 6: Compute one more decimal digit if necessary // Because of how we computed base10Power above, either the digits // so far are in the rounding interval and we're essentially done, // or we need exactly one more digit. // Intuitively: `intervalWidth` is the width of the rounding interval, // `delta` is the distance from the value we've computed so far // to our current target value. if intervalWidth > delta { // Step 6, Case A: We have a value that lies within the rounding // interval, and it's a multiple of 10^base10Power. As described // earlier, there can only be one such. This is the fast case. // Experimentally, ~39% of all inputs get here. // We don't need any more digits, just trim trailing zeros let trailingZeros = digits.leadingZeroBitCount / 8 nextDigit &-= trailingZeros base10Power &+= trailingZeros // No final-digit adjustment is needed } else { // Step 6, Case B: We need another digit // Experimentally, ~61% of all inputs get here. // Adjust `delta` to measure the distance from the value we've computed so // far to the actual float value (instead of the upper endpoint). This // requires subtracting 1/2 ULP from both delta and intervalWidth: let halfUlp = scaledBinaryUlp &* 5 // This is `delta -= ulp/2; delta *= 10` reordered to reduce precision loss delta = delta &* 10 &- halfUlp // Adjust `intervalWidth` to reflect only the lower part of the rounding interval intervalWidth = intervalWidth &* 10 &- halfUlp // Multiplying by 10 above scaled us from 10^base10Power // to 10^(base10Power - 1), which gives us the extra digit we want: var digit = UInt8(truncatingIfNeeded: delta &>> fractionBits) delta &= fractionMask // `delta` is now the scaled distance from our current base-10 // value to the actual binary target value. `digit` is the closest // base-10 digit _below_ our target, `digit + 1` is the closest // _above_ the target. We need to choose the best one. // Note: Using arithmetic to combine booleans as below is considerably // faster than the obvious if-else chain. Swift booleans are consistently // represented as single-byte 0 or 1 values. let epsilon = UInt64(64) // If `delta` is definitively > 1/2, then `digit` is further than `digit + 1` let greater = unsafe unsafeBitCast(delta > (oneHalf &+ epsilon), to: UInt8.self) // They might be equally close (ignoring precision loss in the earlier calculations), // in which case we want `digit + 1` if that would make the result even. let greaterOrEqual = unsafe unsafeBitCast(delta > (oneHalf &- epsilon), to: UInt8.self) // If the lower value is outside of the interval, we definitely want the upper one: // (Note: in the regular symmetric interval case, this is redundant with `greater`) let outOfInterval = unsafe unsafeBitCast(delta > intervalWidth, to: UInt8.self) // Select the upper value if any of these three conditions holds: digit &+= greater | (greaterOrEqual & digit) | outOfInterval // Write out the extra digit buffer.storeBytes( of: digit &+ 0x30, toByteOffset: nextDigit, as: UInt8.self) nextDigit &+= 1 base10Power &-= 1 } // Step 7: Finish formatting let isBoundary = (f.significandBitPattern == 0) let forceExponential = ((binaryExponent > 1) || (binaryExponent == 1 && !isBoundary)) return _finishFormatting( buffer: &buffer, sign: f.sign, firstDigit: firstDigit, nextDigit: nextDigit, forceExponential: forceExponential, base10Power: base10Power) } // ================================================================ // // Float64 // // ================================================================ // Support Legacy ABI on top of new implementation @_silgen_name("swift_float64ToString") @usableFromInline internal func _float64ToStringImpl( _ textBuffer: UnsafeMutablePointer, _ bufferLength: UInt, _ value: Float64, _ debug: Bool ) -> UInt64 { // Code below works with raw memory. var buffer = unsafe MutableSpan( _unchecked: textBuffer, count: Int(bufferLength)) for i in 0..(repeating:0x30)` internal func _Float64ToASCII( value f: Float64, buffer utf8Buffer: inout MutableSpan ) -> Range { assert(utf8Buffer.count >= 32) var buffer = utf8Buffer.mutableBytes let significandBitCount = Double.significandBitCount + 1 // 53 let exponentBias = Int(bitPattern: Float64._exponentBias) - 1 + significandBitCount let binaryExponent: Int let significand: Double.RawSignificand // Step 1: Handle the special cases, decompose the input if f.exponentBitPattern == Float64._infinityExponent { if (f.isInfinite) { return _infinity(buffer: &buffer, sign: f.sign) } else { // f.isNaN let quietBit = f.significandBitPattern & Float64._quietNaNMask let payload = f.significandBitPattern & (Float64._significandMask &>> 2) return nan_details( buffer: &buffer, sign: f.sign, quiet: quietBit != 0, payloadHigh: 0, payloadLow: payload ) } } else if f.exponentBitPattern == 0 { if (f.isZero) { return _zero(buffer: &buffer, sign: f.sign) } else { // f.isSubnormal significand = f.significandBitPattern binaryExponent = 1 &- exponentBias } } else { // Normal let implicitBit = Double.RawSignificand(1) << Double.significandBitCount significand = f.significandBitPattern &+ implicitBit binaryExponent = Int(f.exponentBitPattern) &- exponentBias } // Step 2: Compute the base 10 exponent to match the rounding interval let maybeLogThreeQuarters = (f.significandBitPattern == 0 ? Int64(-536607787) : Int64(0)) let rawBase10Power = Int64(binaryExponent) &* 1292913986 &+ maybeLogThreeQuarters let roundedBase10Power = (rawBase10Power &+ 0xffffffff) &>> 32 var base10Power = Int(truncatingIfNeeded: roundedBase10Power) // Step 3: Look up power-of-10 scale factor var powerOfTen: _UInt128 = 0 let powerOfTenExponent = _powerOf10_Binary64(p: 0 &- base10Power, significand: &powerOfTen) // Step 4: Scale the interval (with rounding) // After scaling, we'll use a 54.74 fixed-point format let integerBits = significandBitCount + 1 let fractionBits = 128 - integerBits let fractionMask = (_UInt128(1) << fractionBits) - 1 let oneHalf = _UInt128(1) << (fractionBits - 1) let narrowInterval = f.significandBitPattern & 1 // Scale one binary ULP let align = integerBits &- (binaryExponent &+ powerOfTenExponent) var scaledBinaryUlp = powerOfTen &>> align scaledBinaryUlp &+= _UInt128(bitPattern: _Int128(3 &- 6 &* Int(narrowInterval))) // Scale the upper limit let low = _UInt128(powerOfTen._low) &* _UInt128(significand) let high = _UInt128(powerOfTen._high) &* _UInt128(significand) let upperBound = ((low &>> align) &+ (high &<< (64 - align)) &+ (scaledBinaryUlp &>> 1)) // Compute the width of the scaled rounding interval var intervalWidth = scaledBinaryUlp if f.significandBitPattern == 0 { // In the power-of-two case, the interval is 3/4 ULP. intervalWidth &-= intervalWidth &>> 2 } // Step 5: Emit most of the decimal digits into the destination buffer var firstDigit = 6 var nextDigit = firstDigit let base10Significand = UInt64(truncatingIfNeeded: upperBound >> fractionBits) var delta = upperBound & fractionMask // Convert the digits we have so far and write them out... let digits = _intToSixteenDecimalDigits(base10Significand) let zeros = _UInt128( _low: 0x3030303030303030, _high: 0x3030303030303030) buffer.storeBytes( of: digits &+ zeros, toByteOffset: firstDigit, as: _UInt128.self) nextDigit &+= 16 // Trim leading zero digits firstDigit &+= digits.trailingZeroBitCount / 8 // Step 6: Compute one more decimal digit if necessary if intervalWidth > delta { // Step 6, Case A: We have a value that lies within the interval // We don't need any more digits, we only need to trim trailing zeros let trailingZeros = digits.leadingZeroBitCount / 8 nextDigit &-= trailingZeros base10Power &+= trailingZeros // No final-digit adjustment is needed } else { // Step 6, Case B: We need another digit let halfUlp = scaledBinaryUlp &* 5 delta = delta &* 10 &- halfUlp intervalWidth = intervalWidth &* 10 &- halfUlp var digit = UInt8(truncatingIfNeeded: delta >> fractionBits) delta &= fractionMask let epsilon = _UInt128(64) let greater = unsafe unsafeBitCast(delta > (oneHalf &+ epsilon), to: UInt8.self) let greaterOrEqual = unsafe unsafeBitCast(delta > (oneHalf &- epsilon), to: UInt8.self) let outOfInterval = unsafe unsafeBitCast(delta > intervalWidth, to: UInt8.self) digit &+= greater | (greaterOrEqual & digit) | outOfInterval buffer.storeBytes( of: digit &+ 0x30, toByteOffset: nextDigit, as: UInt8.self) nextDigit &+= 1 base10Power &-= 1 } // Step 7: Finish formatting let isBoundary = (f.significandBitPattern == 0) let forceExponential = ((binaryExponent > 1) || (binaryExponent == 1 && !isBoundary)) return _finishFormatting( buffer: &buffer, sign: f.sign, firstDigit: firstDigit, nextDigit: nextDigit, forceExponential: forceExponential, base10Power: base10Power) } // ================================================================ // // 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") @usableFromInline internal func _float80ToStringImpl( _ textBuffer: UnsafeMutablePointer, _ bufferLength: UInt, _ value: Float80, _ debug: Bool ) -> UInt64 { // Code below works with raw memory. var buffer = unsafe MutableSpan( _unchecked: textBuffer, count: Int(bufferLength)) for i in 0..(repeating:0x30)` internal func _Float80ToASCII( value f: Float80, buffer utf8Buffer: inout MutableSpan ) -> Range { assert(utf8Buffer.count >= 64) 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. // Float80.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 significandBits = Float80.significandBitCount + 1 let exponentBias = Int(bitPattern: Float80._exponentBias) - 1 + significandBits // 16382 + 64 let isBoundary = f.significandBitPattern == 0 if f.exponentBitPattern == Float80._infinityExponent { // 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 & (Float80._quietNaNMask - 1) switch selector { case 0: // ∞ or sNaN on 287, invalid on 387 fallthrough case 1: // Pseudo-NaN: sNaN on 287, invalid on 387 // We treat invalid/indefinite patterns as plain qNaN fallthrough case 3: // sNaN on 287, qNaN on 387 return nan_details( buffer: &buffer, sign: f.sign, 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) } 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 (J-bit set) binaryExponent = Int(f.exponentBitPattern) &- exponentBias significand = rawSignificand } else { // Invalid: non-zero exponent with J-bit clear ("unnormal") return nan_details( buffer: &buffer, sign: .plus, quiet: true, payloadHigh: 0, payloadLow: 0) } return _Float128Backend( utf8Buffer: &utf8Buffer, isBoundary: isBoundary, binaryExponent: binaryExponent, significand: _UInt128(significand), sign: f.sign) } #endif // ================================================================ // // Float128 // // ================================================================ // This requires only the most basic `Float128` type. In particular, // it requires absolutely no arithmetic on that type. /* @available(macOS 15.0, watchOS 11.0, *) internal func _Float128ToASCII( value f: Float128, buffer utf8Buffer: inout MutableSpan ) -> Range { assert(utf8Buffer.count >= 64) var buffer = utf8Buffer.mutableBytes let significandBitCount = Float128.significandBitCount + 1 // 113 let exponentBias = Int(bitPattern: Float128._exponentBias) - 1 + significandBitCount // 16382 + 113 let binaryExponent: Int let significand: UInt128 // Step 1: Handle the special cases, decompose the input if f.exponentBitPattern == Float128._infinityExponent { if (f.isInfinite) { return _infinity(buffer: &buffer, sign: f.sign) } else { // f.isNaN let quietBit = f.significandBitPattern & Float128._quietNaNMask let payload = f.significandBitPattern & (Float128._significandMask &>> 2) return nan_details( buffer: &buffer, sign: f.sign, quiet: quietBit != 0, payloadHigh: payload._high, payloadLow: payload._low ) } } else if f.exponentBitPattern == 0 { if (f.isZero) { return _zero(buffer: &buffer, sign: f.sign) } else { // f.isSubnormal significand = f.significandBitPattern binaryExponent = 1 &- exponentBias } } else { // Normal let implicitBit = UInt128(1) << Float128.significandBitCount significand = f.significandBitPattern &+ implicitBit binaryExponent = Int(f.exponentBitPattern) &- exponentBias } return _Float128Backend( utf8Buffer: &utf8Buffer, isBoundary: f.significandBitPattern == 0, binaryExponent: binaryExponent, significand: _UInt128(significand), sign: f.sign) } */ // ================================================================ // // General conversion supporting any format up to Float128 // // ================================================================ // Core conversion logic for any format with <= 113 bit significand // and <= 15 bit exponent. This can be used for Float128, Float80, as // well as any smaller format. (Of course, the tuned implementations // for Float64, Float32, and Float16 above are much faster.) fileprivate func _Float128Backend( utf8Buffer: inout MutableSpan, isBoundary: Bool, binaryExponent: Int, significand: _UInt128, sign: FloatingPointSign ) -> Range { assert(utf8Buffer.count >= 56) var buffer = utf8Buffer.mutableBytes // Step 2: Compute the base 10 exponent to match the rounding interval let maybeLogThreeQuarters = (isBoundary ? Int64(-536607787) : Int64(0)) let rawBase10Power = Int64(binaryExponent) &* 1292913986 &+ maybeLogThreeQuarters let roundedBase10Power = (rawBase10Power &+ 0xffffffff) &>> 32 var base10Power = Int(truncatingIfNeeded: roundedBase10Power) // Step 3: Look up power-of-10 scale factor var powerOfTen = _UInt256() let powerOfTenExponent = _powerOf10_Binary128( p: 0 &- base10Power, significand: &powerOfTen) // Step 4: Scale the interval (with rounding) // Fixed-point format: 114 integer bits, 142 fraction bits = 256 total let significandBits = 113 // Sufficient for Float128 let integerBits = significandBits + 1 let fractionMask = _UInt256( high: 0, UInt64.max >> (integerBits - 64), UInt64.max, low: UInt64.max) let oneHalf = _UInt256( high: 0, UInt64(1) << (128 - 1 - integerBits), 0, low: 0) let narrowInterval = significand & 1 // Scale one binary ULP: scaledBinaryUlp = powerOfTen >> align let align = integerBits &- (binaryExponent &+ powerOfTenExponent) var scaledBinaryUlp = powerOfTen &>> align // Widen or narrow the ULP for even/odd significand let adjustment = 4 &- 8 &* Int(narrowInterval) scaledBinaryUlp &+= adjustment // Scale the upper limit var rawProduct = powerOfTen rawProduct.multiply(by: significand, lsr: align) let upperBound = rawProduct &+ (scaledBinaryUlp &>> 1) // Compute the width of the scaled rounding interval var intervalWidth = scaledBinaryUlp if isBoundary { // Power-of-two: interval is 3/4 ULP intervalWidth = intervalWidth &- (intervalWidth &>> 2) } // Step 5: Emit most of the decimal digits into the destination buffer // Float80 requires 1-21 digits for round-trip correctness; initial // scaling will produce a value of up to 4/3 * 2^64 ≈ 2.45e19 (0-20 // digits, regarding 65 bits) at this point. // Float128 requires 1-36 digits; initial scaling can produce a value // up to 4/3 * 2^113 ≈ 1.38e34 (0-35 digits, requiring 114 bits). // Larger than Float128 would likely require more than 256 bit arithmetic. var firstDigit = 8 var nextDigit = firstDigit // Extract the integer part let base10Significand = upperBound.high >> (128 - integerBits) var delta = upperBound & fractionMask let zeros8 = UInt64(0x3030303030303030) let zeros16 = _UInt128( _low: 0x3030303030303030, _high: 0x3030303030303030) let TenE16 = UInt64(10000000000000000) // As noted above, Float128 has at most 35 digits at this point. // Top part is at most 1.38e18, which fits in 64 bits let reciprocal = _UInt128(UInt64(0xe69594bec44de15b)) // ≈ 2^117 / 10^16 let hi19low = (_UInt128(base10Significand._low) * reciprocal) >> 64 let hi19extended = (_UInt128(base10Significand._high) * reciprocal + hi19low) >> 53 var hi19 = UInt64(truncatingIfNeeded: hi19extended) var lo16 = UInt64(truncatingIfNeeded: base10Significand - _UInt128(hi19) * _UInt128(TenE16)) // Correct the two values above... if lo16 >= TenE16 { lo16 -= TenE16 hi19 += 1 } // The above is a faster version of this div/rem pair, which otherwise // accounts for >80% of the total runtime of this function: // let hi19 = UInt64(truncatingIfNeeded: base10Significand / _UInt128(TenE16)) // let lo16 = UInt64(truncatingIfNeeded: base10Significand % _UInt128(TenE16)) let hi3 = UInt32(truncatingIfNeeded: hi19 / TenE16) let digitsHi = _intToEightDecimalDigits(hi3) buffer.storeBytes( of: digitsHi &+ zeros8, toByteOffset: firstDigit, as: UInt64.self) nextDigit &+= 8 let mid16 = UInt64(truncatingIfNeeded: hi19 % TenE16) let digitsMid = _intToSixteenDecimalDigits(mid16) buffer.storeBytes( of: digitsMid &+ zeros16, toByteOffset: nextDigit, as: _UInt128.self) nextDigit &+= 16 let digitsLo = _intToSixteenDecimalDigits(lo16) buffer.storeBytes( of: digitsLo &+ zeros16, toByteOffset: nextDigit, as: _UInt128.self) nextDigit &+= 16 // Trim leading zero digits if digitsHi != 0 { firstDigit &+= digitsHi.trailingZeroBitCount / 8 } else if digitsMid != 0 { firstDigit &+= 8 + digitsMid.trailingZeroBitCount / 8 } else { firstDigit &+= 24 &+ digitsLo.trailingZeroBitCount / 8 } // Step 6: Compute one more decimal digit if necessary if intervalWidth > delta { // Step 6, Case A: Value lies within the interval. // Trim trailing zeros. let trailingZeros: Int if digitsLo != 0 { trailingZeros = digitsLo.leadingZeroBitCount / 8 } else if digitsMid != 0 { trailingZeros = 16 &+ digitsMid.leadingZeroBitCount / 8 } else { trailingZeros = 32 &+ digitsHi.leadingZeroBitCount / 8 } nextDigit &-= trailingZeros base10Power &+= trailingZeros } else { // Step 6, Case B: We need another digit var halfUlp = scaledBinaryUlp halfUlp.multiply(by: UInt32(5)) // delta = delta * 10 - halfUlp delta.multiply(by: UInt32(10)) delta = delta &- halfUlp // intervalWidth = intervalWidth * 10 - halfUlp intervalWidth.multiply(by: UInt32(10)) intervalWidth = intervalWidth &- halfUlp // Extract the next digit var digit = UInt8(truncatingIfNeeded: delta.high >> (128 - integerBits)) delta = delta & fractionMask let epsilon = _UInt256(UInt64(256)) let greater = unsafe unsafeBitCast( delta > (oneHalf &+ epsilon), to: UInt8.self) let greaterOrEqual = unsafe unsafeBitCast( delta > (oneHalf &- epsilon), to: UInt8.self) let outOfInterval = unsafe unsafeBitCast( delta > intervalWidth, to: UInt8.self) digit &+= greater | (greaterOrEqual & digit) | outOfInterval buffer.storeBytes( of: digit &+ 0x30, toByteOffset: nextDigit, as: UInt8.self) nextDigit &+= 1 base10Power &-= 1 } // Step 7: Finish formatting let forceExponential = ((binaryExponent > 1) || (binaryExponent == 1 && !isBoundary)) return _finishFormatting( buffer: &buffer, sign: sign, firstDigit: firstDigit, nextDigit: nextDigit, forceExponential: forceExponential, base10Power: base10Power) } // ================================================================ // // 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 6 unused bytes at the beginning of `buffer` before // `firstDigit` and that all unused bytes are filled with `"0"` (0x30) // characters. fileprivate func _finishFormatting( buffer: inout MutableRawSpan, sign: FloatingPointSign, firstDigit: Int, nextDigit: Int, forceExponential: Bool, base10Power: Int ) -> Range { // 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 var p = base10Power &+ digitCount &- 1 if p < -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 let powerSign: UInt8 if p < 0 { powerSign = 0x2d // "-" p = 0 &- p } else { powerSign = 0x2b // "+" } unsafe buffer.storeBytes( of: powerSign, toUncheckedByteOffset: nextDigit, as: UInt8.self) nextDigit &+= 1 if p > 99 { if p > 999 { let d = asciiDigitTable[p / 100] unsafe buffer.storeBytes( of: d, toUncheckedByteOffset: nextDigit, as: UInt16.self) nextDigit &+= 2 } else { let d = 0x30 &+ UInt8(truncatingIfNeeded: (p / 100)) unsafe buffer.storeBytes( of: d, toUncheckedByteOffset: nextDigit, as: UInt8.self) nextDigit &+= 1 } p = p % 100 } // For historical reasons, exponents are always at least 2 digits let d = unsafe asciiDigitTable[unchecked: p] buffer.storeBytes( of: d, toByteOffset: nextDigit, as: UInt16.self) nextDigit &+= 2 } else if p < 0 { // "-0.000123456789" // We need up to 6 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 &+= p &- 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 p &+ 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...(p &+ 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 &+ p &+ 1, as: UInt8.self) } else { // "12345678900.0" // Fill trailing zeros, put ".0" at the end // so the result is obviously floating-point. // Remember buffer was initialized with "0" nextDigit = firstDigit &+ p &+ 3 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 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 fileprivate func _infinity( buffer: inout MutableRawSpan, sign: FloatingPointSign ) -> Range { 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 } } fileprivate func _zero( buffer: inout MutableRawSpan, sign: FloatingPointSign ) -> Range { 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 } } fileprivate let hexdigits: _InlineArray<16, UInt8> = [ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66 ] // Emit up to 16 hex digits, pruning leading zeros 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 } } // Emit exactly 16 hex digits 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 } } fileprivate func nan_details( buffer: inout MutableRawSpan, sign: FloatingPointSign, quiet: Bool, payloadHigh: UInt64, payloadLow: UInt64 ) -> Range { // 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.. 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) return singles } @inline(__always) fileprivate func _intToSixteenDecimalDigits(_ n: UInt64) -> _UInt128 { let hi8 = n / 100000000 let lo8 = n &- hi8 * 100000000 return _UInt128( _low: _intToEightDecimalDigits(UInt32(truncatingIfNeeded: hi8)), _high: _intToEightDecimalDigits(UInt32(truncatingIfNeeded: lo8)) ) } // ================================================================ // // Arithmetic Helpers // // ================================================================ // Custom 256-bit unsigned integer type, with various arithmetic // helpers as methods. // Used by 80- and 128-bit floating point formatting logic above... 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 } init(_ low: _UInt128) { self.high = 0 self.low = low } init(_ low: UInt64) { self.high = 0 self.low = _UInt128(low) } 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) } // Multiply by a UInt128, // shift 384-bit intermediate value right by the specified amount, and // return the low-order 256 bits mutating func multiply(by rhs: _UInt128, lsr: Int) { // Break into 64-bit components let rhs1 = _UInt128(rhs._high) let rhs0 = _UInt128(rhs._low) let lhs3 = _UInt128(high._high) let lhs2 = _UInt128(high._low) let lhs1 = _UInt128(low._high) let lhs0 = _UInt128(low._low) // Compute cross-products, propagate carries let w0 = rhs0 * lhs0 let w1a = rhs0 * lhs1 let w1b = rhs1 * lhs0 let w1 = (_UInt128(w0._high) + _UInt128(w1a._low) + _UInt128(w1b._low)) let w2a = rhs0 * lhs2 let w2b = rhs1 * lhs1 let w2 = (_UInt128(w1a._high) + _UInt128(w1b._high) + _UInt128(w1._high) + _UInt128(w2a._low) + _UInt128(w2b._low)) let w3a = rhs0 * lhs3 let w3b = rhs1 * lhs2 let w3 = (_UInt128(w2a._high) + _UInt128(w2b._high) + _UInt128(w2._high) + _UInt128(w3a._low) + _UInt128(w3b._low)) let w4 = (_UInt128(w3a._high) + _UInt128(w3b._high) + _UInt128(w3._high) + rhs1 * lhs3) // Discard overhead bits var x0 = w0._low var x1 = w1._low var x2 = w2._low var x3 = w3._low var x4 = w4._low var x5 = w4._high // Shift right by a multiple of 64 bits var shift = lsr while shift >= 64 { x0 = x1 x1 = x2 x2 = x3 x3 = x4 x4 = x5 x5 = 0 shift -= 64 } // Shift the remainder if shift > 0 { x0 = (x0 >> shift) + (x1 << (64 - shift)) x1 = (x1 >> shift) + (x2 << (64 - shift)) x2 = (x2 >> shift) + (x3 << (64 - shift)) x3 = (x3 >> shift) + (x4 << (64 - shift)) // x4 = (x4 >> shift) + (x5 << (64 - shift)) // x5 = (x5 >> shift) } // Keep the low-order 256 bits low = _UInt128(_low: x0, _high: x1) high = _UInt128(_low: x2, _high: x3) } mutating func multiplyHigh(by rhs: _UInt128) { multiply(by: rhs, lsr: 128) } // TODO: Reduce code size here either by rephrasing it // as a nested for loop with additional bookkeeping, or // by recursively using the 256-bit x 128-bit multiplies above. mutating func multiplyHigh(by rhs: _UInt256) { var current = _UInt128(low._low) * _UInt128(rhs.low._low) current = _UInt128(current._high) var t = _UInt128(low._low) &* _UInt128(rhs.low._high) current += _UInt128(t._low) var next = _UInt128(t._high) t = _UInt128(low._high) &* _UInt128(rhs.low._low) current += _UInt128(t._low) next += _UInt128(t._high) current = next + _UInt128(current._high) t = _UInt128(low._low) &* _UInt128(rhs.high._low) current += _UInt128(t._low) next = _UInt128(t._high) t = _UInt128(low._high) &* _UInt128(rhs.low._high) current += _UInt128(t._low) next += _UInt128(t._high) t = _UInt128(high._low) &* _UInt128(rhs.low._low) current += _UInt128(t._low) next += _UInt128(t._high) current = next + _UInt128(current._high) t = _UInt128(low._low) &* _UInt128(rhs.high._high) current += _UInt128(t._low) next = _UInt128(t._high) t = _UInt128(low._high) &* _UInt128(rhs.high._low) current += _UInt128(t._low) next += _UInt128(t._high) t = _UInt128(high._low) &* _UInt128(rhs.low._high) current += _UInt128(t._low) next += _UInt128(t._high) t = _UInt128(high._high) &* _UInt128(rhs.low._low) current += _UInt128(t._low) next += _UInt128(t._high) current = next + _UInt128(current._high) t = _UInt128(low._high) &* _UInt128(rhs.high._high) current += _UInt128(t._low) next = _UInt128(t._high) t = _UInt128(high._low) &* _UInt128(rhs.high._low) current += _UInt128(t._low) next += _UInt128(t._high) t = _UInt128(high._high) &* _UInt128(rhs.low._high) current += _UInt128(t._low) next += _UInt128(t._high) let newlow = current._low current = next + _UInt128(current._high) t = _UInt128(high._low) &* _UInt128(rhs.high._high) current += _UInt128(t._low) next = _UInt128(t._high) t = _UInt128(high._high) &* _UInt128(rhs.high._low) current += _UInt128(t._low) next += _UInt128(t._high) low = _UInt128(_low: newlow, _high: current._low) current = next + _UInt128(current._high) high = current + _UInt128(high._high) &* _UInt128(rhs.high._high) } static func &- (lhs: _UInt256, rhs: _UInt256) -> _UInt256 { var t = _UInt128(lhs.low._low) &+ _UInt128(~rhs.low._low) &+ 1 let w0 = t._low t = _UInt128(t._high) &+ _UInt128(lhs.low._high) &+ _UInt128(~rhs.low._high) let w1 = t._low t = _UInt128(t._high) &+ _UInt128(lhs.high._low) &+ _UInt128(~rhs.high._low) let w2 = t._low let w3 = t._high &+ lhs.high._high &+ ~rhs.high._high return _UInt256(high: w3, w2, w1, low: w0) } static func < (lhs: _UInt256, rhs: _UInt256) -> Bool { return (lhs.high < rhs.high) || (lhs.high == rhs.high && lhs.low < rhs.low) } static func > (lhs: _UInt256, rhs: _UInt256) -> Bool { return rhs < lhs } static func &+ (lhs: _UInt256, rhs: _UInt256) -> _UInt256 { let low = lhs.low &+ rhs.low let carry: _UInt128 = low < lhs.low ? 1 : 0 let high = lhs.high &+ rhs.high &+ carry return _UInt256(high: high, low: low) } // Add a signed int... static func &+= (lhs: inout _UInt256, rhs: Int) { if rhs >= 0 { let r = _UInt128(UInt(rhs)) let newlow = lhs.low &+ r let carry: _UInt128 = newlow < lhs.low ? 1 : 0 lhs.high &+= carry lhs.low = newlow } else { let magnitude = _UInt128(UInt(bitPattern: 0 &- rhs)) let borrow: _UInt128 = lhs.low < magnitude ? 1 : 0 lhs.low &-= magnitude lhs.high &-= borrow } } static func & (lhs: _UInt256, rhs: _UInt256) -> _UInt256 { return _UInt256(high: lhs.high & rhs.high, low: lhs.low & rhs.low) } // Right-shift by 0..<128 bits static func &>> (lhs: _UInt256, rhs: Int) -> _UInt256 { var hi = lhs.high._high var midhi = lhs.high._low var midlo = lhs.low._high var lo = lhs.low._low // Shift by whole 64-bit words first if rhs >= 64 { lo = midlo midlo = midhi midhi = hi hi = 0 } // Shift by remaining bits let r = rhs & 63 if r > 0 { let anti = 64 &- r lo = (lo >> r) | (midlo << anti) midlo = (midlo >> r) | (midhi << anti) midhi = (midhi >> r) | (hi << anti) hi = hi >> r } return _UInt256(high: hi, midhi, midlo, low: lo) } } // ================================================================ // // Powers of 10 // // ================================================================ @inline(__always) fileprivate func _powerOf10_Binary64( p: Int, significand: inout _UInt128 ) -> Int { if p >= 0 && p <= 55 { let upper64 = powersOf10_Exact128[p &* 2 &+ 1] let lower64 = powersOf10_Exact128[p &* 2] significand = _UInt128(_low: lower64, _high: upper64) 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 { significand = _UInt128(_low: baseLow, _high: baseHigh) return baseExponent } else { let extra = powersOf10_Exact128[extraPower &* 2 &+ 1] let high = (_UInt128(truncatingIfNeeded:baseHigh) &* _UInt128(truncatingIfNeeded:extra)) let low = (_UInt128(truncatingIfNeeded:baseLow) &* _UInt128(truncatingIfNeeded:extra) &+ _UInt128(UInt64.max >> 1)) significand = high &+ (low &>> 64) return baseExponent &+ binaryExponentFor10ToThe(extraPower) } } // To keep the supporting table size to a minimum, this // picks a value from each of three tables and multiplies // them together to get a sufficiently-accurate final result. fileprivate func _powerOf10_Binary128( p: Int, significand: inout _UInt256 ) -> Int { if p >= 0 && p <= 55 { let exactLow = powersOf10_Exact128[p * 2] let exactHigh = powersOf10_Exact128[p * 2 + 1] significand = _UInt256(high: exactHigh, exactLow, 0, low: 0) return binaryExponentFor10ToThe(p) } let index = p + 5376 let finePower = index % 56 let mediumPower = index % 896 - finePower let coarsePower = p - mediumPower - finePower let coarseIndex = (index / 896) * 4 let mediumIndex = (mediumPower / 56) * 4 let fineIndex = finePower * 2 significand = _UInt256( high: powersOf10_Binary128_Coarse[coarseIndex + 3], powersOf10_Binary128_Coarse[coarseIndex + 2], powersOf10_Binary128_Coarse[coarseIndex + 1], low: powersOf10_Binary128_Coarse[coarseIndex + 0]) let medium = _UInt256( high: powersOf10_Binary128_Medium[mediumIndex + 3], powersOf10_Binary128_Medium[mediumIndex + 2], powersOf10_Binary128_Medium[mediumIndex + 1], low: powersOf10_Binary128_Medium[mediumIndex + 0]) significand.multiplyHigh(by: medium) let fine = _UInt128( _low: powersOf10_Exact128[fineIndex], _high: powersOf10_Exact128[fineIndex + 1]) significand.multiplyHigh(by: fine) let coarseExponent = binaryExponentFor10ToThe(coarsePower) let mediumExponent = binaryExponentFor10ToThe(mediumPower) let fineExponent = binaryExponentFor10ToThe(finePower) return coarseExponent + mediumExponent + fineExponent } @inline(__always) fileprivate func binaryExponentFor10ToThe(_ p: Int) -> Int { return Int(((Int64(p) &* 55732705) >> 24) &+ 1) } // 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 powersOf10_Binary64 table below says that: // // 0x0.95fe7e07c91efafa3931b850df08e738 x 2^-1328 // // is the result of rounding down the exact binary value of 10^-400 to // 128 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. // ## powersOf10_Float32 // Complete table suitable for Float32 conversion. fileprivate let powersOf10_Float32: _InlineArray<_, UInt64> = [ 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 0x8000000000000000, // x 2^1 == 10^0 exactly 0xa000000000000000, // x 2^4 == 10^1 exactly 0xc800000000000000, // x 2^7 == 10^2 exactly 0xfa00000000000000, // x 2^10 == 10^3 exactly 0x9c40000000000000, // x 2^14 == 10^4 exactly 0xc350000000000000, // x 2^17 == 10^5 exactly 0xf424000000000000, // x 2^20 == 10^6 exactly 0x9896800000000000, // x 2^24 == 10^7 exactly 0xbebc200000000000, // x 2^27 == 10^8 exactly 0xee6b280000000000, // x 2^30 == 10^9 exactly 0x9502f90000000000, // x 2^34 == 10^10 exactly 0xba43b74000000000, // x 2^37 == 10^11 exactly 0xe8d4a51000000000, // x 2^40 == 10^12 exactly 0x9184e72a00000000, // x 2^44 == 10^13 exactly 0xb5e620f480000000, // x 2^47 == 10^14 exactly 0xe35fa931a0000000, // x 2^50 == 10^15 exactly 0x8e1bc9bf04000000, // x 2^54 == 10^16 exactly 0xb1a2bc2ec5000000, // x 2^57 == 10^17 exactly 0xde0b6b3a76400000, // x 2^60 == 10^18 exactly 0x8ac7230489e80000, // x 2^64 == 10^19 exactly 0xad78ebc5ac620000, // x 2^67 == 10^20 exactly 0xd8d726b7177a8000, // x 2^70 == 10^21 exactly 0x878678326eac9000, // x 2^74 == 10^22 exactly 0xa968163f0a57b400, // x 2^77 == 10^23 exactly 0xd3c21bcecceda100, // x 2^80 == 10^24 exactly 0x84595161401484a0, // x 2^84 == 10^25 exactly 0xa56fa5b99019a5c8, // x 2^87 == 10^26 exactly 0xcecb8f27f4200f3a, // x 2^90 == 10^27 exactly 0x813f3978f8940984, // x 2^94 ~= 10^28 0xa18f07d736b90be5, // x 2^97 ~= 10^29 0xc9f2c9cd04674ede, // x 2^100 ~= 10^30 0xfc6f7c4045812296, // x 2^103 ~= 10^31 0x9dc5ada82b70b59d, // x 2^107 ~= 10^32 0xc5371912364ce305, // x 2^110 ~= 10^33 0xf684df56c3e01bc6, // x 2^113 ~= 10^34 0x9a130b963a6c115c, // x 2^117 ~= 10^35 0xc097ce7bc90715b3, // x 2^120 ~= 10^36 0xf0bdc21abb48db20, // x 2^123 ~= 10^37 0x96769950b50d88f4, // x 2^127 ~= 10^38 0xbc143fa4e250eb31, // x 2^130 ~= 10^39 0xeb194f8e1ae525fd, // x 2^133 ~= 10^40 0x92efd1b8d0cf37be, // x 2^137 ~= 10^41 0xb7abc627050305ad, // x 2^140 ~= 10^42 0xe596b7b0c643c719, // x 2^143 ~= 10^43 0x8f7e32ce7bea5c6f, // x 2^147 ~= 10^44 0xb35dbf821ae4f38b, // x 2^150 ~= 10^45 0xe0352f62a19e306e, // x 2^153 ~= 10^46 0x8c213d9da502de45, // x 2^157 ~= 10^47 0xaf298d050e4395d6, // x 2^160 ~= 10^48 0xdaf3f04651d47b4c, // x 2^163 ~= 10^49 0x88d8762bf324cd0f, // x 2^167 ~= 10^50 ] // ## powersOf10_Exact128 // 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 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 support. // Table size: 896 bytes 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 ] // ## powersOf10_Binary64 // 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 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 ] // ## powersOf10_Binary128 // Needed by 80-bit formatter. This is sufficient precision // to support a future Float128 implementation if anyone's interested. // Total table size: 512 + 384 = 896 bytes // Table size: 512 bytes fileprivate let powersOf10_Binary128_Medium: _InlineArray<_, UInt64> = [ 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 ] // Table size: 12 * 32 = 384 bytes fileprivate let powersOf10_Binary128_Coarse: _InlineArray<_, UInt64> = [ 0x9f855c9864e639d5, 0x257261546827afab, 0xeddb8bd5b1dd7ed8, 0x9f2f658cea3b24bc, // x 2^-17858 ~= 10^-5376 0xdadd9645f360cb51, 0xf290163350ecb3eb, 0xa8edffdccfe4db4b, 0xd9167ab0c1965798, // x 2^-14882 ~= 10^-4480 0x982b64e953ac4e27, 0x45efb05f20cf48b3, 0x4b4de34e0ebc3e06, 0x9406af8f83fd6265, // x 2^-11905 ~= 10^-3584 0x42032f9f971bfc07, 0x9fb576046ab35018, 0x474b3cb1fe1d6a7f, 0xc9dea80d6283a34c, // x 2^-8929 ~= 10^-2688 0xb62593291c768919, 0xc098e6ed0bfbd6f6, 0x6c83ad1260ff20f4, 0x89a63ba4c497b50e, // x 2^-5952 ~= 10^-1792 0x276e3f0f67f0553b, 0x00de73d9d5be6974, 0x6d4aa5b50bb5dc0d, 0xbbb7ef38bb827f2d, // x 2^-2976 ~= 10^-896 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x8000000000000000, // x 2^1 == 10^0 exactly 0xf48b51375df06e86, 0x412fe9e72afd355e, 0x870a8d87239d8f35, 0xae8f2b2ce3d5dbe9, // x 2^2977 ~= 10^896 0xbf34ff7963028cd9, 0xc20578fa3851488b, 0x2d4070f33b21ab7b, 0xee0ddd84924ab88c, // x 2^5953 ~= 10^1792 0x8cd036553f38a1e8, 0x5e997e9f45d7897d, 0xf09e780bcc8238d9, 0xa2528e74eaf101fc, // x 2^8930 ~= 10^2688 0x134ca67a679b84ae, 0x8909e424a112a3cd, 0x95aa118ec1d08317, 0xdd5dc8a2bf27f3f7, // x 2^11906 ~= 10^3584 0x0f7740145246fb8f, 0x186ef2c39acb4103, 0x888c9ab2fc5b3437, 0x96f18b1742aad751, // x 2^14883 ~= 10^4480 ]