How to separate thousands from a Float value with decimals in Swift - swift

I have the following Float: 1123455432.67899
My desired result is a String: 1,123,455,432.67899
Best case correct , and . based on location (US/Europe)
struct Number {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter
}()
}
let myFloat: Float = 1123455432.67899
let myNumber = NSNumber(value: myFloat)
let formatter = Number.withSeparator
if let result = formatter.string(from: myNumber) {
print(result)
}
This formatter works great as long as my Float has no decimals, als soon as I'm having decimals it starts to "calculate". It calculates up/down based on the 3rd decimal number.
What am I missing? What's the best way to get a String: 1,123,455,432.67899 from a Float with no matter how many decimal numbers? Help is very appreciated.
Edit:
My exact function:
func formatValue(_ value: String ) -> String {
if let double = Double(value) {
let formatter = Number.withSeparator
if let result = formatter.string(from: NSNumber(value: double)) {
return result
} else {
return value
}
} else {
return value
}
}
value is always a number for example 5.5555555555. But in this specific case the result = 5.556.

Use Double instead of Float, the value you are specifying is not well representable in Float:
// [... your current code ...]
let myDouble: Double = 1123455432.67899
let myNumber = NSNumber(value: myDouble)
// [... your current code ...]
1,123,455,432.679
The e+XX notation Float has by default is not just for show, it is there because Float cannot store all digits. See:
let myFloat2: Float = 1123455432.67899
print(myFloat2 == 1123455432) // true
let notRepresentable = Float(exactly:1123455432.67899) // nil

Fundamentally, your issue comes from the floating point imprecision of Float. Using a double precision floating point data type (Double) will alleviate this, to an extent.
Also, you shouldn't hardcode the groupingSeperator, but instead let it be inferred from the current locale (which is the default behaviour).
import Foundation
let numberFormatter: NumberFormatter = {
let nf = NumberFormatter()
nf.numberStyle = .decimal
return nf
}()
let myDouble = 1123455432.67899
let myNumber = NSNumber(value: myDouble)
// It's also directly initializable from a literal
// let myNumber: NSNumber = 1123455432.67899
guard let result = numberFormatter.string(from: myNumber) else { fatalError() }
print(result)

In addition to luk2302's answer, I would suggest to add it as a method to a Double extension, as follows:
extension Double {
func formattedString(_ maximumFractionDigits: Int = 5) -> String? {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = maximumFractionDigits
return numberFormatter.string(for:self)
}
}
if let formattedString = 1123455432.67899.formattedString() {
print(formattedString) // 1,123,455,432.67899
}
It might improve the ease of getting the desired string.
Thanks for #rmaddy and #LeoDabus for providing useful notes.

Related

How to convert number to words in swift by using func

Given the integer 'number' in the range of 0 ..<< 1000, print the number as a word.
For example, given: let number : Int = 125
output should be one-hundred and twenty-five
You can use NumberFormatter pretty effectively :) Here's example
let numberFormatter = NumberFormatter()
let number = 12355532
numberFormatter.numberStyle = .spellOut
let numberAsWord = numberFormatter.string(from: NSNumber(value: number))
print(numberAsWord)
You could also extend NSNumber to do this behind the scenes like this
public extension NSNumber {
var spelledOut: String? {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter.string(from: self)
}
}
To avoid creating a Number Formatter every time you call this property you can create a static formatter. You can also make the computed property generic to support all numeric types:
extension NumberFormatter {
static let spelled: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter
}()
}
extension Numeric {
var spelledOut: String? { NumberFormatter.spelled.string(for: self) }
}
let integer = 1234
let integerSpelled = integer.spelledOut // "one thousand two hundred thirty-four"
let double = 123.4
let doubleSpelled = double.spelledOut // "one hundred twenty-three point four"

In Swift 5, How to convert a Float to a String localized in order to display it in a textField?

I need to convert a Float to a localized String.
i write this function which is an extension from Float:
func afficherUnFloat() -> String {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = Locale.current
//numberFormatter.maximumFractionDigits = 2
//numberFormatter.maximumIntegerDigits = 6
if let result = numberFormatter.number(from: self) {
return numberFormatter.string(for: result) ?? "0"
}
return "0"
}
but it didn't work:
Here is the exemple
let xxx : Float = 111.222
myTextField.text = String(xxx).afficherUnFloat()
I have installed a pod KSNumericTextField, that limit the numbers in the textfield. He display it only if it is locally formatted.
When i run the app, it doesn't diplay 111,222 in a french region, or 111,222 in an arabic one.
nothing is dislpayed
Note that there is no need to cast your Float to NSNumber. You can use Formatter's method string(for: Any) instead of NumberFormatter's method string(from: NSNumber). Btw it will create a new number formatter every time you call this property. I would make your formatter static:
extension Formatter {
static let decimal: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = .current
numberFormatter.maximumFractionDigits = 2 // your choice
numberFormatter.maximumIntegerDigits = 6 // your choice
return numberFormatter
}()
}
extension FloatingPoint {
var afficherUnFloat: String { Formatter.decimal.string(for: self) ?? "" }
}
let float: Float = 111.222
let string = float.afficherUnFloat // "111.22"
Here is finaly a solution:
extension Float {
func afficherUnFloat() -> String {
let text : NSNumber = self as NSNumber
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.locale = .current
numberFormatter.groupingSeparator = ""
numberFormatter.maximumFractionDigits = 2 // your choice
numberFormatter.maximumIntegerDigits = 6 // your choice
let result = numberFormatter.string(from: text) ?? ""
return result
}
}
With this, you can format every Float to a localized String, compatible with the keyboard choosen by the user, regardless of his locality or langage.
There is no need to force a special keyboard to have a specific decimal separator.
you can use it like this:
let myFloat: Float = 111.222
let myString :String = myFloat.afficherUnFloat()
myString will be displayed as the location requires

Converting text field data to decimal value and back to string

I converted text field string into a double to do calculations and then back to a string to output it on a label. I am now working with currency inputs so I need to convert it to a decimal rather than a double. Can someone help?
func calcTotal() {
let totalConv: Double? = Double(totalTextField.text!)
let tipConv: Double? = Double(tipTextField.text!)
guard totalConv != nil && tipConv != nil else {
return
}
let result = totalConv! * ((tipConv! / 100) + 1)
let output = String(format: "$ %.2f", result)
totalAmount.text = String(output)
}
You will just need to use Decimal(string:) initializer and NumberFormatter (currency style) to format your decimal value.
func calcTotal() {
guard
let totalConv = Decimal(string: totalTextField.text!),
let tipConv = Decimal(string: tipTextField.text!)
else { return }
let result = totalConv * ((tipConv / 100) + 1)
totalAmount.text = Formatter.currency.string(for: result)
}
extension Formatter {
static let currency: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
return numberFormatter
}()
}

Change scientific notation to decimal in swift

I want to convert a float value from 1e-05 to 0.00001 in Swift.
I used the following extension:
extension Float {
var avoidNotation: String {
let numberFormatter = NumberFormatter()
numberFormatter.allowsFloats = true
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter.number(from: "\(self)")!.stringValue
}
}
But when I try to using with float value like 1e-05.avoidNotation result its the same, insted of 0.00001
You should use Formatter's string(for:) method instead of getting the stringValue from the number resulting from your string interpolation:
extension Float {
var avoidNotation: String {
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter.string(for: self) ?? ""
}
}
Float(1e-05).avoidNotation // "0.00001"
I would recommend also instead of creating a NumberFormatter every time you call that property extending Formatter and adding a static formatter. You can also extend FloatingPoint instead of Float so you extend all Floating Point types:
extension Formatter {
static let avoidNotation: NumberFormatter = {
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 8
numberFormatter.numberStyle = .decimal
return numberFormatter
}()
}
extension FloatingPoint {
var avoidNotation: String {
return Formatter.avoidNotation.string(for: self) ?? ""
}
}
Float(1e-05).avoidNotation // "0.00001"
Swift 4.2
Disable scientific notation:
let number = NSNumber(value: floatValue)
print(number.decimalValue)
Extension:
extension Float {
func avoidNotation() -> String {
let number = NSNumber(value: self)
return "\(number.decimalValue)"
}
}

How to convert Long Double to String in swift

I would like to print data Double in Swift, but the output is always 4.444444444444e+24, not a real number.
How can I do that?
An even easier approach to format your Doubles without scientific notation would be to use String(format: "%.0f", data)
Note that Double cannot hold 44444444444444444.0 correctly, therefore you would probably get something like 44444444444444448 as output.
To get correct results you should use NSDecimalNumber, like this:
let decimalNumber = NSDecimalNumber(string: "44444444444444444.0")
print(decimalNumber.stringValue)
See if this helps you...
This code converts a number from scientific format to normal format
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let finalNumber = numberFormatter.number(from: "\(1e+07)")
print(finalNumber!)
This is the result: 10000000
#Skytect's answer is almost correct. It is just missing one step. Try the following code
let data1 : Double = 44444444444444444.0
let data2 : Double = 1000000.0
let data3 = data1 * data2
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let num = NSNumber(value: data3)
let finalNumber = numberFormatter.string(from: num)
print(finalNumber!)
More Class and Class func way
class Formatter {
static let numberFormatter: NumberFormatter = {
$0.minimumFractionDigits = 0
$0.maximumFractionDigits = 1
return $0
}(NumberFormatter())
class func string(from double: Double) -> String {
let nsNumber = NSNumber(value: double)
guard let formattedString = numberFormatter.string(from: nsNumber) else { fatalError("Should never happen") }
return formattedString
}
}
Usage
UITextField.text = Formatter.string(from: double)