Skip to content

Instantly share code, notes, and snippets.

@denkeni
Last active December 31, 2017 08:59
Show Gist options
  • Save denkeni/f07e5dcdba40746e3bb017d11c0fd012 to your computer and use it in GitHub Desktop.
Save denkeni/f07e5dcdba40746e3bb017d11c0fd012 to your computer and use it in GitHub Desktop.
Double to String Precision Issue (Swift & Obj-C)
let value : Double = 1234567890.1234567
// 1. String format
"\(value)" == "1234567890.1234567" // false
"\(value)" // "1234567890.12346"
value.description
String(format: "%f", value) == "1234567890.1234567" // false
String(format: "%f", value) // "1234567890.123457"
String(format: "%.7f", value) == "1234567890.1234567" // true!
String(format: "%.7f", value) // "1234567890.1234567"
String(format: "%.8f", value) == "1234567890.1234567" // false
String(format: "%.8f", value) // "1234567890.12345672" wtf
String(format: "%.9f", value) == "1234567890.1234567" // false
String(format: "%.9f", value) // "1234567890.123456717" wtf
// 2. NSNumber & NumberFormatter
let number = NSNumber(value: value)
number.doubleValue == value // true
number.stringValue == "1234567890.1234567" // false
number.stringValue // "1234567890.123457"
let nf = NumberFormatter()
nf.numberStyle = .decimal
nf.usesGroupingSeparator = false
// 2.1 Significant Digits = 17
nf.usesSignificantDigits = true
nf.maximumSignificantDigits = 14
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.1235"
nf.maximumSignificantDigits = 15
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346"
nf.maximumSignificantDigits = 16
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346" wtf
nf.maximumSignificantDigits = 17
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346" wtf
// 2.2 minimum and maximum number of (integer, fraction) digits = (10, 7)
nf.usesSignificantDigits = false
nf.maximumIntegerDigits = 10
nf.maximumFractionDigits = 4
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.1235"
nf.maximumFractionDigits = 5
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346"
nf.maximumFractionDigits = 6
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346" wtf
nf.maximumFractionDigits = 7
nf.string(from: number) == "1234567890.1234567" // false
nf.string(from: number) // "1234567890.12346" wtf
// 3. NSDecimalNumber & Decimal
let num = NSDecimalNumber(value: value)
num.doubleValue == value // false!
num.stringValue == "1234567890.1234567" // false
num.stringValue // "1234567890.1234569216" wtf
num.description == "1234567890.1234567" // false
var decimal = Decimal(value) // 1234567890.1234569216
let decimalString = NSDecimalString(&decimal, nil) // "1234567890.1234569216"
decimalString == "1234567890.1234567" // false
// 4. Break into fractional and integral parts
let sep = modf(value)
sep.0 // integral:1234567890
sep.1 // fractional:0.1234567165374756
sep.1 == value - sep.0 // true
sep.1 == 0.1234567 // false!
// 5. JSONEncoder (weird workaround)
let array = [1234567890.1234567] // [1234567891.123457] wtf
array[0] == 1234567890.1234567 // true
let jsonEncoder = JSONEncoder()
if let data = try? jsonEncoder.encode(array) {
if var str = String(data: data, encoding: .utf8) {
// "[1234567891.1234567]"
str.removeFirst()
str.removeLast()
str == "1234567890.1234567" // true!
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment