1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// RUN: %target-run-simple-swift
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// UNSUPPORTED: use_os_stdlib
// rdar://77087867
// UNSUPPORTED: CPU=arm64_32 && OS=watchos
// rdar://104232602
// UNSUPPORTED: CPU=x86_64 && (DARWIN_SIMULATOR=ios || DARWIN_SIMULATOR=watchos || DARWIN_SIMULATOR=tvos)
import StdlibUnittest
let PrintTests = TestSuite("FloatingPointPrinting")
// Check that all floating point types
// are CustomStringConvertible
PrintTests.test("CustomStringConvertible") {
func hasDescription(_ any: Any) {
expectTrue(any is CustomStringConvertible)
}
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
if #available(SwiftStdlib 5.3, *) {
hasDescription(Float16(1.0))
hasDescription(CFloat16(1.0))
}
#endif
hasDescription(Float(1.0))
hasDescription(Double(1.0))
#if !os(Windows) && (arch(i386) || arch(x86_64))
hasDescription(Float80(1.0))
#endif
hasDescription(CFloat(1.0))
hasDescription(CDouble(1.0))
}
// Check that all floating point types
// are CustomDebugStringConvertible
PrintTests.test("CustomDebugStringConvertible") {
func hasDebugDescription(_ any: Any) {
expectTrue(any is CustomDebugStringConvertible)
}
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
if #available(SwiftStdlib 5.3, *) {
hasDebugDescription(Float16(1.0))
hasDebugDescription(CFloat16(1.0))
}
#endif
hasDebugDescription(Float(1.0))
hasDebugDescription(Double(1.0))
#if !os(Windows) && (arch(i386) || arch(x86_64))
hasDebugDescription(Float80(1.0))
#endif
hasDebugDescription(CFloat(1.0))
hasDebugDescription(CDouble(1.0))
}
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
@available(SwiftStdlib 5.8, *) // Regex
func testFinite(_ bitPattern: UInt16) {
let value = Float16(bitPattern: bitPattern)
let string = value.description
let debugString = value.debugDescription
// description and debugDescription should agree for finite values
expectEqual(string, debugString)
// test that conversion round-trips correctly
expectEqual(value, Float16(string))
// parse the string so we can test for shortness and closeness
let fmt = #/(?'sign'-?)(?'int'\d+)(?:\.(?'frac'\d+))?(?:e(?'exp'[+-]\d+))?/#
let match = try! fmt.wholeMatch(in: string)!
let significand: Int
let bias: Int
if let frac = match.frac, frac != "0" {
significand = Int(match.int + frac)!
bias = frac.count
} else {
significand = Int(match.int)!
bias = 0
}
let exponent = Int(match.exp ?? "0")! - bias
let float = Float(value)
let error = (float - Float(string)!).magnitude
// If the string representation isn't exact (up to Float accuracy), try
// the adjacent values to see if they would have been closer.
if error != 0 {
let up = "\(match.sign)\(significand + 1)e\(exponent)"
let upError = (float - Float(up)!).magnitude
expectFalse(
upError < error || upError == error && significand % 2 == 1,
"Float16(\(value)).description was \(string), but \(up) would be closer."
)
let dn = "\(match.sign)\(significand - 1)e\(exponent)"
let dnError = (float - Float(dn)!).magnitude
expectFalse(
dnError < error || dnError == error && significand % 2 == 1,
"Float16(\(value)).description was \(string), but \(dn) would be closer."
)
}
// If the string representation isn't an exact integer, check if we could
// have used a shorter string.
if error != 0 || match.exp != nil {
let dn = "\(match.sign)\(significand/10)e\(exponent+1)"
expectFalse(
Float16(dn)! == value,
"Float16(\(value)).description was \(string), but \(dn) rounds to the same value and is shorter."
)
let up = "\(match.sign)\((significand+9)/10)e\(exponent+1)"
expectFalse(
Float16(up)! == value,
"Float16(\(value)).description was \(string), but \(up) rounds to the same value and is shorter."
)
}
}
#endif
PrintTests.test("Printable_Float16") {
#if !((os(macOS) || targetEnvironment(macCatalyst)) && arch(x86_64))
guard #available(SwiftStdlib 5.8, *) else { return } // Regex
for bitPattern in UInt16.zero ..< 0x7c00 {
testFinite(bitPattern)
testFinite(0x8000 | bitPattern)
}
expectEqual(Float16.infinity.description, "inf")
expectEqual((-Float16.infinity).description, "-inf")
expectEqual(Float16.infinity.debugDescription, "inf")
expectEqual((-Float16.infinity).debugDescription, "-inf")
// Platforms without float 16 argument passing can cause NaNs to be changed
// while being passed.
#if !arch(wasm32)
for bitPattern in (0x7c01 as UInt16) ... 0x7fff {
expectEqual(Float16(bitPattern: bitPattern).description, "nan")
expectEqual(Float16(bitPattern: 0x8000 | bitPattern).description, "nan")
let payload: String = if bitPattern & 0xff == 0 {
""
} else {
"(0x\(String(bitPattern & 0xff, radix: 16)))"
}
let expected: String = if bitPattern & 0b10_0000_0000 == 0 {
"snan" + payload
} else {
"nan" + payload
}
expectEqual(Float16(bitPattern: bitPattern).debugDescription, expected)
expectEqual(Float16(bitPattern: 0x8000 | bitPattern).debugDescription, "-\(expected)")
}
#endif
#endif
}
runAllTests()
|