Yurkevich
Yurkevich

Reputation: 4517

Decimal with extremely long number

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

Answers (3)

Yurkevich
Yurkevich

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

Sulthan
Sulthan

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

Stephen O'Connor
Stephen O'Connor

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

Related Questions