How to format string to Decimal without losing precission? [duplicate] - ios

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
Lets take a look at this simple example
let formatter = NumberFormatter()
formatter.number(from: "0.945")?.decimalValue // result: 0.945
formatter.number(from: "0.94")?.decimalValue // result: 0.9399999999999999
How can I achieve that "0.94" converts to Decimal with exact same value e.g. 0.94?
I prefer solutions with NumberFormatter because I want to use this String to Decimal conversion also for amounts with currency, such as "$0.94" and "0.94€"

This website contains explanation. Basically, computers store these numbers using a system that can't represent them very accurately.
If you need to have better accuracy, I suggesting working with decimal types such as Decimal or NSDecimalNumber:
Decimal(string: "0.945")
Decimal(string: "0.94")

Related

Why is output of {42.05 + 0.05 } like this on Dart Lang? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 1 year ago.
When i try this on DartPad output is like this. Anyone can explain ?
This is expected behavior. Double numbers cannot represent all decimal fractions precisely, and neither 0.05 nor 42.05 are the exact values that the double values represent.
The exact values are:
42.0499999999999971578290569595992565155029296875
0.05000000000000000277555756156289135105907917022705078125
If you add these two exact values, the result can yet again not be represented exactly as a double. The two closest representable doubles are:
42.099999999999994315658113919198513031005859375
42.10000000000000142108547152020037174224853515625
Of these, the former is closer to the correct result of the addition, so that is the double value chosen to represent that result.
This issue is not specific to Dart. All language using IEEE-754 64-bit floating point numbers will get the same result, and that is probably all languages with a 64-bit floating point type (C, C++, C#, Java, JavaScript, etc).

Converting Double to NSNumber in Swift Loses Accuracy [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
For some reason, certain Doubles in my Swift app are giving me trouble when converting to NSNumber, while some are not. My app needs to convert doubles with 2 decimal places (prices) to NSNumbers so they can be stored and retrieved using Core Data. For example, a few particular prices such as 79.99 would evaluate to 99.98999999999999 unless specifically formatted using NSNumber's doubleValue method.
Here selectedWarranty.price = 79.99 as shown in debugger
// item.price: NSNumber?
// selectedWarranty.price: Double?
item.price = NSNumber(double: selectedWarranty.price!)
I programmed some print statements to show how the conversion works out
Original double: 79.99
Converted to NSNumber: 79.98999999999999
.doubleValue Representation: 79.99
Can somebody explain if there is a reason why the initializer cannot surely keep 2 decimal places for every number? I would really like to store the prices in Core Data like they should be. Formatting every time it is displayed doesn't sound very convenient.
UPDATE:
Converted Core Data object to type NSDecimalNumber through data model, 79.99 and 99.99 no longer a problem, but now more manageable issue with different numbers...
Original double: 39.99
Converted to NSDecimalNumber: 39.99000000000001024
Firstly, you're confusing some terms. 79.98999999999999 is higher precision than 79.99 (it has a longer decimal expansion), but lower accuracy (it deviates from the true value).
Secondly, NSNumber does not store neither 79.99 nor 79.98999999999999. It stores the magnitude of the value according to the IEEE 754 standard. What you're seeing is likely the consequence of the printing logic that's applied to convert that magnitude into a human readable number. In any case, you should not be relying on Float or Double to store values with a fixed precision. By their very nature, they sacrifice precision in order to gain a longer range of representable values.
You would be much better off representing prices as an Int of cents, or as an NSDecimalNumber.
Please refer to Why not use Double or Float to represent currency?
That's how double works everywhere. If you need only 2 decimal places consider using integer/long instead adding point after second digit, when need to display the value.

Why NSString's doubleValue differ from the original string? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 6 years ago.
NSString is #"16.240"
it's doubleValue is 16.239999999999998
What happened behind the scenes?
Because of floating point rounding errors.
Long-story-short; not every number can be represented using floating point types.
References: #1, #2, #3.
If it is value for price (or money in general) better to use NSDecimalNumber because it is save each part of float value as is.
NSDecimalNumber *price = [NSDecimalNumber decimalNumberWithString:#"16.240"];
NSLog(price); //16.24
http://rypress.com/tutorials/objective-c/data-types/nsdecimalnumber

Swift: Creating a double from a String appends 0000000000001 to the resulting number

I am trying to get a Double value from a UITextField using Double(myTextField.text!)!. The problem is, when I enter certain numbers I get 0000000000001 appended to the end of the number. For example, Double("9.05")! gives the value 9.050000000000001 instead of the expected 9.05.
Can anyone explain why this is happening, and how I get avoid / fix it?
Thanks in advance for any help.
As several have noted, the underlying problem is that when you store 9.05 in binary, you get rounding errors. So it's not appending some value; it's showing you the correct value after rounding (in binary). This is very much like store 2/3 in decimal. You wind up with "6.66667" which seems wrong, but is due to rounding. 1/100 is "0.00000010100011110101..." in binary.
To get what you want, you need formatting. Ashish gives a working example, but it's become easier in more recent builds of Swift. You don't need as NSString anymore:
import Foundation
let strVal = "9.05"
let doubleVal = Double(strVal)! // Convert String to Double
let formattedStr = String(format: "%.2f", doubleVal) // Double -> String w/ formatting
print(formattedStr)
You may be confused about the difference between the double value and how it is represented as decimal digits. You can't express 9.05 in a finite number of binary digits, just like you can't express 2/3 in a finite number of decimal digits. There will always be some rounding error. That's why, for instance, you cannot safely compare with == two floating point numbers.
If what you really want is to do decimal math, then you have two choices:
Work in fixed point rather than floating point. Multiply everything by 100 and store it as an Int. For many problems is this an ideal solution.
NSDecimalNumber. This is available in Cocoa and lets you do math in decimal rather than binary. 9.05 as an NSDecimalNumber is exactly 9.05. This is a good solution for more general problems, but is a little harder to implement.
That is a general problem of binary representations of a floating point digits where 9.05 cannot be represented exactly.
Try this in a playground:
9.05 // 9.050000000000001
so even directly initializing the value is not a "workaround"
try use this
var value: Double = (swiftString as NSString).doubleValue
see:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/#//apple_ref/occ/instp/NSString/doubleValue
As Eric D. Defined in comment please check the http://floating-point-gui.de/basic/
You can format your string to get desired output :
var strVal = "9.05"
var dbl : Double = (NSString(format: "%.2f", (strVal as NSString).doubleValue)).doubleValue
println(dbl)
It's working in Xcode Version 6.3.2

float unusual behaviour Objective c [duplicate]

This question already has answers here:
Trouble with floats in Objective-C
(3 answers)
Closed 7 years ago.
I am getting an unusal issue with float in Objective C. I enter 100.1 and i get 100.100002 shouldn't it be something like 100.100000 .
Following is the code
float temp=100.1;
NSLog(#"%f",temp);
100.100000
Can someone guide me what am i doing wrong or how to fix it ? I cannot use fixed decimal places i-e i cannot just use 100.10 . I need all decimal places .
Because that is a fundamental part of what happens when you represent an arbitrary floating point value in binary. The number of binary digits is limited, therefore rounding occurs. Depending on your needs, you might be better off using NSDecimalNumber.
Try using double instead;
double temp=100.1;
NSLog(#"%.8f",temp);
100.10000000
It is an issue with representation accuracy. I do not think it will be a problem to use double instead.

Resources