Keeping Trailing Zeros from .doubleValue() in Swift - swift

I am working on an application that needs to do some displaying and calculating of Double types in Swift. The struct that I created takes a Double as a parameter, and since it also displays it, I would like to keep the trailing zero at the end of the value. However, I cannot seem to keep the trailing zero from being truncated.
Here is what I have been trying in a Playground:
let numberString = "-3.60"
// "3.60"
let positiveString = numberString.stringByReplacingOccurrencesOfString("-", withString: "", options: nil, range: nil)
// 3.6
let positiveDouble = (positiveString as NSString).doubleValue
// "3.60"
let positiveDoubleString = NSString(format: "%0.02f", positiveDouble)
// 3.6
let positiveDoubleWithZeros = positiveDoubleString.doubleValue
I keep getting 3.6 as the result, no matter what I try. What is the obvious part of the conversion that I am missing?

You have to use NSNumberFormatter:
let formatter = NSNumberFormatter()
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 3
println(formatter.stringFromNumber(1.0000))
println(formatter.stringFromNumber(1.2345))
This example will print 1.00 for the first case and 1.234 for the second, the number of minimum and maximum decimal places can be adjust as you need.
I Hope that helps you!

Related

String number with limited precision fraction digits in Swift

What would be the fastest way to convert a String number "1234.5678" to an NSNumber with precision -> 1234.56 and back to String "1234.56".
let numberFormatter = NumberFormatter()
numberFormatter.maximumFractionDigits = 2
numberFormatter.string(from: numberFormatter.number(from: "1234.534234")!)
This code does not look that beautiful. Any ideas?
You can use the new formatted method and specify the number of precision fraction length to two:
let decimal = Decimal(
sign: .plus,
exponent: -4,
significand: 12345678
) // 1234.5678
decimal.formatted(.number.precision(.fractionLength(2))) // "1,234.57"
decimal.formatted(.number.grouping(.never).precision(.fractionLength(2))) // "1234.57"
decimal.formatted(.number.grouping(.never).rounded(rule: .towardZero).precision(.fractionLength(2))) // "1234.56"
Alternatively if you are only interested in the string regardless of any numeric modification like rounding you can strip the unwanted characters with Regular Expression
let string = "1234.5678"
let trimmedString = string.replacingOccurrences(of: "(\\d+\\.\\d{2})\\d.",
with: "$1",
options: .regularExpression)

How to get the first number after a decimal point of a Double?

I have a Double like this:
339.09965653839
How can I get the first number after the dot?
0 // desired result
I tried to look into similar questions but unfortunately I found only ways to separate a double in two parts also these two Double. I would like to have an Int and then be able to print it as a string.
To get the digit as an Int, you can do a little math:
let someNum = 339.09965653839
let digit = Int((someNum - Double(Int(someNum))) * 10)
And of course it is trivial to display digit in/as a string as needed.
Or, alternatively:
let number = 123.456
// 1234 % 123 = 4
let digit = Int(number * 10) % Int(number)
Convert double to string and fetch the first character after dot.
let value = 339.09965653839
let valueInString = "\(value)".split(separator: ".")
print(valueInString[1].first ?? "")

How to convert Exponential Value to Decimal Value

let balance = "2.477854178281608e-06"
// I have to convert this exponential value in Decimal
/* Already tried the below-mentioned solution, but not working */
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let finalNumber = numberFormatter.number(from: balance)
print(finalNumber!)
Value is printing "2.477854178281608e-06\n"
Any help will be appreciated.
let balance = "2.477854178281608e-06"
// I have to convert this exponential value in Decimal
This is not an exponential value. This is a string that represents a number using exponential format. You seem to want a string representing the same number in a different format. The important thing here is that neither string is "the value." The value is the same regardless of representation (or approximately the same if the representation is limited).
So first you need the value represented by the string. To do that, convert it to a Double.
let value = Double(balance)!
Now, you say you want to convert that to a string in decimal format (I assume you mean 0.000...). So you need a formatter:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 20
let string = numberFormatter.string(for: value)!
print(string) // 0.00000247785417828161
You'll note that this value is slightly different than the previous value. That's because there are rounding errors when dealing with values this small.
If all of these base-10 digits are important, you can work with the Decimal type rather than Double. This avoids decimal/binary rounding, but is less convenient and slower for some kinds of math. If this is a type of currency that is expressed in base-10 units (which is basically all of them), you always want to work with Decimal and never with Double.
let balance = "2.477854178281608e-06"
let value = Decimal(string: balance)!
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 21
let string = numberFormatter.string(for: value)!
print(string) // 0.000002477854178281608

How to properly handle comparison between double values in Swift?

I know similar question has been asked but I still could not figured out the solution.
I am getting double value like this.
let priceUsdInt = (price as NSString).doubleValue
And I want to compare this value to 1.00 so:
if priceUsdInt > 1.00 {
let priceUsdCur = priceUsdInt.currencyUS
finalPriceUsdCur = priceUsdCur
} else {
let priceUsdCur = priceUsdInt.currencyUS6
finalPriceUsdCur = priceUsdCur
}
This always bring two decimal results. Even-though value is way lower then 1.00.
Basically, what I want to achieve is if value is lesser then 1.00 then show it until six decimals i.e. 0.123456 when converted to currency format, if not show only two decimals after it i.e. 1.23.
Thank you for your time.
This demonstrates showing a 6 digit precision in currency formatting when the value from string coverted to double value is below 1.0 and 2 digit precision when its above 1.0
let belowOne = ".12023456"
let belowDoubleVal = Double(belowOne) ?? 0.0
let currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currency
if belowDoubleVal < 1.0 {
// this handles the 6 digit precision you require when value is below 1.0
currencyFormatter.minimumFractionDigits = 6
}
// old way using NSSNumber
// let belowOneString = currencyFormatter.string(from: NSNumber(value: belowDoubleVal))
// you can pass the double value to formatter using .string(for: Any)
// thanks for pointing this out by Leo Dabus
let belowOneString = currencyFormatter.string(for: belowDoubleVal)

No scientific notation and rounding with double

I want to round a number to 6 places and I don't want it to be displayed using scientific notation. I am using this code to round the decimal to 6 places but if the value is really small, it is still displaying it using scientific notation. I know that I can use the number formatter (displayed below as well) to remove the scientific notation but if I do that then it is returns a string so I cannot round a string to a certain number of decimal places. If I do the rounding first, that still doesn't work in all scenarios. It still shows some numbers without rounding. What is the best way to achieve this? It should work in all different scenarios where numbers are infinitely long or repeating
extension Double {
// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.decimal
numberFormatter.number(from:"")
I tried to use this code
let currentValue = 1/2.3344 //answer is 0.42837559972584...
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.decimal
numberFormatter.maximumFractionDigits = 6
guard let finalNum = numberFormatter.number(from: String(describing: currentValue)) else {return nil}
text = String (describing: finalNum)
I want it to display 0.428375. The value rounded to 6 decimal places.
When the current value is this: let currentValue = 1/233442 which is 0.00000428371... I want it to display 0.000004. The decimal rounded to 6 decimal places and not in scientific notation.
When the current value is this: let currentValue = 1/2334429 I want it to display 0 because that is the value rounded to 6 decimal places.
The number(from: someString) method converts a string to a number,
you want it the other way around:
let currentEntry = 1/2.3344
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.maximumFractionDigits = 6
guard let text = numberFormatter.string(for: currentEntry) else {
// ...
}
print(text) // 0.428376
Note that your String(describing:) conversions only hide the problem.
You really should avoid String(describing:) (even if the compiler suggests
it as a Fix-it!), it almost never does what you need.