mirror of
https://github.com/apple/swift.git
synced 2026-10-30 22:15:52 +01:00
Historically Swift rounded this value toward zero to preserve the range invariant that the rounded result was in [0,π]. The 754 working group has provided some guidance that they think getting the most accurate value is more important than trying to satisfy such invariants, so we will change our guidance to implementors, and the specific value of Float.pi to match. Implements [SE-0552](https://github.com/swiftlang/swift/pull/92206)
1129 lines
33 KiB
Swift
1129 lines
33 KiB
Swift
//===--- Float.swift ------------------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SwiftShims
|
|
|
|
@frozen
|
|
public struct Float {
|
|
public // @testable
|
|
var _value: Builtin.FPIEEE32
|
|
|
|
@_transparent
|
|
public init() {
|
|
self._value = Builtin.zeroInitializer()
|
|
}
|
|
|
|
@_transparent
|
|
public // @testable
|
|
init(_ _value: Builtin.FPIEEE32) {
|
|
self._value = _value
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: CustomStringConvertible {
|
|
/// A textual representation of the value.
|
|
///
|
|
/// For any finite value, this property provides a string that can be
|
|
/// converted back to an instance of `Float` without rounding errors. That
|
|
/// is, if `x` is an instance of `Float`, then `Float(x.description) ==
|
|
/// x` is always true. For any NaN value, the property's value is "nan", and
|
|
/// for positive and negative infinity its value is "inf" and "-inf".
|
|
public var description: String {
|
|
if isNaN {
|
|
return "nan"
|
|
} else {
|
|
return debugDescription
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: CustomDebugStringConvertible {
|
|
/// A textual representation of the value, suitable for debugging.
|
|
///
|
|
/// This property has the same value as the `description` property, except
|
|
/// that NaN values are printed in an extended format.
|
|
public var debugDescription: String {
|
|
var buffer = _InlineArray<32, UTF8.CodeUnit>(repeating: 0x30)
|
|
var span = buffer.mutableSpan
|
|
let textRange = _Float32ToASCII(value: self, buffer: &span)
|
|
let ascii = unsafe buffer.span.extracting(unchecked: textRange)
|
|
return ascii.withUnsafeBufferPointer {
|
|
unsafe String._fromASCII($0)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: TextOutputStreamable {
|
|
public func write<Target>(to target: inout Target) where Target: TextOutputStream {
|
|
if isNaN {
|
|
// Match `description`.
|
|
target.write("nan")
|
|
return
|
|
}
|
|
var buffer = _InlineArray<32, UTF8.CodeUnit>(repeating: 0x30)
|
|
var span = buffer.mutableSpan
|
|
let textRange = _Float32ToASCII(value: self, buffer: &span)
|
|
let ascii = unsafe buffer.span.extracting(unchecked: textRange)
|
|
return ascii.withUnsafeBufferPointer {
|
|
unsafe target._writeASCII($0)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: BinaryFloatingPoint {
|
|
|
|
// Floating-point types are always symmetric, so Magnitude is Self.
|
|
public typealias Magnitude = Float
|
|
|
|
public typealias Exponent = Int
|
|
|
|
public typealias RawSignificand = UInt32
|
|
|
|
@inlinable
|
|
public static var exponentBitCount: Int {
|
|
return 8
|
|
}
|
|
|
|
@inlinable
|
|
public static var significandBitCount: Int {
|
|
return 23
|
|
}
|
|
|
|
// Implementation details.
|
|
@inlinable // FIXME(inline-always) was usableFromInline
|
|
internal static var _infinityExponent: UInt {
|
|
@inline(__always) get { return 1 &<< UInt(exponentBitCount) - 1 }
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always) was usableFromInline
|
|
internal static var _exponentBias: UInt {
|
|
@inline(__always) get { return _infinityExponent &>> 1 }
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always) was usableFromInline
|
|
internal static var _significandMask: UInt32 {
|
|
@inline(__always) get {
|
|
return 1 &<< UInt32(significandBitCount) - 1
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always) was usableFromInline
|
|
internal static var _quietNaNMask: UInt32 {
|
|
@inline(__always) get {
|
|
return 1 &<< UInt32(significandBitCount - 1)
|
|
}
|
|
}
|
|
|
|
// Conversions to/from integer encoding. These are not part of the
|
|
// BinaryFloatingPoint prototype because there's no guarantee that an
|
|
// integer type of the same size actually exists (e.g. Float80).
|
|
//
|
|
// If we want them in a protocol at some future point, that protocol should
|
|
// be "InterchangeFloatingPoint" or "PortableFloatingPoint" or similar, and
|
|
// apply to IEEE 754 "interchange types".
|
|
/// The bit pattern of the value's encoding.
|
|
///
|
|
/// The bit pattern matches the binary interchange format defined by the
|
|
/// [IEEE 754 specification][spec].
|
|
///
|
|
/// [spec]: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
|
|
@inlinable
|
|
public var bitPattern: UInt32 {
|
|
return UInt32(Builtin.bitcast_FPIEEE32_Int32(_value))
|
|
}
|
|
|
|
/// Creates a new value with the given bit pattern.
|
|
///
|
|
/// The value passed as `bitPattern` is interpreted in the binary interchange
|
|
/// format defined by the [IEEE 754 specification][spec].
|
|
///
|
|
/// [spec]: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
|
|
///
|
|
/// - Parameter bitPattern: The integer encoding of a `Float` instance.
|
|
@inlinable
|
|
public init(bitPattern: UInt32) {
|
|
self.init(Builtin.bitcast_Int32_FPIEEE32(bitPattern._value))
|
|
}
|
|
|
|
@inlinable
|
|
public var sign: FloatingPointSign {
|
|
let shift = Float.significandBitCount + Float.exponentBitCount
|
|
return FloatingPointSign(
|
|
rawValue: Int(bitPattern &>> UInt32(shift))
|
|
)!
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "sign")
|
|
public var isSignMinus: Bool { Builtin.unreachable() }
|
|
|
|
@inlinable
|
|
public var exponentBitPattern: UInt {
|
|
return UInt(bitPattern &>> UInt32(Float.significandBitCount)) &
|
|
Float._infinityExponent
|
|
}
|
|
|
|
@inlinable
|
|
public var significandBitPattern: UInt32 {
|
|
return UInt32(bitPattern) & Float._significandMask
|
|
}
|
|
|
|
@inlinable
|
|
public init(
|
|
sign: FloatingPointSign,
|
|
exponentBitPattern: UInt,
|
|
significandBitPattern: UInt32
|
|
) {
|
|
let signShift = Float.significandBitCount + Float.exponentBitCount
|
|
let sign = UInt32(sign == .minus ? 1 : 0)
|
|
let exponent = UInt32(
|
|
exponentBitPattern & Float._infinityExponent
|
|
)
|
|
let significand = UInt32(
|
|
significandBitPattern & Float._significandMask
|
|
)
|
|
self.init(bitPattern:
|
|
sign &<< UInt32(signShift) |
|
|
exponent &<< UInt32(Float.significandBitCount) |
|
|
significand
|
|
)
|
|
}
|
|
|
|
@inlinable
|
|
public var isCanonical: Bool {
|
|
// All Float and Double encodings are canonical in IEEE 754.
|
|
//
|
|
// On platforms that do not support subnormals, we treat them as
|
|
// non-canonical encodings of zero.
|
|
if Self.leastNonzeroMagnitude == Self.leastNormalMagnitude {
|
|
if exponentBitPattern == 0 && significandBitPattern != 0 {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
@inlinable
|
|
public static var infinity: Float {
|
|
return Float(bitPattern: 0x7f800000)
|
|
}
|
|
|
|
@inlinable
|
|
public static var nan: Float {
|
|
return Float(bitPattern: 0x7fc00000)
|
|
}
|
|
|
|
@inlinable
|
|
public static var signalingNaN: Float {
|
|
return Float(nan: 0, signaling: true)
|
|
}
|
|
|
|
@available(*, unavailable, renamed: "nan")
|
|
public static var quietNaN: Float { Builtin.unreachable() }
|
|
|
|
@inlinable
|
|
public static var greatestFiniteMagnitude: Float {
|
|
return 0x1.fffffep127
|
|
}
|
|
|
|
@inlinable
|
|
public static var pi: Float {
|
|
// Note: in standard library versions prior to 6.5, this value was rounded
|
|
// toward zero (0x1.921fb4p1) instead of to nearest. The change in value
|
|
// was approved under SE-0552 Rounding of `Float.pi`.
|
|
return 0x1.921fb6p1
|
|
}
|
|
|
|
@inlinable
|
|
public var ulp: Float {
|
|
guard _fastPath(isFinite) else { return .nan }
|
|
if _fastPath(isNormal) {
|
|
let bitPattern_ = bitPattern & Float.infinity.bitPattern
|
|
return Float(bitPattern: bitPattern_) * 0x1p-23
|
|
}
|
|
// On arm, flush subnormal values to 0.
|
|
return .leastNormalMagnitude * 0x1p-23
|
|
}
|
|
|
|
@inlinable
|
|
public static var leastNormalMagnitude: Float {
|
|
return 0x1.0p-126
|
|
}
|
|
|
|
@inlinable
|
|
public static var leastNonzeroMagnitude: Float {
|
|
#if arch(arm)
|
|
// On 32b arm, the default FPCR has subnormals flushed to zero.
|
|
return leastNormalMagnitude
|
|
#else
|
|
return leastNormalMagnitude * ulpOfOne
|
|
#endif
|
|
}
|
|
|
|
/// The unit in the last place of 1.0.
|
|
///
|
|
/// The positive difference between 1.0 and the next greater representable
|
|
/// number. The `ulpOfOne` constant corresponds to the C macros
|
|
/// `FLT_EPSILON`, `DBL_EPSILON`, and others with a similar purpose.
|
|
@inlinable
|
|
public static var ulpOfOne: Float {
|
|
return 0x1.0p-23
|
|
}
|
|
|
|
@inlinable
|
|
@_semantics("optimize.sil.inline.constant.arguments")
|
|
public var exponent: Int {
|
|
if !isFinite { return .max }
|
|
if isZero { return .min }
|
|
let provisional = Int(exponentBitPattern) - Int(Float._exponentBias)
|
|
if isNormal { return provisional }
|
|
let shift =
|
|
Float.significandBitCount - significandBitPattern._binaryLogarithm()
|
|
return provisional + 1 - shift
|
|
}
|
|
|
|
@inlinable
|
|
public var significand: Float {
|
|
if isNaN { return self }
|
|
if isNormal {
|
|
return Float(sign: .plus,
|
|
exponentBitPattern: Float._exponentBias,
|
|
significandBitPattern: significandBitPattern)
|
|
}
|
|
if isSubnormal {
|
|
let shift =
|
|
Float.significandBitCount - significandBitPattern._binaryLogarithm()
|
|
return Float(
|
|
sign: .plus,
|
|
exponentBitPattern: Float._exponentBias,
|
|
significandBitPattern: significandBitPattern &<< shift
|
|
)
|
|
}
|
|
// zero or infinity.
|
|
return Float(
|
|
sign: .plus,
|
|
exponentBitPattern: exponentBitPattern,
|
|
significandBitPattern: 0
|
|
)
|
|
}
|
|
|
|
@inlinable
|
|
public init(sign: FloatingPointSign, exponent: Int, significand: Float) {
|
|
var result = significand
|
|
if sign == .minus { result = -result }
|
|
if significand.isFinite && !significand.isZero {
|
|
var clamped = exponent
|
|
let leastNormalExponent = 1 - Int(Float._exponentBias)
|
|
let greatestFiniteExponent = Int(Float._exponentBias)
|
|
if clamped < leastNormalExponent {
|
|
clamped = max(clamped, 3*leastNormalExponent)
|
|
while clamped < leastNormalExponent {
|
|
result *= Float.leastNormalMagnitude
|
|
clamped -= leastNormalExponent
|
|
}
|
|
}
|
|
else if clamped > greatestFiniteExponent {
|
|
clamped = min(clamped, 3*greatestFiniteExponent)
|
|
let step = Float(sign: .plus,
|
|
exponentBitPattern: Float._infinityExponent - 1,
|
|
significandBitPattern: 0)
|
|
while clamped > greatestFiniteExponent {
|
|
result *= step
|
|
clamped -= greatestFiniteExponent
|
|
}
|
|
}
|
|
let scale = Float(
|
|
sign: .plus,
|
|
exponentBitPattern: UInt(Int(Float._exponentBias) + clamped),
|
|
significandBitPattern: 0
|
|
)
|
|
result = result * scale
|
|
}
|
|
self = result
|
|
}
|
|
|
|
/// Creates a NaN ("not a number") value with the specified payload.
|
|
///
|
|
/// NaN values compare not equal to every value, including themselves. Most
|
|
/// operations with a NaN operand produce a NaN result. Don't use the
|
|
/// equal-to operator (`==`) to test whether a value is NaN. Instead, use
|
|
/// the value's `isNaN` property.
|
|
///
|
|
/// let x = Float(nan: 0, signaling: false)
|
|
/// print(x == .nan)
|
|
/// // Prints "false"
|
|
/// print(x.isNaN)
|
|
/// // Prints "true"
|
|
///
|
|
/// - Parameters:
|
|
/// - payload: The payload to use for the new NaN value.
|
|
/// - signaling: Pass `true` to create a signaling NaN or `false` to create
|
|
/// a quiet NaN.
|
|
@inlinable
|
|
public init(nan payload: RawSignificand, signaling: Bool) {
|
|
// We use significandBitCount - 2 bits for NaN payload.
|
|
_precondition(payload < (Float._quietNaNMask &>> 1),
|
|
"NaN payload is not encodable.")
|
|
var significand = payload
|
|
significand |= Float._quietNaNMask &>> (signaling ? 1 : 0)
|
|
self.init(
|
|
sign: .plus,
|
|
exponentBitPattern: Float._infinityExponent,
|
|
significandBitPattern: significand
|
|
)
|
|
}
|
|
|
|
@inlinable
|
|
public var nextUp: Float {
|
|
// Silence signaling NaNs, map -0 to +0.
|
|
let x = self + 0
|
|
#if arch(arm)
|
|
// On arm, treat subnormal values as zero.
|
|
if _slowPath(x == 0) { return .leastNonzeroMagnitude }
|
|
if _slowPath(x == -.leastNonzeroMagnitude) { return -0.0 }
|
|
#endif
|
|
if _fastPath(x < .infinity) {
|
|
let increment = Int32(bitPattern: x.bitPattern) &>> 31 | 1
|
|
let bitPattern_ = x.bitPattern &+ UInt32(bitPattern: increment)
|
|
return Float(bitPattern: bitPattern_)
|
|
}
|
|
return x
|
|
}
|
|
|
|
// For core standard library floating-point types, LLVM can lower copysign
|
|
// for us; this gets somewhat better codegen than the generic implementation,
|
|
// but more importantly allows it to participate in other optimizations
|
|
// at the LLVM level.
|
|
@_transparent
|
|
public init(signOf sign: Float, magnitudeOf mag: Float) {
|
|
_value = Builtin.int_copysign_FPIEEE32(mag._value, sign._value)
|
|
}
|
|
|
|
@_transparent
|
|
public mutating func round(_ rule: FloatingPointRoundingRule) {
|
|
switch rule {
|
|
case .toNearestOrAwayFromZero:
|
|
_value = Builtin.int_round_FPIEEE32(_value)
|
|
case .toNearestOrEven:
|
|
_value = Builtin.int_rint_FPIEEE32(_value)
|
|
case .towardZero:
|
|
_value = Builtin.int_trunc_FPIEEE32(_value)
|
|
case .awayFromZero:
|
|
if sign == .minus {
|
|
_value = Builtin.int_floor_FPIEEE32(_value)
|
|
}
|
|
else {
|
|
_value = Builtin.int_ceil_FPIEEE32(_value)
|
|
}
|
|
case .up:
|
|
_value = Builtin.int_ceil_FPIEEE32(_value)
|
|
case .down:
|
|
_value = Builtin.int_floor_FPIEEE32(_value)
|
|
#if !$Embedded
|
|
@unknown default:
|
|
self._roundSlowPath(rule)
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Slow path for new cases that might have been inlined into an old
|
|
// ABI-stable version of round(_:) called from a newer version. If this is
|
|
// the case, this non-inlinable function will call into the _newer_ version
|
|
// which _will_ support this rounding rule.
|
|
@usableFromInline
|
|
internal mutating func _roundSlowPath(_ rule: FloatingPointRoundingRule) {
|
|
self.round(rule)
|
|
}
|
|
|
|
@_transparent
|
|
public mutating func negate() {
|
|
_value = Builtin.fneg_FPIEEE32(self._value)
|
|
}
|
|
|
|
@_transparent
|
|
public static func +=(lhs: inout Float, rhs: Float) {
|
|
lhs._value = Builtin.fadd_FPIEEE32(lhs._value, rhs._value)
|
|
}
|
|
|
|
@_transparent
|
|
public static func -=(lhs: inout Float, rhs: Float) {
|
|
lhs._value = Builtin.fsub_FPIEEE32(lhs._value, rhs._value)
|
|
}
|
|
|
|
@_transparent
|
|
public static func *=(lhs: inout Float, rhs: Float) {
|
|
lhs._value = Builtin.fmul_FPIEEE32(lhs._value, rhs._value)
|
|
}
|
|
|
|
@_transparent
|
|
public static func /=(lhs: inout Float, rhs: Float) {
|
|
lhs._value = Builtin.fdiv_FPIEEE32(lhs._value, rhs._value)
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public mutating func formRemainder(dividingBy other: Float) {
|
|
self = _stdlib_remainderf(self, other)
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public mutating func formTruncatingRemainder(dividingBy other: Float) {
|
|
_value = Builtin.frem_FPIEEE32(self._value, other._value)
|
|
}
|
|
|
|
@_transparent
|
|
public mutating func formSquareRoot( ) {
|
|
_value = Builtin.int_sqrt_FPIEEE32(_value)
|
|
}
|
|
|
|
@_transparent
|
|
public mutating func addProduct(_ lhs: Float, _ rhs: Float) {
|
|
_value = Builtin.int_fma_FPIEEE32(lhs._value, rhs._value, _value)
|
|
}
|
|
|
|
@_transparent
|
|
public func isEqual(to other: Float) -> Bool {
|
|
return Bool(Builtin.fcmp_oeq_FPIEEE32(self._value, other._value))
|
|
}
|
|
|
|
@_transparent
|
|
public func isLess(than other: Float) -> Bool {
|
|
return Bool(Builtin.fcmp_olt_FPIEEE32(self._value, other._value))
|
|
}
|
|
|
|
@_transparent
|
|
public func isLessThanOrEqualTo(_ other: Float) -> Bool {
|
|
return Bool(Builtin.fcmp_ole_FPIEEE32(self._value, other._value))
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isNormal: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return exponentBitPattern > 0 && isFinite
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isFinite: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return exponentBitPattern < Float._infinityExponent
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isZero: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return exponentBitPattern == 0 && significandBitPattern == 0
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isSubnormal: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return exponentBitPattern == 0 && significandBitPattern != 0
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isInfinite: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return !isFinite && significandBitPattern == 0
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isNaN: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return !isFinite && significandBitPattern != 0
|
|
}
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
public var isSignalingNaN: Bool {
|
|
@inline(__always)
|
|
get {
|
|
return isNaN && (significandBitPattern & Float._quietNaNMask) == 0
|
|
}
|
|
}
|
|
|
|
@inlinable
|
|
public var binade: Float {
|
|
guard _fastPath(isFinite) else { return .nan }
|
|
#if !arch(arm)
|
|
if _slowPath(isSubnormal) {
|
|
let bitPattern_ =
|
|
(self * 0x1p23).bitPattern
|
|
& (-Float.infinity).bitPattern
|
|
return Float(bitPattern: bitPattern_) * 0x1p-23
|
|
}
|
|
#endif
|
|
return Float(bitPattern: bitPattern & (-Float.infinity).bitPattern)
|
|
}
|
|
|
|
@inlinable
|
|
@_semantics("optimize.sil.inline.constant.arguments")
|
|
public var significandWidth: Int {
|
|
let trailingZeroBits = significandBitPattern.trailingZeroBitCount
|
|
if isNormal {
|
|
guard significandBitPattern != 0 else { return 0 }
|
|
return Float.significandBitCount &- trailingZeroBits
|
|
}
|
|
if isSubnormal {
|
|
let leadingZeroBits = significandBitPattern.leadingZeroBitCount
|
|
return UInt32.bitWidth &- (trailingZeroBits &+ leadingZeroBits &+ 1)
|
|
}
|
|
return -1
|
|
}
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init(floatLiteral value: Float) {
|
|
self = value
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: _ExpressibleByBuiltinIntegerLiteral, ExpressibleByIntegerLiteral {
|
|
@_transparent
|
|
public
|
|
init(_builtinIntegerLiteral value: Builtin.IntLiteral){
|
|
self = Float(Builtin.itofp_with_overflow_IntLiteral_FPIEEE32(value))
|
|
}
|
|
|
|
@_transparent
|
|
public init(integerLiteral value: Int64) {
|
|
self = Float(Builtin.sitofp_Int64_FPIEEE32(value._value))
|
|
}
|
|
}
|
|
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !os(anyAppleOS))) && (arch(i386) || arch(x86_64))
|
|
|
|
|
|
extension Float: _ExpressibleByBuiltinFloatLiteral {
|
|
@_transparent
|
|
public
|
|
init(_builtinFloatLiteral value: Builtin.FPIEEE80) {
|
|
self = Float(Builtin.fptrunc_FPIEEE80_FPIEEE32(value))
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
|
|
extension Float: _ExpressibleByBuiltinFloatLiteral {
|
|
@_transparent
|
|
public
|
|
init(_builtinFloatLiteral value: Builtin.FPIEEE64) {
|
|
// FIXME: This can result in double rounding errors (https://github.com/apple/swift/issues/49672).
|
|
self = Float(Builtin.fptrunc_FPIEEE64_FPIEEE32(value))
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
extension Float: Hashable {
|
|
@inlinable
|
|
public func hash(into hasher: inout Hasher) {
|
|
var v = self
|
|
if isZero {
|
|
// To satisfy the axiom that equality implies hash equality, we need to
|
|
// finesse the hash value of -0.0 to match +0.0.
|
|
v = 0
|
|
}
|
|
hasher.combine(v.bitPattern)
|
|
}
|
|
|
|
@inlinable
|
|
public func _rawHashValue(seed: Int) -> Int {
|
|
// To satisfy the axiom that equality implies hash equality, we need to
|
|
// finesse the hash value of -0.0 to match +0.0.
|
|
let v = isZero ? 0 : self
|
|
return Hasher._hash(seed: seed, bytes: UInt64(v.bitPattern), count: 4)
|
|
}
|
|
}
|
|
|
|
@_unavailableInEmbedded
|
|
extension Float: _HasCustomAnyHashableRepresentation {
|
|
// Not @inlinable
|
|
public func _toCustomAnyHashable() -> AnyHashable? {
|
|
return AnyHashable(_box: _FloatAnyHashableBox(self))
|
|
}
|
|
}
|
|
|
|
|
|
extension Float {
|
|
@inlinable // FIXME(inline-always)
|
|
public var magnitude: Float {
|
|
@inline(__always)
|
|
get {
|
|
return Float(Builtin.int_fabs_FPIEEE32(_value))
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extension Float {
|
|
@_transparent
|
|
public static prefix func - (x: Float) -> Float {
|
|
return Float(Builtin.fneg_FPIEEE32(x._value))
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: Sendable { }
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Explicit conversions between types.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Construction from other concrete types.
|
|
|
|
extension Float {
|
|
@_transparent
|
|
public init(_ v: Int) {
|
|
#if _pointerBitWidth(_64)
|
|
_value = Builtin.sitofp_Int64_FPIEEE32(v._value)
|
|
#elseif _pointerBitWidth(_32)
|
|
_value = Builtin.sitofp_Int32_FPIEEE32(v._value)
|
|
#else
|
|
_value = Builtin.sitofp_Int16_FPIEEE32(v._value)
|
|
#endif
|
|
}
|
|
|
|
// Fast-path for conversion when the source is representable as int,
|
|
// falling back on the generic _convert operation otherwise.
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init<Source: BinaryInteger>(_ value: Source) {
|
|
if value.bitWidth <= 64 {
|
|
if Source.isSigned {
|
|
let asInt = Int64(truncatingIfNeeded: value)
|
|
_value = Builtin.sitofp_Int64_FPIEEE32(asInt._value)
|
|
} else {
|
|
let asUInt = UInt64(truncatingIfNeeded: value)
|
|
_value = Builtin.uitofp_Int64_FPIEEE32(asUInt._value)
|
|
}
|
|
} else {
|
|
// TODO: we can do much better than the generic _convert here for Float
|
|
// and Double by pulling out the high-order 32/64b of the integer, ORing
|
|
// in a sticky bit, and then using the builtin.
|
|
self = Float._convert(from: value).value
|
|
}
|
|
}
|
|
|
|
// Fast-path for conversion when the source is representable as int,
|
|
// falling back on the generic _convert operation otherwise.
|
|
@export(implementation) @inline(never)
|
|
public init?<Source: BinaryInteger>(exactly value: Source) {
|
|
if value.bitWidth <= 64 {
|
|
// If the source is small enough to fit in a word, we can use the LLVM
|
|
// conversion intrinsic, then check if we can round-trip back to the
|
|
// the original value; if so, the conversion was exact. We need to be
|
|
// careful, however, to make sure that the first conversion does not
|
|
// round to a value that is out of the defined range of the second
|
|
// conversion. E.g. Float(Int.max) rounds to Int.max + 1, and converting
|
|
// that back to Int will trap. For Float, Double, and Float80, this is
|
|
// only an issue for the upper bound (because the lower bound of [U]Int
|
|
// is either zero or a power of two, both of which are exactly
|
|
// representable). For Float16, we also need to check for overflow to
|
|
// -.infinity.
|
|
if Source.isSigned {
|
|
let extended = Int64(truncatingIfNeeded: value)
|
|
_value = Builtin.sitofp_Int64_FPIEEE32(extended._value)
|
|
guard self < 0x1.0p63 && Int(self) == extended else {
|
|
return nil
|
|
}
|
|
} else {
|
|
let extended = UInt64(truncatingIfNeeded: value)
|
|
_value = Builtin.uitofp_Int64_FPIEEE32(extended._value)
|
|
guard self < 0x1.0p64 && UInt(self) == extended else {
|
|
return nil
|
|
}
|
|
}
|
|
} else {
|
|
// TODO: we can do much better than the generic _convert here for Float
|
|
// and Double by pulling out the high-order 32/64b of the integer, ORing
|
|
// in a sticky bit, and then using the builtin.
|
|
let (value_, exact) = Self._convert(from: value)
|
|
guard exact else { return nil }
|
|
self = value_
|
|
}
|
|
}
|
|
|
|
|
|
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
|
|
|
|
/// Creates a new instance that approximates the given value.
|
|
///
|
|
/// The value of `other` is rounded to a representable value, if necessary.
|
|
/// A NaN passed as `other` results in another NaN, with a signaling NaN
|
|
/// value converted to quiet NaN.
|
|
///
|
|
/// let x: Float16 = 21.25
|
|
/// let y = Float(x)
|
|
/// // y == 21.25
|
|
///
|
|
/// let z = Float(Float16.nan)
|
|
/// // z.isNaN == true
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
@available(SwiftStdlib 5.3, *)
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init(_ other: Float16) {
|
|
_value = Builtin.fpext_FPIEEE16_FPIEEE32(other._value)
|
|
}
|
|
|
|
/// Creates a new instance initialized to the given value, if it can be
|
|
/// represented without rounding.
|
|
///
|
|
/// If `other` can't be represented as an instance of `Float` without
|
|
/// rounding, the result of this initializer is `nil`. In particular,
|
|
/// passing NaN as `other` always results in `nil`.
|
|
///
|
|
/// let x: Float16 = 21.25
|
|
/// let y = Float(exactly: x)
|
|
/// // y == Optional.some(21.25)
|
|
///
|
|
/// let z = Float(exactly: Float16.nan)
|
|
/// // z == nil
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
@available(SwiftStdlib 5.3, *)
|
|
@inlinable
|
|
@inline(__always)
|
|
public init?(exactly other: Float16) {
|
|
self.init(other)
|
|
// Converting the infinity value is considered value preserving.
|
|
// In other cases, check that we can round-trip and get the same value.
|
|
// NaN always fails.
|
|
if Float16(self) != other {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/// Creates a new instance initialized to the given value.
|
|
///
|
|
/// The value of `other` is represented exactly by the new instance. A NaN
|
|
/// passed as `other` results in another NaN, with a signaling NaN value
|
|
/// converted to quiet NaN.
|
|
///
|
|
/// let x: Float = 21.25
|
|
/// let y = Float(x)
|
|
/// // y == 21.25
|
|
///
|
|
/// let z = Float(Float.nan)
|
|
/// // z.isNaN == true
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init(_ other: Float) {
|
|
_value = other._value
|
|
}
|
|
|
|
/// Creates a new instance initialized to the given value, if it can be
|
|
/// represented without rounding.
|
|
///
|
|
/// If `other` can't be represented as an instance of `Float` without
|
|
/// rounding, the result of this initializer is `nil`. In particular,
|
|
/// passing NaN as `other` always results in `nil`.
|
|
///
|
|
/// let x: Float = 21.25
|
|
/// let y = Float(exactly: x)
|
|
/// // y == Optional.some(21.25)
|
|
///
|
|
/// let z = Float(exactly: Float.nan)
|
|
/// // z == nil
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
public init?(exactly other: Float) {
|
|
self.init(other)
|
|
// Converting the infinity value is considered value preserving.
|
|
// In other cases, check that we can round-trip and get the same value.
|
|
// NaN always fails.
|
|
if Float(self) != other {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new instance that approximates the given value.
|
|
///
|
|
/// The value of `other` is rounded to a representable value, if necessary.
|
|
/// A NaN passed as `other` results in another NaN, with a signaling NaN
|
|
/// value converted to quiet NaN.
|
|
///
|
|
/// let x: Double = 21.25
|
|
/// let y = Float(x)
|
|
/// // y == 21.25
|
|
///
|
|
/// let z = Float(Double.nan)
|
|
/// // z.isNaN == true
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init(_ other: Double) {
|
|
_value = Builtin.fptrunc_FPIEEE64_FPIEEE32(other._value)
|
|
}
|
|
|
|
/// Creates a new instance initialized to the given value, if it can be
|
|
/// represented without rounding.
|
|
///
|
|
/// If `other` can't be represented as an instance of `Float` without
|
|
/// rounding, the result of this initializer is `nil`. In particular,
|
|
/// passing NaN as `other` always results in `nil`.
|
|
///
|
|
/// let x: Double = 21.25
|
|
/// let y = Float(exactly: x)
|
|
/// // y == Optional.some(21.25)
|
|
///
|
|
/// let z = Float(exactly: Double.nan)
|
|
/// // z == nil
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
public init?(exactly other: Double) {
|
|
self.init(other)
|
|
// Converting the infinity value is considered value preserving.
|
|
// In other cases, check that we can round-trip and get the same value.
|
|
// NaN always fails.
|
|
if Double(self) != other {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
#if !(os(Windows) || os(Android) || ($Embedded && !os(Linux) && !os(anyAppleOS))) && (arch(i386) || arch(x86_64))
|
|
|
|
/// Creates a new instance that approximates the given value.
|
|
///
|
|
/// The value of `other` is rounded to a representable value, if necessary.
|
|
/// A NaN passed as `other` results in another NaN, with a signaling NaN
|
|
/// value converted to quiet NaN.
|
|
///
|
|
/// let x: Float80 = 21.25
|
|
/// let y = Float(x)
|
|
/// // y == 21.25
|
|
///
|
|
/// let z = Float(Float80.nan)
|
|
/// // z.isNaN == true
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable // FIXME(inline-always)
|
|
@inline(__always)
|
|
public init(_ other: Float80) {
|
|
_value = Builtin.fptrunc_FPIEEE80_FPIEEE32(other._value)
|
|
}
|
|
|
|
/// Creates a new instance initialized to the given value, if it can be
|
|
/// represented without rounding.
|
|
///
|
|
/// If `other` can't be represented as an instance of `Float` without
|
|
/// rounding, the result of this initializer is `nil`. In particular,
|
|
/// passing NaN as `other` always results in `nil`.
|
|
///
|
|
/// let x: Float80 = 21.25
|
|
/// let y = Float(exactly: x)
|
|
/// // y == Optional.some(21.25)
|
|
///
|
|
/// let z = Float(exactly: Float80.nan)
|
|
/// // z == nil
|
|
///
|
|
/// - Parameter other: The value to use for the new instance.
|
|
|
|
@inlinable
|
|
@inline(__always)
|
|
public init?(exactly other: Float80) {
|
|
self.init(other)
|
|
// Converting the infinity value is considered value preserving.
|
|
// In other cases, check that we can round-trip and get the same value.
|
|
// NaN always fails.
|
|
if Float80(self) != other {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Standard Operator Table
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TODO: These should not be necessary, since they're already provided by
|
|
// <T: FloatingPoint>, but in practice they are currently needed to
|
|
// disambiguate overloads. We should find a way to remove them, either by
|
|
// tweaking the overload resolution rules, or by removing the other
|
|
// definitions in the standard lib, or both.
|
|
|
|
|
|
extension Float {
|
|
@_transparent
|
|
public static func + (lhs: Float, rhs: Float) -> Float {
|
|
var lhs = lhs
|
|
lhs += rhs
|
|
return lhs
|
|
}
|
|
|
|
@_transparent
|
|
public static func - (lhs: Float, rhs: Float) -> Float {
|
|
var lhs = lhs
|
|
lhs -= rhs
|
|
return lhs
|
|
}
|
|
|
|
@_transparent
|
|
public static func * (lhs: Float, rhs: Float) -> Float {
|
|
var lhs = lhs
|
|
lhs *= rhs
|
|
return lhs
|
|
}
|
|
|
|
@_transparent
|
|
public static func / (lhs: Float, rhs: Float) -> Float {
|
|
var lhs = lhs
|
|
lhs /= rhs
|
|
return lhs
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Strideable Conformance
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
extension Float: Strideable {
|
|
@_transparent
|
|
public func distance(to other: Float) -> Float {
|
|
return other - self
|
|
}
|
|
|
|
@_transparent
|
|
public func advanced(by amount: Float) -> Float {
|
|
return self + amount
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// AnyHashable
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
@_unavailableInEmbedded
|
|
internal struct _FloatAnyHashableBox: _AnyHashableBox {
|
|
internal typealias Base = Float
|
|
|
|
internal let _value: Base
|
|
|
|
internal init(_ value: Base) {
|
|
self._value = value
|
|
}
|
|
|
|
internal var _canonicalBox: _AnyHashableBox {
|
|
// Float and Double are bridged with NSNumber, so we have to follow
|
|
// NSNumber's rules for equality. I.e., we need to make sure equal
|
|
// numerical values end up in identical boxes after canonicalization, so
|
|
// that _isEqual will consider them equal and they're hashed the same way.
|
|
//
|
|
// Note that these AnyHashable boxes don't currently feed discriminator bits
|
|
// to the hasher, so we allow repeatable collisions. E.g., -1 will always
|
|
// collide with UInt64.max.
|
|
if _value < 0 {
|
|
if let i = Int64(exactly: _value) {
|
|
return _IntegerAnyHashableBox(i)
|
|
}
|
|
} else {
|
|
if let i = UInt64(exactly: _value) {
|
|
return _IntegerAnyHashableBox(i)
|
|
}
|
|
}
|
|
if let d = Double(exactly: _value) {
|
|
return _DoubleAnyHashableBox(d)
|
|
}
|
|
// If a value can't be represented by a Double, keep it in its original
|
|
// representation so that it won't compare equal to approximations. (So that
|
|
// we don't round off Float80 values.)
|
|
return self
|
|
}
|
|
|
|
internal func _isEqual(to box: _AnyHashableBox) -> Bool? {
|
|
_internalInvariant(Int64(exactly: _value) == nil, "self isn't canonical")
|
|
_internalInvariant(UInt64(exactly: _value) == nil, "self isn't canonical")
|
|
if let box = box as? _FloatAnyHashableBox {
|
|
return _value == box._value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
internal var _hashValue: Int {
|
|
return _rawHashValue(_seed: 0)
|
|
}
|
|
|
|
internal func _hash(into hasher: inout Hasher) {
|
|
_internalInvariant(Int64(exactly: _value) == nil, "self isn't canonical")
|
|
_internalInvariant(UInt64(exactly: _value) == nil, "self isn't canonical")
|
|
hasher.combine(_value)
|
|
}
|
|
|
|
internal func _rawHashValue(_seed: Int) -> Int {
|
|
var hasher = Hasher(_seed: _seed)
|
|
_hash(into: &hasher)
|
|
return hasher.finalize()
|
|
}
|
|
|
|
internal var _base: Any {
|
|
return _value
|
|
}
|
|
|
|
internal func _unbox<T: Hashable>() -> T? {
|
|
return _value as? T
|
|
}
|
|
|
|
internal func _downCastConditional<T>(
|
|
into result: UnsafeMutablePointer<T>
|
|
) -> Bool {
|
|
guard let value = _value as? T else { return false }
|
|
unsafe result.initialize(to: value)
|
|
return true
|
|
}
|
|
}
|
|
|
|
|
|
extension Float: ConvertibleToBytes {}
|
|
|
|
extension Float: ConvertibleFromBytes {}
|
|
|