I wonder if this is by design (and if so, why?) or because of a bug, perhaps the one discussed here.
EDIT: AFAICT it seems to be that bug.
Demonstration program here.
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() {
print("Please wait …")
let startFloat = (7.038531e-26 as Float).nextDown
let endFloat = (7.038531e-26 as Float).nextUp
let endDouble = Double(endFloat)
var d = Double(startFloat)
let step = d.ulp
var mc = 0
while d <= endDouble {
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()
I've only tested it with the default toolchain of Xcode 12.1 (12A7403), but when I do, it prints:
Please wait …
Found mismatched conversion (after 805306368 matching conversions):
Double: 0_01110101011_0101110010000111111110110000000000000000000000000000 7.038531e-26
concrete: 0_00101011_01011100100001111111110 7.0385313e-26
generic: 0_00101011_01011100100001111111101 7.038531e-26
Shouldn't this bug fix be in Xcode 12.1? @scanon @xwu