Skip to content

Commit 6a1be26

Browse files
authored
Merge pull request #2827 from buttaface/decimal
SR-13015: Decimal calculation incorrect on Linux
2 parents 5b68bf4 + 81fddf2 commit 6a1be26

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

Sources/Foundation/Decimal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ fileprivate func integerMultiply<T:VariableLengthNumber>(_ big: inout T,
10251025
accumulator = UInt32(carry) + bigij + UInt32(right[j]) * UInt32(left[i])
10261026
carry = UInt16(truncatingIfNeeded:accumulator >> 16)
10271027
big[i+j] = UInt16(truncatingIfNeeded:accumulator)
1028-
} else if carry != 0 || (right[j] == 0 && left[j] == 0) {
1028+
} else if carry != 0 || (right[j] > 0 && left[i] > 0) {
10291029
return .overflow
10301030
}
10311031
}

Tests/Foundation/Tests/TestDecimal.swift

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ class TestDecimal: XCTestCase {
342342
XCTAssertEqual(otherBits + Decimal(1), highBit)
343343
}
344344

345-
func test_Misc() {
345+
func test_Misc() throws {
346346
XCTAssertEqual(.minus, Decimal(-5.2).sign)
347347
XCTAssertEqual(.plus, Decimal(5.2).sign)
348348
var d = Decimal(5.2)
@@ -426,6 +426,23 @@ class TestDecimal: XCTestCase {
426426
XCTAssertEqual(expected, pow(power, j))
427427
}
428428
}
429+
430+
do {
431+
// SR-13015
432+
let a = try XCTUnwrap(Decimal(string: "119.993"))
433+
let b = try XCTUnwrap(Decimal(string: "4.1565"))
434+
let c = try XCTUnwrap(Decimal(string: "18.209"))
435+
let d = try XCTUnwrap(Decimal(string: "258.469"))
436+
let ab = a * b
437+
let aDivD = a / d
438+
let caDivD = c * aDivD
439+
XCTAssertEqual(ab, try XCTUnwrap(Decimal(string: "498.7509045")))
440+
XCTAssertEqual(aDivD, try XCTUnwrap(Decimal(string: "0.46424522863476857959755328492004843907")))
441+
XCTAssertEqual(caDivD, try XCTUnwrap(Decimal(string: "8.453441368210501065891847765109162027")))
442+
443+
let result = (a * b) + (c * (a / d))
444+
XCTAssertEqual(result, try XCTUnwrap(Decimal(string: "507.2043458682105010658918477651091")))
445+
}
429446
}
430447

431448
func test_MultiplicationOverflow() {
@@ -522,7 +539,7 @@ class TestDecimal: XCTestCase {
522539
XCTAssertEqual(0, result._isNegative, "0 * -1")
523540
}
524541

525-
func test_Normalise() {
542+
func test_Normalise() throws {
526543
var one = Decimal(1)
527544
var ten = Decimal(-10)
528545
XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain))
@@ -558,6 +575,36 @@ class TestDecimal: XCTestCase {
558575
XCTAssertEqual(.lossOfPrecision, NSDecimalNormalize(&large, &small, .plain))
559576
XCTAssertEqual(small.exponent, 127)
560577
XCTAssertEqual(large.exponent, 127)
578+
579+
// Normalise with loss of precision
580+
let a = try XCTUnwrap(Decimal(string: "498.7509045"))
581+
let b = try XCTUnwrap(Decimal(string: "8.453441368210501065891847765109162027"))
582+
583+
var aNormalized = a
584+
var bNormalized = b
585+
let normalizeError = NSDecimalNormalize(&aNormalized, &bNormalized, .plain)
586+
XCTAssertEqual(normalizeError, NSDecimalNumber.CalculationError.lossOfPrecision)
587+
588+
XCTAssertEqual(aNormalized.exponent, -31)
589+
XCTAssertEqual(aNormalized._mantissa.0, 0)
590+
XCTAssertEqual(aNormalized._mantissa.1, 21760)
591+
XCTAssertEqual(aNormalized._mantissa.2, 45355)
592+
XCTAssertEqual(aNormalized._mantissa.3, 11455)
593+
XCTAssertEqual(aNormalized._mantissa.4, 62709)
594+
XCTAssertEqual(aNormalized._mantissa.5, 14050)
595+
XCTAssertEqual(aNormalized._mantissa.6, 62951)
596+
XCTAssertEqual(aNormalized._mantissa.7, 0)
597+
XCTAssertEqual(bNormalized.exponent, -31)
598+
XCTAssertEqual(bNormalized._mantissa.0, 56467)
599+
XCTAssertEqual(bNormalized._mantissa.1, 17616)
600+
XCTAssertEqual(bNormalized._mantissa.2, 59987)
601+
XCTAssertEqual(bNormalized._mantissa.3, 21635)
602+
XCTAssertEqual(bNormalized._mantissa.4, 5988)
603+
XCTAssertEqual(bNormalized._mantissa.5, 63852)
604+
XCTAssertEqual(bNormalized._mantissa.6, 1066)
605+
XCTAssertEqual(bNormalized._mantissa.7, 1628)
606+
XCTAssertEqual(a, aNormalized)
607+
XCTAssertNotEqual(b, bNormalized) // b had a loss Of Precision when normalising
561608
}
562609

563610
func test_NSDecimal() throws {

0 commit comments

Comments
 (0)