From 713937f44c2965129fff22f9b7d511a843bbf6db Mon Sep 17 00:00:00 2001 From: Oschly Date: Sat, 22 Jul 2023 11:07:40 +0200 Subject: [PATCH] Fix `NSDecimalPower(_:_:_:_:)` behavior --- Sources/Foundation/Decimal.swift | 22 +++++++++++++++++----- Tests/Foundation/Tests/TestDecimal.swift | 5 +++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Sources/Foundation/Decimal.swift b/Sources/Foundation/Decimal.swift index 37ca9ff5414..7ba809a0d28 100644 --- a/Sources/Foundation/Decimal.swift +++ b/Sources/Foundation/Decimal.swift @@ -1801,7 +1801,7 @@ public func NSDecimalPower(_ result: UnsafeMutablePointer, _ number: Un return .overflow } NSDecimalCopy(result,number) - return result.pointee.power(UInt(power), roundingMode:roundingMode) + return result.pointee.power(power, roundingMode:roundingMode) } public func NSDecimalMultiplyByPowerOf10(_ result: UnsafeMutablePointer, _ number: UnsafePointer, _ power: Int16, _ roundingMode: NSDecimalNumber.RoundingMode) -> NSDecimalNumber.CalculationError { @@ -2242,11 +2242,11 @@ extension Decimal { _exponent = newExponent return .noError } - fileprivate mutating func power(_ p:UInt, roundingMode:RoundingMode) -> CalculationError { + fileprivate mutating func power(_ p:Int, roundingMode:RoundingMode) -> CalculationError { if isNaN { return .overflow } - var power = p + var power = abs(p) if power == 0 { _exponent = 0 _length = 1 @@ -2254,7 +2254,7 @@ extension Decimal { self[0] = 1 _isCompact = 1 return .noError - } else if power == 1 { + } else if power == 1 || isZero { return .noError } @@ -2297,7 +2297,19 @@ extension Decimal { let previousError = error var rightOp = self error = NSDecimalMultiply(&self, &temporary, &rightOp, roundingMode) - + + // if power is negative, use multiplicative inverse + if p < 0 { + rightOp = self + + error = NSDecimalDivide( + &self, + &temporary, + &rightOp, + roundingMode + ) + } + if previousError != .noError { // FIXME is this the intent? error = previousError } diff --git a/Tests/Foundation/Tests/TestDecimal.swift b/Tests/Foundation/Tests/TestDecimal.swift index eaf48a2f645..fd0cfd04346 100644 --- a/Tests/Foundation/Tests/TestDecimal.swift +++ b/Tests/Foundation/Tests/TestDecimal.swift @@ -398,9 +398,14 @@ class TestDecimal: XCTestCase { a = Decimal(8) XCTAssertEqual(.noError, NSDecimalPower(&result, &a, 2, .plain)) XCTAssertEqual(Decimal(64), result) + a = Decimal(8) + XCTAssertEqual(.noError, NSDecimalPower(&result, &a, -2, .plain)) + XCTAssertEqual(Decimal(1/64), result) a = Decimal(-2) XCTAssertEqual(.noError, NSDecimalPower(&result, &a, 3, .plain)) XCTAssertEqual(Decimal(-8), result) + XCTAssertEqual(.noError, NSDecimalPower(&result, &a, -3, .plain)) + XCTAssertEqual(Decimal(-1/8), result) for i in -2...10 { for j in 0...5 { var actual = Decimal(i)