Yes, I thought so too. Here's a program that prints each pair of mismatching conversions from Double
to Float
for all Double
values in 1.0 ... 2.0
:
func concrete(_ value: Double) -> Float {
return Float.init(value) // Will call intrinsic
}
func generic<T: BinaryFloatingPoint>(_ value: T) -> Float {
return Float.init(value) // Will call ._convert(from:)
}
extension String {
func leftPadded(to minCount: Int, with char: Character=" ") -> String {
return String(repeating: char, count: max(0, minCount-count)) + self
}
}
extension BinaryFloatingPoint {
var segmentedBinaryString: String {
let e = String(exponentBitPattern, radix: 2)
let s = String(significandBitPattern, radix: 2)
return [self.sign == .plus ? "0" : "1", "_",
e.leftPadded(to: Self.exponentBitCount, with: "0"), "_",
s.leftPadded(to: Self.significandBitCount, with: "0")].joined()
}
}
func test() {
var d = Double(1)
let step = d.ulp
var mc = 0
while d <= 2 {
let a = concrete(d)
let b = generic(d)
if a != b {
print("Found mismatched conversion (after \(mc) matching conversions):")
print(" Double: ", d.segmentedBinaryString, d)
print(" concrete:", a.segmentedBinaryString, a)
print(" generic: ", b.segmentedBinaryString, b)
mc = 0
} else {
mc &+= 1
}
d += step
}
}
test()
Here's what it will print:
Found mismatched conversion (after 805306368 matching conversions):
Double: 0_01111111111_0000000000000000000000110000000000000000000000000000 1.0000001788139343
concrete: 0_01111111_00000000000000000000010 1.0000002
generic: 0_01111111_00000000000000000000001 1.0000001
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000001110000000000000000000000000000 1.0000004172325134
concrete: 0_01111111_00000000000000000000100 1.0000005
generic: 0_01111111_00000000000000000000011 1.0000004
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000010110000000000000000000000000000 1.0000006556510925
concrete: 0_01111111_00000000000000000000110 1.0000007
generic: 0_01111111_00000000000000000000101 1.0000006
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000011110000000000000000000000000000 1.0000008940696716
concrete: 0_01111111_00000000000000000001000 1.000001
generic: 0_01111111_00000000000000000000111 1.0000008
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000100110000000000000000000000000000 1.0000011324882507
concrete: 0_01111111_00000000000000000001010 1.0000012
generic: 0_01111111_00000000000000000001001 1.0000011
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000101110000000000000000000000000000 1.0000013709068298
concrete: 0_01111111_00000000000000000001100 1.0000014
generic: 0_01111111_00000000000000000001011 1.0000013
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000110110000000000000000000000000000 1.000001609325409
concrete: 0_01111111_00000000000000000001110 1.0000017
generic: 0_01111111_00000000000000000001101 1.0000015
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000000111110000000000000000000000000000 1.000001847743988
concrete: 0_01111111_00000000000000000010000 1.0000019
generic: 0_01111111_00000000000000000001111 1.0000018
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000001000110000000000000000000000000000 1.0000020861625671
concrete: 0_01111111_00000000000000000010010 1.0000021
generic: 0_01111111_00000000000000000010001 1.000002
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000001001110000000000000000000000000000 1.0000023245811462
concrete: 0_01111111_00000000000000000010100 1.0000024
generic: 0_01111111_00000000000000000010011 1.0000023
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000001010110000000000000000000000000000 1.0000025629997253
concrete: 0_01111111_00000000000000000010110 1.0000026
generic: 0_01111111_00000000000000000010101 1.0000025
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000001011110000000000000000000000000000 1.0000028014183044
concrete: 0_01111111_00000000000000000011000 1.0000029
generic: 0_01111111_00000000000000000010111 1.0000027
Found mismatched conversion (after 1073741823 matching conversions):
Double: 0_01111111111_0000000000000000001100110000000000000000000000000000 1.0000030398368835
concrete: 0_01111111_00000000000000000011010 1.0000031
generic: 0_01111111_00000000000000000011001 1.000003
(I stopped it there (after a couple of minutes) .)
The generic one does not behave according to its documentation, ie:
If two representable values are equally close, the result is the value with more trailing zeros in its significand bit pattern.