Skip to content

Commit 23dc001

Browse files
authored
Merge pull request swiftlang#33910 from xwu/exactness-in-little-things-a-wonderful-source-of-cheerfulness
[stdlib] Simplify 'BinaryFloatingPoint.init?<T: BinaryFloatingPoint>(exactly: T)'
2 parents 913543e + 26cda27 commit 23dc001

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

stdlib/public/core/FloatingPoint.swift

+24-3
Original file line numberDiff line numberDiff line change
@@ -1950,9 +1950,30 @@ extension BinaryFloatingPoint {
19501950
/// - Parameter value: A floating-point value to be converted.
19511951
@inlinable
19521952
public init?<Source: BinaryFloatingPoint>(exactly value: Source) {
1953-
let (value_, exact) = Self._convert(from: value)
1954-
guard exact else { return nil }
1955-
self = value_
1953+
// We define exactness by equality after roundtripping; since NaN is never
1954+
// equal to itself, it can never be converted exactly.
1955+
if value.isNaN { return nil }
1956+
1957+
if (Source.exponentBitCount > Self.exponentBitCount
1958+
|| Source.significandBitCount > Self.significandBitCount)
1959+
&& value.isFinite && !value.isZero {
1960+
let exponent = value.exponent
1961+
if exponent < Self.leastNormalMagnitude.exponent {
1962+
if exponent < Self.leastNonzeroMagnitude.exponent { return nil }
1963+
if value.significandWidth >
1964+
Int(Self.Exponent(exponent) - Self.leastNonzeroMagnitude.exponent) {
1965+
return nil
1966+
}
1967+
} else {
1968+
if exponent > Self.greatestFiniteMagnitude.exponent { return nil }
1969+
if value.significandWidth >
1970+
Self.greatestFiniteMagnitude.significandWidth {
1971+
return nil
1972+
}
1973+
}
1974+
}
1975+
1976+
self = Self(value)
19561977
}
19571978

19581979
@inlinable

test/stdlib/FloatingPoint.swift.gyb

+41
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,47 @@ FloatingPoint.test("BinaryFloatingPoint/genericIntegerConversion") {
116116
}
117117

118118
FloatingPoint.test("BinaryFloatingPoint/genericFloatingPointConversion") {
119+
func convert<
120+
T: BinaryFloatingPoint, U: BinaryFloatingPoint
121+
>(exactly value: T, to: U.Type) -> U { U(exactly: value) }
122+
123+
expectEqual(convert(exactly: 0 as Float, to: Double.self), 0.0)
124+
expectEqual(convert(exactly: -0.0 as Float, to: Double.self), -0.0)
125+
expectEqual(
126+
convert(exactly: -0.0 as Float, to: Double.self).sign,
127+
FloatingPointSign.minus)
128+
expectEqual(convert(exactly: 0 as Double, to: Float.self), 0.0 as Float)
129+
expectEqual(convert(exactly: -0.0 as Double, to: Float.self), -0.0 as Float)
130+
expectEqual(
131+
convert(exactly: -0.0 as Double, to: Float.self).sign,
132+
FloatingPointSign.minus)
133+
expectEqual(convert(exactly: 1 as Float, to: Double.self), 1.0)
134+
expectEqual(convert(exactly: -1 as Float, to: Double.self), -1.0)
135+
expectEqual(convert(exactly: 1 as Double, to: Float.self), 1.0 as Float)
136+
expectEqual(convert(exactly: -1 as Double, to: Float.self), -1.0 as Float)
137+
expectEqual(
138+
convert(exactly: Float.infinity, to: Double.self), Double.infinity)
139+
expectEqual(
140+
convert(exactly: -Float.infinity, to: Double.self), -Double.infinity)
141+
expectEqual(
142+
convert(exactly: Double.infinity, to: Float.self), Float.infinity)
143+
expectEqual(
144+
convert(exactly: -Double.infinity, to: Float.self), -Float.infinity)
145+
expectEqual(convert(exactly: Float.nan, to: Double.self), nil)
146+
expectEqual(convert(exactly: Double.nan, to: Float.self), nil)
147+
expectEqual(convert(exactly: Float.nan, to: Float.self), nil)
148+
expectEqual(convert(exactly: Double.nan, to: Double.self), nil)
149+
expectEqual(
150+
convert(exactly: Double.leastNonzeroMagnitude, to: Float.self), nil)
151+
expectEqual(
152+
convert(exactly: Float.leastNonzeroMagnitude, to: Double.self),
153+
Double(Float.leastNonzeroMagnitude))
154+
expectEqual(
155+
convert(exactly: Double.greatestFiniteMagnitude, to: Float.self), nil)
156+
expectEqual(
157+
convert(exactly: Float.greatestFiniteMagnitude, to: Double.self),
158+
Double(Float.greatestFiniteMagnitude))
159+
119160
expectTrue(Double._convert(from: 0 as Float) == (value: 0, exact: true))
120161
expectTrue(Double._convert(from: -0.0 as Float) == (value: -0.0, exact: true))
121162
expectTrue(Double._convert(from: 1 as Float) == (value: 1, exact: true))

0 commit comments

Comments
 (0)