Skip to content

Commit db10388

Browse files
authored
Merge pull request swiftlang#30194 from xwu/floating-point-conversion-oops
2 parents e9a7427 + 6e46135 commit db10388

File tree

2 files changed

+21
-10
lines changed

2 files changed

+21
-10
lines changed

stdlib/public/core/FloatingPoint.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,23 +1858,24 @@ extension BinaryFloatingPoint {
18581858
if source.significandWidth <= leadingBitIndex {
18591859
return (value, true)
18601860
}
1861-
// We promise to round to the closest representation, and if two
1862-
// representable values are equally close, the value with more trailing
1863-
// zeros in its significand bit pattern. Therefore, we must take a look at
1864-
// the bits that we've just truncated.
1861+
// We promise to round to the closest representation. Therefore, we must
1862+
// take a look at the bits that we've just truncated.
18651863
let ulp = (1 as Source.RawSignificand) << -shift
18661864
let truncatedBits = source.significandBitPattern & (ulp - 1)
18671865
if truncatedBits < ulp / 2 {
18681866
return (value, false)
18691867
}
18701868
let rounded = source.sign == .minus ? value.nextDown : value.nextUp
1871-
guard _fastPath(
1872-
truncatedBits != ulp / 2 ||
1873-
exponentBitPattern.trailingZeroBitCount <
1874-
rounded.exponentBitPattern.trailingZeroBitCount) else {
1875-
return (value, false)
1869+
if _fastPath(truncatedBits > ulp / 2) {
1870+
return (rounded, false)
18761871
}
1877-
return (rounded, false)
1872+
// If two representable values are equally close, we return the value with
1873+
// more trailing zeros in its significand bit pattern.
1874+
return
1875+
significandBitPattern.trailingZeroBitCount >
1876+
rounded.significandBitPattern.trailingZeroBitCount
1877+
? (value, false)
1878+
: (rounded, false)
18781879
}
18791880

18801881
/// Creates a new instance from the given value, rounded to the closest

test/stdlib/FloatingPoint.swift.gyb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,16 @@ FloatingPoint.test("BinaryFloatingPoint/genericFloatingPointConversion") {
206206
Float._convert(
207207
from: Double._convert(from: Float.leastNonzeroMagnitude).value).value,
208208
Float.leastNonzeroMagnitude)
209+
210+
// Let's make sure that the correct value is returned when two representable
211+
// values are equally close to the original value.
212+
let bitPattern: UInt64 = 0b01111111111_0000000000000000000000110000000000000000000000000000
213+
var z = Double(bitPattern: bitPattern)
214+
expectEqual(Float._convert(from: z).value, Float(z))
215+
216+
z = Double(Float.greatestFiniteMagnitude) +
217+
Double(Float.greatestFiniteMagnitude.ulp / 2)
218+
expectEqual(Float._convert(from: z).value, Float(z))
209219
}
210220

211221
func positiveOne<T: ExpressibleByIntegerLiteral>() -> T {

0 commit comments

Comments
 (0)