File: PrintFloat16.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (155 lines) | stat: -rw-r--r-- 5,242 bytes parent folder | download
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()