Int won't show numbers after the comma - swift

I want to get from a string to a int. My problem is now that i'll get a int value but it wont show the number after the comma. If the string is -0,23, than the int will print 0.How can i fix this? Please help.
let int = (percent_change_24hArray[indexPath.row] as NSString).integerValue

You will probably have to use a NumberFormatter for that, set up for your locale. In the US, the decimal separator is a period. (".") A comma is considered a delimiter.
Plus, assuming you are in a locale where the decimal separator is a comma, converting to an integer will truncate the part after the decimal separator anyway.
Code like the code below should work:
var str = "-0,23"
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "fr_FR")
let aVal = formatter.number(from: str)?.doubleValue
(I'm using France's French as the locale since France uses a comma as a decimal separator.)
Note that you need to think carefully about where you numeric strings come from in order to decide how to handle locale. if these are user-entered strings then you should probably use a number formatter with the default locale for the device. That way a European user can use a comma as a decimal separator and a US user can use a period as a decimal separator and both will work.

You need to use a float, integers don't take numbers after the comma
https://developer.apple.com/documentation/swift/float

Related

String Format Specifiers : rounding rule used for decimal values

I am using String(format:) to convert a Float. I thought the number would be rounded.
Sometimes it is.
String(format: "%.02f", 1.455) //"1.46"
Sometimes not.
String(format: "%.02f", 1.555) //"1.55"
String(round(1.555 * 100) / 100.0) //"1.56"
I guess 1.55 cannot be represented exactly as binary. And that it becomes something like 1.549999XXXX
But NumberFormatter doesn't seem to cause the same problem... Why? Should it be preferred over String(format:)?
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
if let string = formatter.string(for: 1.555) {
print(string) // 1.56
}
Reference to the problem (to use String (format :) to round a decimal number) can be found in the answers (or more often comments) to these questions: Rounding a double value to x number of decimal places in swift and How to format a Double into Currency - Swift 3. But the problem it covers (math with FloatingPoint) has been dealt with many times on SO (for all languages).
String(format:) does not have the function of rounding a decimal number (even if it is unfortunately proposed in some answers) but of formatting it (as its name suggests). This formatting sometimes causes a rounding. That is true. But we have to keep in mind a problem that the number 1.555 is... not worth 1.555.
In Swift, Double and Float, that conform to the FloatingPoint protocol respect the IEEE 754 specification. However, some values ​​cannot be exactly represented by the IEEE 754 standard.
In the same way that you can't represent a third exactly in a (finite) decimal expansion, there are lots of numbers which look simple in decimal, but which have long or infinite expansions in a binary expansion." (source)
To be convinced of this, we can use The Float Converter to convert between the decimal representation of numbers (like "1.02") and the binary format used by all modern CPUs (IEEE 754 floating point). For 1.555, the value actually stored in float is 1.55499994754791259765625
So the problem does not come from String (format :). For example, we can try another way to round to the thousandth and we find the same problem. :
round (8.45 * pow (10.0, 3.0)) / pow (10.0, 3.0)
// 8.449999999999999
That is how it is : "Binary floating point arithmetic is fine so long as you know what's going on and don't expect values ​​to be exactly the decimal ones you put in your program".
So the real question is : is this really a problem for you to use ? It depends on the app. Generally if we convert a number into a String by limiting its precision (by rounding), it is because we consider that this precision is not useful to the user. If this is the kind of data we're talking about, then it's okay to use a FloatingPoint.
However, to format it it may be more relevant to use a NumberFormatter. Not necessarily for its rounding algorithm, but rather because it allows you to locate the format :
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
formatter.locale = Locale(identifier: "fr_FR")
formatter.string(for: 1.55)!
// 1,55
formatter.locale = Locale(identifier: "en_US")
formatter.string(for: 1.55)!
// 1.55
Conversely, if we are in a case where precision matters, we must abandon Double / Float and use Decimal. Still to keep our rounding example, we can use this extension (which may be the best answer to the question "Rounding a double value to x number of decimal places in swift ") :
extension Double {
func roundedDecimal(to scale: Int = 0, mode: NSDecimalNumber.RoundingMode = .plain) -> Decimal {
var decimalValue = Decimal(self)
var result = Decimal()
NSDecimalRound(&result, &decimalValue, scale, mode)
return result
}
}
1.555.roundedDecimal(to: 2)
// 1.56

Formatting percent number to zh (simplified Chinese) using the right percent sign (ie. %)

I'd like to use NumberFormatter to generate zh-localised percents as follows, in order to supersede my own code as follow:
let locale = Locale(identifier: lang)
let formatter = NumberFormatter()
formatter.locale = locale
formatter.numberStyle = .percent
formatter.maximumFractionDigits = d
let number = NSNumber(value: Double(n))
if let r = formatter.string(from: number) {
if lang == "zh" { return r.replace(["%"], withString: "%")
return r
}
// My fallback code
Unfortunately, unlike my code, in simplified Chinese NumberFormatter generates latin % sign rather than the chinese version % (hence the replacement patch I do).
I am wondering if one could tweak NumberFormatter further so that it take care of it? (and in other non-latin languages).
You seem to imply that what NumberFormatter outputs is incorrect. However, as a native Chinese, I can confidently say that "50%" is the natural way of writing a percentage in the zh locale. This is also evident from this Baidu Baike (Chinese counterpart of Wikipedia) article. I have never seen any app write percentages with the full-width percentage sign. I can't even type it with the Chinese IME on my Mac.
To my eyes, "50%" looks weird, probably because it's mixing full-width and half-width characters. I've occasionally seen "50%" in Japanese sites, but it's still rather rare.
if you really want, you can set the percentSymbol property in NumberFormatter:
let formatter = NumberFormatter()
formatter.percentSymbol = "%"
formatter.numberStyle = .percent
print(formatter.string(from: 0.5) ?? "failed")
To be honest, I would trust the output of NumberFormatter, which is designed by a bunch of professional localisation engineers.

How to convert NSString to float without rounding it?

I have tried the following but when I convert the string it is automatically rounded.
let str = "10,60"
let str2 = (str as NSString).floatValue //prints "10.0"
//What I would like to do
let str2 = (str as NSSTring).floatValueNotRounded //prints "10,60"
.floatValue does not handle local formats and your number uses a comma as the decimal point - the the parse just stops at the comma and you get 10. Use either NumberFormatter or Scanner to parse localised numbers. E.g.:
let formatter = NumberFormatter()
let val = formatter.number(from: str)
should work provided your locale uses the comma as the decimal point. If you are in one locale and wish to parse numbers written according to another you can set locale property of the formatter.

Add leading and trailing zeroes to a string/label in swift

In swift I know how to set the number of digits after the decimal point when converting a double to a string:
String(format: "%0.2f", someDouble)
Similarly I know how to set the number of digits before the decimal point:
String(format: "%02d", someDouble)
But how can I do both?
I want the string to always have a 00.00 format.
Thanks
You simply combine the two:
String(format: "%05.2f", someDouble)
The 0 means fill with leading zeros as needed.
The 5 means you want the final output to be at least 5 characters, include the decimal point.
The .2 means you want two decimal places.
If this is a number you are showing to a user then you should probably use NumberFormatter so the decimal is properly formatted for the user's locale.

Convert NumberFormatter.Style.spellOut to Int

Try to find a way to convert plain English number (e.g., One, Two...) to Int (e.g., 1, 2...)
I know that there is way to convert from Int to English using
numberFormatter:NumberFormatter = NumberFormatter()
numberFormatter.numberStyle = NumberFormatter.Style.spellOut
var string = numberFormatter.string(from: 3) // "three"
Is there any reverse way of converting this?
I am trying to avoid using array of String like ["One", "Two"..]
Number formatters work in both directions, so you can just use:
let num = numberFormatter.number(from: string)
But you'll need to take some care to make sure it exactly matches the output of the forward direction. "three" will translate to 3, but "Three" won't.
As Sulthan notes, this is absolutely sensitive to the locale of the formatter (which you can set to be different than the user's locale if that's necessary). It is strongly assuming that the input and output from the same formatter match.