Skip to content

Commit 7a736cc

Browse files
committed
Merge pull request #2786 from rintaro/float-debugdesc
2 parents a199fb2 + 702a5ab commit 7a736cc

File tree

3 files changed

+264
-5
lines changed

3 files changed

+264
-5
lines changed

stdlib/public/core/Runtime.swift.gyb

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,26 @@ func _float${bits}ToStringImpl(
350350

351351
func _float${bits}ToString(_ value: Float${bits}, debug: Bool) -> String {
352352

353-
if value.isInfinite {
354-
return value.sign == .minus ? "-inf" : "inf"
355-
}
356-
if value.isNaN {
357-
return "nan"
353+
if !value.isFinite {
354+
let significand = value.significandBitPattern
355+
if significand == 0 {
356+
// Infinity
357+
return value.sign == .minus ? "-inf" : "inf"
358+
}
359+
else {
360+
// NaN
361+
if !debug {
362+
return "nan"
363+
}
364+
let isSignaling = (significand & Float${bits}._quietNaNMask) == 0
365+
let payload = significand & ((Float${bits}._quietNaNMask >> 1) - 1)
366+
// FIXME(performance): Inefficient String manipulation. We could move
367+
// this to C function.
368+
return
369+
(value.sign == .minus ? "-" : "")
370+
+ (isSignaling ? "snan" : "nan")
371+
+ (payload == 0 ? "" : ("(0x" + String(payload, radix: 16) + ")"))
372+
}
358373
}
359374

360375
_sanityCheck(sizeof(_Buffer32.self) == 32)

test/1_stdlib/FloatingPoint.swift.gyb

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,192 @@ FloatingPoint.test("Float80/Literals") {
816816

817817
#endif
818818

819+
FloatingPoint.test("Float32/quietNaN") {
820+
do {
821+
let f: Float32 = .nan
822+
expectTrue(f.isNaN && !f.isSignalingNaN)
823+
expectEqual(0x7fc0_0000, f.bitPattern)
824+
}
825+
do {
826+
// Empty payload
827+
let f: Float32 = Float32(bitPattern: 0x7fc0_0000)
828+
expectTrue(f.isNaN && !f.isSignalingNaN)
829+
}
830+
do {
831+
// Full payload
832+
let f: Float32 = Float32(bitPattern: 0x7fff_ffff)
833+
expectTrue(f.isNaN && !f.isSignalingNaN)
834+
}
835+
do {
836+
// Highest payload `init(nan:signaling:)` can handle
837+
let f: Float32 = Float32(nan: 0x1f_ffff, signaling: false)
838+
expectTrue(f.isNaN && !f.isSignalingNaN)
839+
expectEqual(0x7fdf_ffff, f.bitPattern)
840+
}
841+
do {
842+
// Payload overflow
843+
expectCrashLater()
844+
_ = Float32(nan: 0x20_0000, signaling: false)
845+
}
846+
}
847+
848+
FloatingPoint.test("Float64/quietNaN") {
849+
do {
850+
let f: Float64 = .nan
851+
expectTrue(f.isNaN && !f.isSignalingNaN)
852+
expectEqual(0x7ff8_0000_0000_0000, f.bitPattern)
853+
}
854+
do {
855+
// Empty payload
856+
let f: Float64 = Float64(bitPattern: 0x7ff8_0000_0000_0000)
857+
expectTrue(f.isNaN && !f.isSignalingNaN)
858+
}
859+
do {
860+
// Full payload
861+
let f: Float64 = Float64(bitPattern: 0x7fff_ffff_ffff_ffff)
862+
expectTrue(f.isNaN && !f.isSignalingNaN)
863+
}
864+
do {
865+
// Highest payload `init(nan:signaling:)` can handle
866+
let f: Float64 = Float64(nan: 0x3_ffff_ffff_ffff, signaling: false)
867+
expectTrue(f.isNaN && !f.isSignalingNaN)
868+
expectEqual(0x7ffb_ffff_ffff_ffff, f.bitPattern)
869+
}
870+
do {
871+
// Payload overflow
872+
expectCrashLater()
873+
_ = Float64(nan: 0x4_0000_0000_0000, signaling: false)
874+
}
875+
}
876+
877+
#if arch(i386) || arch(x86_64)
878+
879+
FloatingPoint.test("Float80/quietNaN") {
880+
do {
881+
let f: Float80 = .nan
882+
expectTrue(f.isNaN && !f.isSignalingNaN)
883+
expectEqual(Float80Bits(0x7fff, 0xc000_0000_0000_0000), f.bitPattern)
884+
}
885+
do {
886+
// Empty payload
887+
let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xc000_0000_0000_0000))
888+
expectTrue(f.isNaN && !f.isSignalingNaN)
889+
}
890+
do {
891+
// Full payload
892+
let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xffff_ffff_ffff_ffff))
893+
expectTrue(f.isNaN && !f.isSignalingNaN)
894+
}
895+
do {
896+
// Highest payload `init(nan:signaling:)` can handle
897+
let f: Float80 = Float80(nan: 0x1fff_ffff_ffff_ffff, signaling: false)
898+
expectTrue(f.isNaN && !f.isSignalingNaN)
899+
expectEqual(Float80Bits(0x7fff, 0xdfff_ffff_ffff_ffff), f.bitPattern)
900+
}
901+
do {
902+
// Payload overflow
903+
expectCrashLater()
904+
_ = Float80(nan: 0x2000_0000_0000_0000, signaling: false)
905+
}
906+
}
907+
908+
#endif
909+
910+
#if !arch(i386)
911+
912+
FloatingPoint.test("Float32/signalingNaN") {
913+
do {
914+
let f: Float32 = .signalingNaN
915+
expectTrue(f.isNaN && f.isSignalingNaN)
916+
expectEqual(0x7fa0_0000, f.bitPattern)
917+
}
918+
do {
919+
// Empty payload
920+
let f: Float32 = Float32(bitPattern: 0x7fa0_0000)
921+
expectTrue(f.isNaN && f.isSignalingNaN)
922+
}
923+
do {
924+
// Full payload
925+
let f: Float32 = Float32(bitPattern: 0x7fbf_ffff)
926+
expectTrue(f.isNaN && f.isSignalingNaN)
927+
}
928+
do {
929+
// Highest payload `init(nan:signaling:)` can handle
930+
let f: Float32 = Float32(nan: 0x1f_ffff, signaling: true)
931+
expectTrue(f.isNaN && f.isSignalingNaN)
932+
expectEqual(0x7fbf_ffff, f.bitPattern)
933+
}
934+
do {
935+
// payload overflow
936+
expectCrashLater()
937+
_ = Float32(nan: 0x20_0000, signaling: true)
938+
}
939+
}
940+
941+
FloatingPoint.test("Float64/signalingNaN") {
942+
do {
943+
let f: Float64 = .signalingNaN
944+
expectTrue(f.isNaN && f.isSignalingNaN)
945+
expectEqual(0x7ff4_0000_0000_0000, f.bitPattern)
946+
}
947+
do {
948+
// Empty payload
949+
let f: Float64 = Float64(bitPattern: 0x7ff4_0000_0000_0000)
950+
expectTrue(f.isNaN && f.isSignalingNaN)
951+
}
952+
do {
953+
// Full payload
954+
let f: Float64 = Float64(bitPattern: 0x7ff7_ffff_ffff_ffff)
955+
expectTrue(f.isNaN && f.isSignalingNaN)
956+
}
957+
do {
958+
// Highest payload `init(nan:signaling:)` can handle
959+
let f: Float64 = Float64(nan: 0x3_ffff_ffff_ffff, signaling: true)
960+
expectTrue(f.isNaN && f.isSignalingNaN)
961+
expectEqual(0x7ff7_ffff_ffff_ffff, f.bitPattern)
962+
}
963+
do {
964+
// payload overflow
965+
expectCrashLater()
966+
_ = Float64(nan: 0x4_0000_0000_0000, signaling: true)
967+
}
968+
}
969+
970+
#endif
971+
972+
#if arch(i386) || arch(x86_64)
973+
974+
FloatingPoint.test("Float80/signalingNaN") {
975+
do {
976+
let f: Float80 = .signalingNaN
977+
expectTrue(f.isNaN && f.isSignalingNaN)
978+
expectEqual(Float80Bits(0x7fff, 0xa000_0000_0000_0000), f.bitPattern)
979+
}
980+
do {
981+
// Empty payload
982+
let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xa000_0000_0000_0000))
983+
expectTrue(f.isNaN && f.isSignalingNaN)
984+
}
985+
do {
986+
// Full payload
987+
let f: Float80 = Float80(bitPattern: Float80Bits(0x7fff, 0xbfff_ffff_ffff_ffff))
988+
expectTrue(f.isNaN && f.isSignalingNaN)
989+
}
990+
do {
991+
// Highest payload `init(nan:signaling:)` can handle
992+
let f: Float80 = Float80(nan: 0x1fff_ffff_ffff_ffff, signaling: true)
993+
expectTrue(f.isNaN && f.isSignalingNaN)
994+
expectEqual(Float80Bits(0x7fff, 0xbfff_ffff_ffff_ffff), f.bitPattern)
995+
}
996+
do {
997+
// payload overflow
998+
expectCrashLater()
999+
_ = Float80(nan: 0x2000_0000_0000_0000, signaling: true)
1000+
}
1001+
}
1002+
1003+
#endif
1004+
8191005
var FloatingPointClassification = TestSuite("NumericParsing")
8201006

8211007
FloatingPointClassification.test("FloatingPointClassification/Equatable") {

test/1_stdlib/PrintFloat.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ PrintTests.test("Printable") {
5656
expectPrinted("-inf", -Float.infinity)
5757
expectPrinted("nan", Float.nan)
5858
expectPrinted("nan", -Float.nan)
59+
expectPrinted("nan", Float.signalingNaN)
60+
expectPrinted("nan", -Float.signalingNaN)
5961
expectPrinted("0.0", asFloat32(0.0))
6062
expectPrinted("1.0", asFloat32(1.0))
6163
expectPrinted("-1.0", asFloat32(-1.0))
@@ -66,12 +68,28 @@ PrintTests.test("Printable") {
6668
expectPrinted("-inf", -Double.infinity)
6769
expectPrinted("nan", Double.nan)
6870
expectPrinted("nan", -Double.nan)
71+
expectPrinted("nan", Double.signalingNaN)
72+
expectPrinted("nan", -Double.signalingNaN)
6973
expectPrinted("0.0", asFloat64(0.0))
7074
expectPrinted("1.0", asFloat64(1.0))
7175
expectPrinted("-1.0", asFloat64(-1.0))
7276
expectPrinted("100.125", asFloat64(100.125))
7377
expectPrinted("-100.125", asFloat64(-100.125))
7478

79+
#if arch(i386) || arch(x86_64)
80+
expectPrinted("inf", Float80.infinity)
81+
expectPrinted("-inf", -Float80.infinity)
82+
expectPrinted("nan", Float80.nan)
83+
expectPrinted("nan", -Float80.nan)
84+
expectPrinted("nan", Float80.signalingNaN)
85+
expectPrinted("nan", -Float80.signalingNaN)
86+
expectPrinted("0.0", asFloat80(0.0))
87+
expectPrinted("1.0", asFloat80(1.0))
88+
expectPrinted("-1.0", asFloat80(-1.0))
89+
expectPrinted("100.125", asFloat80(100.125))
90+
expectPrinted("-100.125", asFloat80(-100.125))
91+
#endif
92+
7593
expectPrinted("1.00001", asFloat32(1.00001))
7694
expectPrinted("1.25e+17", asFloat32(125000000000000000.0))
7795
expectPrinted("1.25e+16", asFloat32(12500000000000000.0))
@@ -191,17 +209,57 @@ PrintTests.test("Printable") {
191209
expectDebugPrinted("1.24999998e+17", asFloat32(125000000000000000.0))
192210
expectDebugPrinted("1.25", asFloat32(1.25))
193211
expectDebugPrinted("1.24999997e-05", asFloat32(0.0000125))
212+
expectDebugPrinted("inf", Float.infinity)
213+
expectDebugPrinted("-inf", -Float.infinity)
214+
expectDebugPrinted("nan", Float.nan)
215+
expectDebugPrinted("-nan", -Float.nan)
216+
expectDebugPrinted("nan(0xffff)", Float(nan: 65535, signaling: false))
217+
expectDebugPrinted("-nan(0xffff)", -Float(nan: 65535, signaling: false))
218+
expectDebugPrinted("nan(0x1fffff)", Float(bitPattern: 0x7fff_ffff))
219+
expectDebugPrinted("nan(0x1fffff)", Float(bitPattern: 0x7fdf_ffff))
220+
#if !arch(i386)
221+
expectDebugPrinted("snan", Float.signalingNaN)
222+
expectDebugPrinted("snan(0xffff)", Float(nan: 65535, signaling: true))
223+
expectDebugPrinted("-snan(0xffff)", -Float(nan: 65535, signaling: true))
224+
expectDebugPrinted("snan(0x1fffff)", Float(bitPattern: 0x7fbf_ffff))
225+
#endif
194226

195227
expectDebugPrinted("1.1000000000000001", asFloat64(1.1))
196228
expectDebugPrinted("1.25e+17", asFloat64(125000000000000000.0))
197229
expectDebugPrinted("1.25", asFloat64(1.25))
198230
expectDebugPrinted("1.2500000000000001e-05", asFloat64(0.0000125))
231+
expectDebugPrinted("inf", Double.infinity)
232+
expectDebugPrinted("-inf", -Double.infinity)
233+
expectDebugPrinted("nan", Double.nan)
234+
expectDebugPrinted("-nan", -Double.nan)
235+
expectDebugPrinted("nan(0xffff)", Double(nan: 65535, signaling: false))
236+
expectDebugPrinted("-nan(0xffff)", -Double(nan: 65535, signaling: false))
237+
expectDebugPrinted("nan(0x3ffffffffffff)", Float64(bitPattern: 0x7fff_ffff_ffff_ffff))
238+
expectDebugPrinted("nan(0x3ffffffffffff)", Float64(bitPattern: 0x7ffb_ffff_ffff_ffff))
239+
#if !arch(i386)
240+
expectDebugPrinted("snan", Double.signalingNaN)
241+
expectDebugPrinted("snan(0xffff)", Double(nan: 65535, signaling: true))
242+
expectDebugPrinted("-snan(0xffff)", -Double(nan: 65535, signaling: true))
243+
expectDebugPrinted("snan(0x3ffffffffffff)", Float64(bitPattern: 0x7ff7_ffff_ffff_ffff))
244+
#endif
199245

200246
#if arch(i386) || arch(x86_64)
201247
expectDebugPrinted("1.10000000000000000002", asFloat80(1.1))
202248
expectDebugPrinted("125000000000000000.0", asFloat80(125000000000000000.0))
203249
expectDebugPrinted("1.25", asFloat80(1.25))
204250
expectDebugPrinted("1.25000000000000000001e-05", asFloat80(0.0000125))
251+
expectDebugPrinted("inf", Float80.infinity)
252+
expectDebugPrinted("-inf", -Float80.infinity)
253+
expectDebugPrinted("nan", Float80.nan)
254+
expectDebugPrinted("-nan", -Float80.nan)
255+
expectDebugPrinted("nan(0xffff)", Float80(nan: 65535, signaling: false))
256+
expectDebugPrinted("-nan(0xffff)", -Float80(nan: 65535, signaling: false))
257+
expectDebugPrinted("nan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xffff_ffff_ffff_ffff))
258+
expectDebugPrinted("nan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xdfff_ffff_ffff_ffff))
259+
expectDebugPrinted("snan", Float80.signalingNaN)
260+
expectDebugPrinted("snan(0xffff)", Float80(nan: 65535, signaling: true))
261+
expectDebugPrinted("-snan(0xffff)", -Float80(nan: 65535, signaling: true))
262+
expectDebugPrinted("snan(0x1fffffffffffffff)", Float80(sign: .plus, exponentBitPattern: 0x7fff, significandBitPattern: 0xbfff_ffff_ffff_ffff))
205263
#endif
206264
}
207265

0 commit comments

Comments
 (0)