Skip to content

Commit d8cc90f

Browse files
authored
Merge pull request #3068 from xwu/decimal-significand
[SR-15132][SR-15134] Fix `Decimal` implementation of significand APIs
2 parents 944987e + 9fe6948 commit d8cc90f

File tree

4 files changed

+62
-16
lines changed

4 files changed

+62
-16
lines changed

Darwin/Foundation-swiftoverlay-Tests/TestDecimal.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,27 @@ class TestDecimal : XCTestCase {
565565
XCTAssertEqual(answer,num,"\(ones) / 9 = \(answer) \(num)")
566566
}
567567

568+
func test_Significand() {
569+
var x = -42 as Decimal
570+
XCTAssertEqual(x.significand.sign, .plus)
571+
var y = Decimal(sign: .plus, exponent: 0, significand: x)
572+
XCTAssertEqual(y, -42)
573+
y = Decimal(sign: .minus, exponent: 0, significand: x)
574+
XCTAssertEqual(y, 42)
575+
576+
x = 42 as Decimal
577+
XCTAssertEqual(x.significand.sign, .plus)
578+
y = Decimal(sign: .plus, exponent: 0, significand: x)
579+
XCTAssertEqual(y, 42)
580+
y = Decimal(sign: .minus, exponent: 0, significand: x)
581+
XCTAssertEqual(y, -42)
582+
583+
let a = Decimal.leastNonzeroMagnitude
584+
XCTAssertEqual(Decimal(sign: .plus, exponent: -10, significand: a), 0)
585+
let b = Decimal.greatestFiniteMagnitude
586+
XCTAssertTrue(Decimal(sign: .plus, exponent: 10, significand: b).isNaN)
587+
}
588+
568589
func test_SimpleMultiplication() {
569590
var multiplicand = Decimal()
570591
multiplicand._isNegative = 0

Darwin/Foundation-swiftoverlay/Decimal.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -516,13 +516,13 @@ extension Decimal {
516516
}
517517

518518
public init(sign: FloatingPointSign, exponent: Int, significand: Decimal) {
519-
self.init(
520-
_exponent: Int32(exponent) + significand._exponent,
521-
_length: significand._length,
522-
_isNegative: sign == .plus ? 0 : 1,
523-
_isCompact: significand._isCompact,
524-
_reserved: 0,
525-
_mantissa: significand._mantissa)
519+
self = significand
520+
let error = withUnsafeMutablePointer(to: &self) {
521+
NSDecimalMultiplyByPowerOf10($0, $0, Int16(exponent), .plain)
522+
}
523+
if error == .underflow { self = 0 }
524+
// We don't need to check for overflow because `Decimal` cannot represent infinity.
525+
if sign == .minus { negate() }
526526
}
527527

528528
public init(signOf: Decimal, magnitudeOf magnitude: Decimal) {
@@ -541,7 +541,7 @@ extension Decimal {
541541

542542
public var significand: Decimal {
543543
return Decimal(
544-
_exponent: 0, _length: _length, _isNegative: _isNegative, _isCompact: _isCompact,
544+
_exponent: 0, _length: _length, _isNegative: 0, _isCompact: _isCompact,
545545
_reserved: 0, _mantissa: _mantissa)
546546
}
547547

Sources/Foundation/Decimal.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -684,13 +684,13 @@ extension Decimal {
684684
}
685685

686686
public init(sign: FloatingPointSign, exponent: Int, significand: Decimal) {
687-
self.init(
688-
_exponent: Int32(exponent) + significand._exponent,
689-
_length: significand._length,
690-
_isNegative: sign == .plus ? 0 : 1,
691-
_isCompact: significand._isCompact,
692-
_reserved: 0,
693-
_mantissa: significand._mantissa)
687+
self = significand
688+
let error = withUnsafeMutablePointer(to: &self) {
689+
NSDecimalMultiplyByPowerOf10($0, $0, Int16(exponent), .plain)
690+
}
691+
if error == .underflow { self = 0 }
692+
// We don't need to check for overflow because `Decimal` cannot represent infinity.
693+
if sign == .minus { negate() }
694694
}
695695

696696
public init(signOf: Decimal, magnitudeOf magnitude: Decimal) {
@@ -709,7 +709,7 @@ extension Decimal {
709709

710710
public var significand: Decimal {
711711
return Decimal(
712-
_exponent: 0, _length: _length, _isNegative: _isNegative, _isCompact: _isCompact,
712+
_exponent: 0, _length: _length, _isNegative: 0, _isCompact: _isCompact,
713713
_reserved: 0, _mantissa: _mantissa)
714714
}
715715

Tests/Foundation/Tests/TestDecimal.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
88
//
99

10+
import Foundation
11+
import XCTest
12+
1013
class TestDecimal: XCTestCase {
1114

1215
func test_NSDecimalNumberInit() {
@@ -804,6 +807,27 @@ class TestDecimal: XCTestCase {
804807
XCTAssertEqual(zero3.description, "0")
805808
}
806809

810+
func test_Significand() {
811+
var x = -42 as Decimal
812+
XCTAssertEqual(x.significand.sign, .plus)
813+
var y = Decimal(sign: .plus, exponent: 0, significand: x)
814+
XCTAssertEqual(y, -42)
815+
y = Decimal(sign: .minus, exponent: 0, significand: x)
816+
XCTAssertEqual(y, 42)
817+
818+
x = 42 as Decimal
819+
XCTAssertEqual(x.significand.sign, .plus)
820+
y = Decimal(sign: .plus, exponent: 0, significand: x)
821+
XCTAssertEqual(y, 42)
822+
y = Decimal(sign: .minus, exponent: 0, significand: x)
823+
XCTAssertEqual(y, -42)
824+
825+
let a = Decimal.leastNonzeroMagnitude
826+
XCTAssertEqual(Decimal(sign: .plus, exponent: -10, significand: a), 0)
827+
let b = Decimal.greatestFiniteMagnitude
828+
XCTAssertTrue(Decimal(sign: .plus, exponent: 10, significand: b).isNaN)
829+
}
830+
807831
func test_SimpleMultiplication() {
808832
var multiplicand = Decimal()
809833
multiplicand._isNegative = 0
@@ -1467,6 +1491,7 @@ class TestDecimal: XCTestCase {
14671491
("test_RepeatingDivision", test_RepeatingDivision),
14681492
("test_Round", test_Round),
14691493
("test_ScanDecimal", test_ScanDecimal),
1494+
("test_Significand", test_Significand),
14701495
("test_SimpleMultiplication", test_SimpleMultiplication),
14711496
("test_SmallerNumbers", test_SmallerNumbers),
14721497
("test_Strideable", test_Strideable),

0 commit comments

Comments
 (0)