Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Formatting decimal places with unknown number

Tags:

logic

swift

I'm printing out a number whose value I don't know. In most cases the number is whole or has a trailing .5. In some cases the number ends in .25 or .75, and very rarely the number goes to the thousandths place. How do I specifically detect that last case? Right now my code detects a whole number (0 decimal places), exactly .5 (1 decimal), and then reverts to 2 decimal spots in all other scenarios, but I need to go to 3 when it calls for that.

class func getFormattedNumber(number: Float) -> NSString {

    var formattedNumber = NSString()

    // Use the absolute value so it works even if number is negative
    if (abs(number % 2) == 0) || (abs(number % 2) == 1) {  // Whole number, even or odd
        formattedNumber = NSString(format: "%.0f", number)
    }

    else if (abs(number % 2) == 0.5) || (abs(number % 2) == 1.5) {
        formattedNumber = NSString(format: "%.1f", number)
    }

    else {
        formattedNumber = NSString(format: "%.2f", number)
    }

    return formattedNumber

}
like image 615
Shades Avatar asked Jun 03 '15 13:06

Shades


3 Answers

A Float uses a binary (IEEE 754) representation and cannot represent all decimal fractions precisely. For example,

let x : Float = 123.456

stores in x the bytes 42f6e979, which is approximately 123.45600128173828. So does x have 3 or 14 fractional digits?

You can use NSNumberFormatter if you specify a maximum number of decimal digits that should be presented:

let fmt = NSNumberFormatter()
fmt.locale = NSLocale(localeIdentifier: "en_US_POSIX")
fmt.maximumFractionDigits = 3
fmt.minimumFractionDigits = 0

println(fmt.stringFromNumber(123)!)      // 123
println(fmt.stringFromNumber(123.4)!)    // 123.4
println(fmt.stringFromNumber(123.45)!)   // 123.45
println(fmt.stringFromNumber(123.456)!)  // 123.456
println(fmt.stringFromNumber(123.4567)!) // 123.457

Swift 3/4 update:

let fmt = NumberFormatter()
fmt.locale = Locale(identifier: "en_US_POSIX")
fmt.maximumFractionDigits = 3
fmt.minimumFractionDigits = 0

print(fmt.string(for: 123.456)!) // 123.456
like image 155
Martin R Avatar answered Sep 30 '22 19:09

Martin R


You can use %g to suppress trailing zeros. Then I think you do not need to go through the business of determining the number of places. Eg -

var num1:Double = 5.5
var x = String(format: "%g", num1) // "5.5"

var num2:Double = 5.75
var x = String(format: "%g", num2) // "5.75"

Or this variation where the number of places is specified. Eg -

var num3:Double = 5.123456789
var x = String(format: "%.5g", num3) // "5.1235"
like image 43
simons Avatar answered Sep 30 '22 19:09

simons


My 2 cents ;) Swift 3 ready

Rounds the floating number and strips the trailing zeros to the required minimum/maximum fraction digits.

extension Double {
    func toString(minimumFractionDigits: Int = 0, maximumFractionDigits: Int = 2) -> String {
        let formatter = NumberFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.minimumFractionDigits = minimumFractionDigits
        formatter.maximumFractionDigits = maximumFractionDigits

        return formatter.string(from: self as NSNumber)!
    }
}

Usage:

Double(394.239).toString() // Output: 394.24
Double(394.239).toString(maximumFractionDigits: 1) // Output: 394.2
like image 39
AamirR Avatar answered Sep 30 '22 17:09

AamirR