diff --git a/stdlib/public/runtime/SwiftDtoa.cpp b/stdlib/public/runtime/SwiftDtoa.cpp index 4b253cff87607..802bb007bf5e8 100644 --- a/stdlib/public/runtime/SwiftDtoa.cpp +++ b/stdlib/public/runtime/SwiftDtoa.cpp @@ -1063,7 +1063,9 @@ size_t swift_format_float(float d, char *dest, size_t length) int8_t digits[9]; int digitCount = swift_decompose_float(d, digits, sizeof(digits), &decimalExponent); - if (decimalExponent < -3 || decimalExponent > 6) { + // People use float to model integers <= 2^24, so we use that + // as a cutoff for decimal vs. exponential format. + if (decimalExponent < -3 || fabsf(d) > 0x1.0p24F) { return swift_format_exponential(dest, length, signbit(d), digits, digitCount, decimalExponent); } else { @@ -1117,7 +1119,9 @@ size_t swift_format_double(double d, char *dest, size_t length) int8_t digits[17]; int digitCount = swift_decompose_double(d, digits, sizeof(digits), &decimalExponent); - if (decimalExponent < -3 || decimalExponent > 15) { + // People use double to model integers <= 2^53, so we use that + // as a cutoff for decimal vs. exponential format. + if (decimalExponent < -3 || fabs(d) > 0x1.0p53) { return swift_format_exponential(dest, length, signbit(d), digits, digitCount, decimalExponent); } else { @@ -1166,13 +1170,16 @@ size_t swift_format_float80(long double d, char *dest, size_t length) } } - // Decimal numeric formatting // Decimal numeric formatting int decimalExponent; int8_t digits[21]; int digitCount = swift_decompose_float80(d, digits, sizeof(digits), &decimalExponent); - if (decimalExponent < -3 || decimalExponent > 18) { + // People use long double to model integers <= 2^64, so we use that + // as a cutoff for decimal vs. exponential format. + // The constant is written out as a float80 (aka "long double") literal + // here since it can't be expressed as a 64-bit integer. + if (decimalExponent < -3 || fabsl(d) > 0x1.0p64L) { return swift_format_exponential(dest, length, signbit(d), digits, digitCount, decimalExponent); } else { diff --git a/test/stdlib/PrintFloat.swift.gyb b/test/stdlib/PrintFloat.swift.gyb index cc3b59e836873..9a681bf52c90b 100644 --- a/test/stdlib/PrintFloat.swift.gyb +++ b/test/stdlib/PrintFloat.swift.gyb @@ -544,7 +544,7 @@ PrintTests.test("Printable_Float") { // Every power of 10 should print with only a single digit '1' for power in -45 ... 38 { let s: String - if power < -4 || power > 5 { // Exponential form + if power < -4 || power > 7 { // Exponential form s = exponentialPowerOfTen(power) } else if power < 0 { // Fractional decimal form s = "0." + String(repeating: "0", count: -power - 1) + "1" @@ -562,8 +562,14 @@ PrintTests.test("Printable_Float") { expectAccurateDescription(f.nextUp) } - // Check that the formatter chooses exponential - // format when it should: + // Float can represent all integers -(2^24)...(2^24) + let maxDecimalForm = Float(1 << 24) + expectDescription("16777216.0", maxDecimalForm) + expectDescription("-16777216.0", -maxDecimalForm) + // Outside of that range, use exponential form + expectDescription("1.6777218e+07", maxDecimalForm.nextUp) + expectDescription("-1.6777218e+07", -maxDecimalForm.nextUp) + expectDescription("1.00001", asFloat32(1.00001)) expectDescription("1.25e+17", asFloat32(125000000000000000.0)) expectDescription("1.25e+16", asFloat32(12500000000000000.0)) @@ -575,8 +581,8 @@ PrintTests.test("Printable_Float") { expectDescription("1.25e+10", asFloat32(12500000000.0)) expectDescription("1.25e+09", asFloat32(1250000000.0)) expectDescription("1.25e+08", asFloat32(125000000.0)) - expectDescription("1.25e+07", asFloat32(12500000.0)) - expectDescription("1.25e+06", asFloat32(1250000.0)) + expectDescription("12500000.0", asFloat32(12500000.0)) + expectDescription("1250000.0", asFloat32(1250000.0)) expectDescription("125000.0", asFloat32(125000.0)) expectDescription("12500.0", asFloat32(12500.0)) expectDescription("1250.0", asFloat32(1250.0)) @@ -660,7 +666,7 @@ PrintTests.test("Printable_Double") { // We know how every power of 10 should print for power in -323 ... 308 { let s: String - if power < -4 || power > 14 { // Exponential form + if power < -4 || power > 15 { // Exponential form s = exponentialPowerOfTen(power) } else if power < 0 { // Fractional decimal form s = "0." + String(repeating: "0", count: -power - 1) + "1" @@ -687,12 +693,18 @@ PrintTests.test("Printable_Double") { } } - // Check that the formatter chooses exponential - // format when it should: + // Double can represent all integers -(2^53)...(2^53) + let maxDecimalForm = Double((1 as Int64) << 53) + expectDescription("9007199254740992.0", maxDecimalForm) + expectDescription("-9007199254740992.0", -maxDecimalForm) + // Outside of that range, we use exponential form: + expectDescription("9.007199254740994e+15", maxDecimalForm.nextUp) + expectDescription("-9.007199254740994e+15", -maxDecimalForm.nextUp) + expectDescription("1.00000000000001", asFloat64(1.00000000000001)) expectDescription("1.25e+17", asFloat64(125000000000000000.0)) expectDescription("1.25e+16", asFloat64(12500000000000000.0)) - expectDescription("1.25e+15", asFloat64(1250000000000000.0)) + expectDescription("1250000000000000.0", asFloat64(1250000000000000.0)) expectDescription("125000000000000.0", asFloat64(125000000000000.0)) expectDescription("12500000000000.0", asFloat64(12500000000000.0)) expectDescription("1250000000000.0", asFloat64(1250000000000.0)) @@ -769,7 +781,7 @@ PrintTests.test("Printable_Float80") { // We know how every power of 10 should print for power in -4950 ... 4932 { let s: String - if power < -4 || power > 17 { // Exponential form + if power < -4 || power > 19 { // Exponential form s = exponentialPowerOfTen(power) } else if power < 0 { // Fractional decimal form s = "0." + String(repeating: "0", count: -power - 1) + "1" @@ -794,11 +806,19 @@ PrintTests.test("Printable_Float80") { } } - // Check that the formatter chooses exponential - // format when it should: + // Float80 can represent all integers -(2^64)...(2^64): + let maxDecimalForm = Float80(UInt64.max) + 1.0 + expectDescription("18446744073709551616.0", maxDecimalForm) + expectDescription("-18446744073709551616.0", -maxDecimalForm) + // Outside of that range, use exponential form + expectDescription("1.8446744073709551618e+19", maxDecimalForm.nextUp) + expectDescription("-1.8446744073709551618e+19", -maxDecimalForm.nextUp) + expectDescription("1.00000000000000001", asFloat80(1.00000000000000001)) - expectDescription("1.25e+19", asFloat80(12500000000000000000.0)) - expectDescription("1.25e+18", asFloat80(1250000000000000000.0)) + expectDescription("1.25e+21", asFloat80(1250000000000000000000.0)) + expectDescription("1.25e+20", asFloat80(125000000000000000000.0)) + expectDescription("12500000000000000000.0", asFloat80(12500000000000000000.0)) + expectDescription("1250000000000000000.0", asFloat80(1250000000000000000.0)) expectDescription("125000000000000000.0", asFloat80(125000000000000000.0)) expectDescription("12500000000000000.0", asFloat80(12500000000000000.0)) expectDescription("1250000000000000.0", asFloat80(1250000000000000.0))