mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
156 lines
5.1 KiB
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()
|