Files
swift-mirror/test/stdlib/PrintFloat16.swift

156 lines
5.1 KiB
Swift

// 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()