Reputation: 4517
I was expecting Decimal
to treat number like a String
but instead I reproduced small rounding during testing.
let locale = Locale(identifier: "en_GB")
let price: String? = "1535132527181273627"
let decimal: Decimal? = price != nil ? Decimal(string: price!, locale: locale) : nil
XCTAssertEqual(decimal, 1535132527181273627.0)
The result bothers me:
XCTAssertEqual failed: ("Optional(1535132527181274000)") is not equal to ("Optional(1535132527181273497.6)") -
Upvotes: 0
Views: 295
Reputation: 4517
So it looks like the problem is in the test, not the code. Swift uses Double to store number from the test and it's not long enough, Decimal wasn't rounded but the number to compare in the test was.
Solution is to compare Decimal
.
XCTAssertEqual(price, Decimal(string:"1535132527181273627"))
Upvotes: 0
Reputation: 130102
This is a design problem of the Swift compiler. It has been reported as SR-3317 but that was closed as duplicate of SR-920.
The problem is that the literal 1535132527181273627.0
is parsed as a Double
literal (that is, with limited precision) even if the type should be Decimal
. Using a String
to initialize Decimal
is the only workaround for now.
The solution is to redesign the built-in protocol ExpressibleByFloatLiteral to allow for longer numbers.
Upvotes: 1
Reputation: 1475
I tried your code and the result was:
XCTAssertEqual failed: ("Optional(1535132527181273627)") is not equal to ("Optional(1535132527181273497.6)")
using Xcode 9.4.1 on a MacBook Pro 2015
I think the problem is in the fact that Double
is only able to deal with 15 decimal places. So the number 1535132527181273627.0
cannot be represented accurately. Take a look at Double precision - decimal places
Upvotes: 1