Skip to content

Commit 10a8f4e

Browse files
committed
Merge pull request #348 from wczekalski/bugfix/float-string-precision
Fix precision of float to string to max significant decimals
2 parents 472efd4 + 575300e commit 10a8f4e

File tree

6 files changed

+52
-21
lines changed

6 files changed

+52
-21
lines changed

stdlib/public/core/FloatingPoint.swift.gyb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,14 @@ public struct ${Self} {
198198
extension ${Self} : CustomStringConvertible {
199199
/// A textual representation of `self`.
200200
public var description: String {
201-
return _float${bits}ToString(self)
201+
return _float${bits}ToString(self, debug: false)
202+
}
203+
}
204+
205+
extension ${Self} : CustomDebugStringConvertible {
206+
/// A textual representation of `self`.
207+
public var debugDescription: String {
208+
return _float${bits}ToString(self, debug: true)
202209
}
203210
}
204211

stdlib/public/core/Runtime.swift.gyb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,19 +355,20 @@ struct _Buffer72 {
355355
@_silgen_name("swift_float${bits}ToString")
356356
func _float${bits}ToStringImpl(
357357
buffer: UnsafeMutablePointer<UTF8.CodeUnit>,
358-
_ bufferLength: UInt, _ value: Float${bits}
358+
_ bufferLength: UInt, _ value: Float${bits},
359+
_ debug: Bool
359360
) -> UInt
360361

361362
@warn_unused_result
362-
func _float${bits}ToString(value: Float${bits}) -> String {
363+
func _float${bits}ToString(value: Float${bits}, debug: Bool) -> String {
363364
_sanityCheck(sizeof(_Buffer32.self) == 32)
364365
_sanityCheck(sizeof(_Buffer72.self) == 72)
365366

366367
var buffer = _Buffer32()
367368
return withUnsafeMutablePointer(&buffer) {
368369
(bufferPtr) in
369370
let bufferUTF8Ptr = UnsafeMutablePointer<UTF8.CodeUnit>(bufferPtr)
370-
let actualLength = _float${bits}ToStringImpl(bufferUTF8Ptr, 32, value)
371+
let actualLength = _float${bits}ToStringImpl(bufferUTF8Ptr, 32, value, debug)
371372
return String._fromWellFormedCodeUnitSequence(
372373
UTF8.self,
373374
input: UnsafeBufferPointer(

stdlib/public/stubs/Stubs.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,16 @@ static int swift_snprintf_l(char *Str, size_t StrSize, locale_t Locale,
141141

142142
template <typename T>
143143
static uint64_t swift_floatingPointToString(char *Buffer, size_t BufferLength,
144-
T Value, const char *Format) {
144+
T Value, const char *Format,
145+
bool Debug) {
145146
if (BufferLength < 32)
146147
swift::crash("swift_floatingPointToString: insufficient buffer size");
147148

148-
const int Precision = std::numeric_limits<T>::digits10;
149-
149+
int Precision = std::numeric_limits<T>::digits10;
150+
if (Debug) {
151+
Precision = std::numeric_limits<T>::max_digits10;
152+
}
153+
150154
// Pass a null locale to use the C locale.
151155
int i = swift_snprintf_l(Buffer, BufferLength, /*locale=*/nullptr, Format,
152156
Precision, Value);
@@ -170,21 +174,21 @@ static uint64_t swift_floatingPointToString(char *Buffer, size_t BufferLength,
170174
}
171175

172176
extern "C" uint64_t swift_float32ToString(char *Buffer, size_t BufferLength,
173-
float Value) {
177+
float Value, bool Debug) {
174178
return swift_floatingPointToString<float>(Buffer, BufferLength, Value,
175-
"%0.*g");
179+
"%0.*g", Debug);
176180
}
177181

178182
extern "C" uint64_t swift_float64ToString(char *Buffer, size_t BufferLength,
179-
double Value) {
183+
double Value, bool Debug) {
180184
return swift_floatingPointToString<double>(Buffer, BufferLength, Value,
181-
"%0.*g");
185+
"%0.*g", Debug);
182186
}
183187

184188
extern "C" uint64_t swift_float80ToString(char *Buffer, size_t BufferLength,
185-
long double Value) {
189+
long double Value, bool Debug) {
186190
return swift_floatingPointToString<long double>(Buffer, BufferLength, Value,
187-
"%0.*Lg");
191+
"%0.*Lg", Debug);
188192
}
189193

190194
/// \param[out] LinePtr Replaced with the pointer to the malloc()-allocated

test/1_stdlib/Interval.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ IntervalTestSuite.test("CustomStringConvertible/CustomDebugStringConvertible") {
169169
expectEqual("0.0...0.1", String(X(0.0)...X(0.1)))
170170

171171
expectEqual(
172-
"HalfOpenInterval(X(0.0)..<X(0.1))",
173-
String(reflecting: HalfOpenInterval(X(0.0)..<X(0.1))))
172+
"HalfOpenInterval(X(0.0)..<X(0.5))",
173+
String(reflecting: HalfOpenInterval(X(0.0)..<X(0.5))))
174174
expectEqual(
175-
"ClosedInterval(X(0.0)...X(0.1))",
176-
String(reflecting: ClosedInterval(X(0.0)...X(0.1))))
175+
"ClosedInterval(X(0.0)...X(0.5))",
176+
String(reflecting: ClosedInterval(X(0.0)...X(0.5))))
177177
}
178178

179179
IntervalTestSuite.test("rdar12016900") {

test/1_stdlib/Print.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func debugPrintedIs<T>(
8383
) {
8484
var actual = ""
8585
debugPrint(object, terminator: "", toStream: &actual)
86-
if expected1 != actual && (expected2 != nil && expected2! != actual) {
86+
if expected1 != actual && (expected2 == nil || expected2! != actual) {
8787
print(
8888
"check failed at \(file), line \(line)",
8989
"expected: \"\(expected1)\" or \"\(expected2)\"",
@@ -409,6 +409,23 @@ func test_FloatingPointPrinting() {
409409
printedIs(asFloat80(0.0000000000000000125), "1.25e-17")
410410
#endif
411411

412+
debugPrintedIs(asFloat32(1.1), "1.10000002")
413+
debugPrintedIs(asFloat32(125000000000000000.0), "1.24999998e+17")
414+
debugPrintedIs(asFloat32(1.25), "1.25")
415+
debugPrintedIs(asFloat32(0.0000125), "1.24999997e-05")
416+
417+
debugPrintedIs(asFloat64(1.1), "1.1000000000000001")
418+
debugPrintedIs(asFloat64(125000000000000000.0), "1.25e+17")
419+
debugPrintedIs(asFloat64(1.25), "1.25")
420+
debugPrintedIs(asFloat64(0.0000125), "1.2500000000000001e-05")
421+
422+
#if arch(i386) || arch(x86_64)
423+
debugPrintedIs(asFloat80(1.1), "1.10000000000000000002")
424+
debugPrintedIs(asFloat80(125000000000000000.0), "125000000000000000.0")
425+
debugPrintedIs(asFloat80(1.25), "1.25")
426+
debugPrintedIs(asFloat80(0.0000125), "1.25000000000000000001e-05")
427+
#endif
428+
412429
print("test_FloatingPointPrinting done")
413430
}
414431
test_FloatingPointPrinting()

test/Interpreter/SDK/objc_cast.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,16 +426,18 @@ if let strArr = objImplicitOpt as? [String] {
426426
}
427427

428428
// Casting an array of numbers to different numbers.
429-
// CHECK: Numbers-as-doubles cast produces [3.14159, 2.71828, 0.0]
430-
obj = ([3.14159, 2.71828, 0] as [Double]) as AnyObject
429+
// CHECK: Numbers-as-doubles cast produces [3.9375, 2.71828, 0.0]
430+
obj = ([3.9375, 2.71828, 0] as [Double]) as AnyObject
431431
if let doubleArr = obj as? [Double] {
432+
print(sizeof(Double.self))
432433
print("Numbers-as-doubles cast produces \(doubleArr)")
433434
} else {
434435
print("Numbers-as-doubles failed")
435436
}
436437

437-
// CHECK: Numbers-as-floats cast produces [3.14159{{.*}}, 2.71828{{.*}}, 0.0]
438+
// CHECK: Numbers-as-floats cast produces [3.9375, 2.71828{{.*}}, 0.0]
438439
if let floatArr = obj as? [Float] {
440+
print(sizeof(Float.self))
439441
print("Numbers-as-floats cast produces \(floatArr)")
440442
} else {
441443
print("Numbers-as-floats failed")

0 commit comments

Comments
 (0)