diff --git a/Foundation/Decimal.swift b/Foundation/Decimal.swift index 20d0b5bb73..19152867f0 100644 --- a/Foundation/Decimal.swift +++ b/Foundation/Decimal.swift @@ -986,7 +986,7 @@ fileprivate func integerMultiply(_ big: inout T, accumulator = UInt32(carry) + bigij + UInt32(right[j]) * UInt32(left[i]) carry = UInt16(truncatingIfNeeded:accumulator >> 16) big[i+j] = UInt16(truncatingIfNeeded:accumulator) - } else if carry != 0 || (right[j] == 0 && left[j] == 0) { + } else if carry != 0 || (right[j] > 0 && left[i] > 0) { return .overflow } } diff --git a/TestFoundation/TestDecimal.swift b/TestFoundation/TestDecimal.swift index c1b0fe7d7f..6078faaa80 100644 --- a/TestFoundation/TestDecimal.swift +++ b/TestFoundation/TestDecimal.swift @@ -342,7 +342,7 @@ class TestDecimal: XCTestCase { XCTAssertEqual(otherBits + Decimal(1), highBit) } - func test_Misc() { + func test_Misc() throws { XCTAssertEqual(.minus, Decimal(-5.2).sign) XCTAssertEqual(.plus, Decimal(5.2).sign) var d = Decimal(5.2) @@ -426,6 +426,23 @@ class TestDecimal: XCTestCase { XCTAssertEqual(expected, pow(power, j)) } } + + do { + // SR-13015 + let a = try XCTUnwrap(Decimal(string: "119.993")) + let b = try XCTUnwrap(Decimal(string: "4.1565")) + let c = try XCTUnwrap(Decimal(string: "18.209")) + let d = try XCTUnwrap(Decimal(string: "258.469")) + let ab = a * b + let aDivD = a / d + let caDivD = c * aDivD + XCTAssertEqual(ab, try XCTUnwrap(Decimal(string: "498.7509045"))) + XCTAssertEqual(aDivD, try XCTUnwrap(Decimal(string: "0.46424522863476857959755328492004843907"))) + XCTAssertEqual(caDivD, try XCTUnwrap(Decimal(string: "8.453441368210501065891847765109162027"))) + + let result = (a * b) + (c * (a / d)) + XCTAssertEqual(result, try XCTUnwrap(Decimal(string: "507.2043458682105010658918477651091"))) + } } func test_MultiplicationOverflow() { @@ -522,7 +539,7 @@ class TestDecimal: XCTestCase { XCTAssertEqual(0, result._isNegative, "0 * -1") } - func test_Normalise() { + func test_Normalise() throws { var one = Decimal(1) var ten = Decimal(-10) XCTAssertEqual(.noError, NSDecimalNormalize(&one, &ten, .plain)) @@ -558,6 +575,36 @@ class TestDecimal: XCTestCase { XCTAssertEqual(.lossOfPrecision, NSDecimalNormalize(&large, &small, .plain)) XCTAssertEqual(small.exponent, 127) XCTAssertEqual(large.exponent, 127) + + // Normalise with loss of precision + let a = try XCTUnwrap(Decimal(string: "498.7509045")) + let b = try XCTUnwrap(Decimal(string: "8.453441368210501065891847765109162027")) + + var aNormalized = a + var bNormalized = b + let normalizeError = NSDecimalNormalize(&aNormalized, &bNormalized, .plain) + XCTAssertEqual(normalizeError, NSDecimalNumber.CalculationError.lossOfPrecision) + + XCTAssertEqual(aNormalized.exponent, -31) + XCTAssertEqual(aNormalized._mantissa.0, 0) + XCTAssertEqual(aNormalized._mantissa.1, 21760) + XCTAssertEqual(aNormalized._mantissa.2, 45355) + XCTAssertEqual(aNormalized._mantissa.3, 11455) + XCTAssertEqual(aNormalized._mantissa.4, 62709) + XCTAssertEqual(aNormalized._mantissa.5, 14050) + XCTAssertEqual(aNormalized._mantissa.6, 62951) + XCTAssertEqual(aNormalized._mantissa.7, 0) + XCTAssertEqual(bNormalized.exponent, -31) + XCTAssertEqual(bNormalized._mantissa.0, 56467) + XCTAssertEqual(bNormalized._mantissa.1, 17616) + XCTAssertEqual(bNormalized._mantissa.2, 59987) + XCTAssertEqual(bNormalized._mantissa.3, 21635) + XCTAssertEqual(bNormalized._mantissa.4, 5988) + XCTAssertEqual(bNormalized._mantissa.5, 63852) + XCTAssertEqual(bNormalized._mantissa.6, 1066) + XCTAssertEqual(bNormalized._mantissa.7, 1628) + XCTAssertEqual(a, aNormalized) + XCTAssertNotEqual(b, bNormalized) // b had a loss Of Precision when normalising } func test_NSDecimal() throws {