Display 99.99 with 1 decimal place 99.9 Fail

I wrote a string extension


extension String {

func formatDoubleToString(value: Double, places: Int) -> String {

var result : String

if places == 1 {

result = String(format: "%.1f", value)

}

else if places == 2 {

result = String(format: "%.2f", value)

}

else {

result = String(format: "%.f", value)

}

return result

}


All my test on this extension pass except these ones where I work with .999 :

Display 99.99 with 1 decimal place 99.9

Display 9999.999 with two decimal places 9999.99


func testStringExtentionFormatDoubleToStringPlaces1_1(){

let result: String = String().formatDoubleToString(value: 99.99, places: 1)

XCTAssert(result == "99.9", "Display 99.99 with 1 decimal place 99.9")

}


func testStringExtentionFormatDoubleToStringZeroPlaces2_7(){

let result: String = String().formatDoubleToString(value: 9999.999, places: 2)

XCTAssert(result == "9999.99", "Display 9999.999 with two decimal places 9999.99")

}

Replies

You probably can't do it this way. String format specifiers (%f, etc) follow the IEEE printf formatting rules (pubs.opengroup.org/onlinepubs/009695399/functions/printf.html), and it says this about "%f":


"The double argument shall be converted to decimal notation in the style "[-]ddd.ddd", where the number of digits after the radix character is equal to the precision specification. If the precision is missing, it shall be taken as 6; if the precision is explicitly zero and no '#' flag is present, no radix character shall appear. If a radix character appears, at least one digit appears before it. The low-order digit shall be rounded in an implementation-defined manner."


I tried these in a playground:


print (String(format: "%.1f", 99.99))
print (String(format: "%.2f", 9999.999))


and it prints:


100.0
10000.00


Clearly, the "implementation-defined" rounding takes the requested precision into account. You can code around this if you want, but the result would be lying: 99.99 is a lot closer to 100.0 than it is to 99.9.

let number = 99.9999

let ret1 = floor(number * 10) / 10 // 99.9

let ret2 = floor(number * 100) / 100 // 99.99