Swift. How to set custom number format? With space thouthand separator and two digits after point - swift

I need separate thouthands with space, and two digit after point.
let d1: Double = 20000000.0
let d2: Double = 1.2345
I want to view:
let s1 = String(format: "????", d1) //20 000 000.00
let s2 = String(format: "????", d2) //1.23
How to do it?

let d1: Double = 20000000.0
let d2: Double = 1.2345
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.decimalSeparator = "." // Default separator is dependent to the current local.
print(formatter.string(for: d1)) // 20 000 000.00
print(formatter.string(for: d2)) // 1.23

Related

NSNumberFormatter and .floor roundingMode

Can someone tell me why this happening?
let formatter = NumberFormatter.init()
formatter.numberStyle = .decimal
formatter.usesGroupingSeparator = false
formatter.roundingMode = .floor
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
let v = 36
let scale = 10
let float = formatter.string(from: NSNumber(value: Float(v) / Float(scale)))!
let double = formatter.string(from: NSNumber(value: Double(v) / Double(scale)))!
print(float) // 3.59
print(double) // 3.60
When I use Float the result is 3.59 (wrong result in my opinion) and when I use Double the result is 3.60.
I know it is something related to .floor roundingMode, but i don't fully understand the reason.
If you would like to preserve your fraction digits precision it is better to use Swift native Decimal type. That's what it is. You can use the Decimal init(sign: FloatingPointSign, exponent: Int, significand: Decimal) initializer and use your scale exponent and your value significand. Just make sure to negate its value:
extension SignedInteger {
var negated: Self { self * -1 }
}
let v = 36
let scale = 10
let sign: FloatingPointSign = v >= 0 ? .plus : .minus
let exponent = Decimal(scale).exponent.negated
let significand = Decimal(v).significand
let decimal = Decimal.init(sign: sign, exponent: exponent, significand: significand)
let formatted = formatter.string(for: decimal) // "3.60"

When rounding swift double it shows different numbers

When I got two numbers, like 5.085 and 70.085. My code rounds the first number to 5.09, but the second one it goes to 70.08. For some reason, when making let aux1 = aux * 100 the value goes to 7008.49999999. Any one have the solution to it?
Here is my code:
let aux = Double(value)!
let aux1 = aux * 100
let aux2 = (aux1).rounded()
let number = aux2 / 100
return formatter.string(from: NSNumber(value: number))!
If you want to format the Double by rounding it's fraction digits. Try't:
First, implement this method
func formatDouble(_ double: Double, withFractionDigits digits: Int) -> String{
let formatter = NumberFormatter()
formatter.maximumFractionDigits = digits
let string = formatter.string(from: (NSNumber(floatLiteral: double)))!
return string
/*if you want a Double instead of a String, change the return value and uncomment the bellow lines*/
//let number = formatter.number(from: string)!
//return number.doubleValue
}
after, you can call't that way
let roundedNumber = formatDouble(Double(value)!, withFractionDigits: 2)

Swift 4 String formatter to currency

I have string 99897.05 and I want to convert it like this 99 897.05
example:
input: 8121.1
output 8 121.1
input 111111.11
output 111 111.11
What you need is the currencyGroupingSeparator:
let amount = 99897.05
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyGroupingSeparator = " "
formatter.string(for: amount) //"$99 897.05"
You could change it whatever you'd like:
formatter.currencyGroupingSeparator = "💵"
formatter.string(for: amount) //"$99💵897.05"

Formatting decimal places with unknown number

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
}
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
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"
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
If you want to print a floating point number to 3 decimal places, you can use String(format: "%.3f"). This will round, so 0.10000001 becomes 0.100, 0.1009 becomes 0.101 etc.
But it sounds like you don’t want the trailing zeros, so you might want to trim them off. (is there a way to do this with format? edit: yes, g as #simons points out)
Finally, this really shouldn’t be a class function since it’s operating on primitive types. Better to either make it a free function, or perhaps extend Double/Float:
extension Double {
func toString(#decimalPlaces: Int)->String {
return String(format: "%.\(decimalPlaces)g", self)
}
}
let number = -0.3009
number.toString(decimalPlaces: 3) // -0.301

correct NSNumberFormatter for many cases in swift

i am having some problems with NSNumberFormatter and Significant Digits in swift.
var test1 : Float = 0.2345
var test2 : Float = 1234.4567
var test3 : Float = 2.234234
i want to show this values in 3 different labels (label1, label2, label3). i am looking for NSNumberFormatter so my variables could look like:
0.24
1234.46
2.23
so all of them have 2 digits after "."
and if first digit is 0 it is visible
right now my code is
var formatter = NSNumberFormatter()
formatter.maximumFractionDigits = 2
formatter.usesSignificantDigits = true
formatter.minimumSignificantDigits = 1
formatter.maximumSignificantDigits = 4
label1.text = formatter.stringFromNumber(var1)
label2.text = formatter.stringFromNumber(var2)
label3.text = formatter.stringFromNumber(var3)
Just leave
formatter.maximumFractionDigits = 2
formatter.minimumSignificantDigits = 1
and add:
formatter.numberStyle = .DecimalStyle
remove the rest:
formatter.usesSignificantDigits = true
formatter.maximumSignificantDigits = 4
It should gives you just number with 2 decimal places.