12
12
13
13
@_exported import Foundation // Clang module
14
14
@_implementationOnly import _CoreFoundationOverlayShims
15
+ import AppKit
15
16
16
17
extension Decimal {
17
18
public typealias RoundingMode = NSDecimalNumber . RoundingMode
@@ -26,6 +27,7 @@ public func pow(_ x: Decimal, _ y: Int) -> Decimal {
26
27
}
27
28
28
29
extension Decimal : Hashable , Comparable {
30
+ // (Used by `doubleValue`.)
29
31
private subscript( index: UInt32 ) -> UInt16 {
30
32
get {
31
33
switch index {
@@ -42,6 +44,7 @@ extension Decimal : Hashable, Comparable {
42
44
}
43
45
}
44
46
47
+ // (Used by `NSDecimalNumber` and `hash(into:)`.)
45
48
internal var doubleValue : Double {
46
49
if _length == 0 {
47
50
return _isNegative == 1 ? Double . nan : 0
@@ -124,7 +127,7 @@ extension Decimal : Codable {
124
127
125
128
var mantissaContainer = try container. nestedUnkeyedContainer ( forKey: . mantissa)
126
129
var mantissa : ( CUnsignedShort , CUnsignedShort , CUnsignedShort , CUnsignedShort ,
127
- CUnsignedShort , CUnsignedShort , CUnsignedShort , CUnsignedShort ) = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )
130
+ CUnsignedShort , CUnsignedShort , CUnsignedShort , CUnsignedShort ) = ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 )
128
131
mantissa. 0 = try mantissaContainer. decode ( CUnsignedShort . self)
129
132
mantissa. 1 = try mantissaContainer. decode ( CUnsignedShort . self)
130
133
mantissa. 2 = try mantissaContainer. decode ( CUnsignedShort . self)
@@ -134,12 +137,12 @@ extension Decimal : Codable {
134
137
mantissa. 6 = try mantissaContainer. decode ( CUnsignedShort . self)
135
138
mantissa. 7 = try mantissaContainer. decode ( CUnsignedShort . self)
136
139
137
- self = Decimal ( _exponent: exponent,
138
- _length: length,
139
- _isNegative: CUnsignedInt ( isNegative ? 1 : 0 ) ,
140
- _isCompact: CUnsignedInt ( isCompact ? 1 : 0 ) ,
141
- _reserved: 0 ,
142
- _mantissa: mantissa)
140
+ self . init ( _exponent: exponent,
141
+ _length: length,
142
+ _isNegative: CUnsignedInt ( isNegative ? 1 : 0 ) ,
143
+ _isCompact: CUnsignedInt ( isCompact ? 1 : 0 ) ,
144
+ _reserved: 0 ,
145
+ _mantissa: mantissa)
143
146
}
144
147
145
148
public func encode( to encoder: Encoder ) throws {
@@ -182,9 +185,50 @@ extension Decimal : SignedNumeric {
182
185
_reserved: 0 , _mantissa: self . _mantissa)
183
186
}
184
187
185
- // FIXME(integers): implement properly
186
188
public init ? < T : BinaryInteger > ( exactly source: T ) {
187
- fatalError ( )
189
+ let zero = 0 as T
190
+
191
+ if source == zero {
192
+ self = Decimal . zero
193
+ return
194
+ }
195
+
196
+ let negative : UInt32 = ( T . isSigned && source < zero) ? 1 : 0
197
+ var mantissa = source. magnitude
198
+ var exponent : Int32 = 0
199
+
200
+ let maxExponent = Int8 . max
201
+ while mantissa. isMultiple ( of: 10 ) && ( exponent < maxExponent) {
202
+ exponent += 1
203
+ mantissa /= 10
204
+ }
205
+
206
+ // If the mantissa still requires more than 128 bits of storage then it is too large.
207
+ if mantissa. bitWidth > 128 && ( mantissa >> 128 != zero) { return nil }
208
+
209
+ let mantissaParts : ( UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 )
210
+ let loWord = UInt64 ( truncatingIfNeeded: mantissa)
211
+ var length = ( ( loWord. bitWidth - loWord. leadingZeroBitCount) + ( UInt16 . bitWidth - 1 ) ) / UInt16. bitWidth
212
+ mantissaParts. 0 = UInt16 ( truncatingIfNeeded: loWord >> 0 )
213
+ mantissaParts. 1 = UInt16 ( truncatingIfNeeded: loWord >> 16 )
214
+ mantissaParts. 2 = UInt16 ( truncatingIfNeeded: loWord >> 32 )
215
+ mantissaParts. 3 = UInt16 ( truncatingIfNeeded: loWord >> 48 )
216
+
217
+ let hiWord = mantissa. bitWidth > 64 ? UInt64 ( truncatingIfNeeded: mantissa >> 64 ) : 0
218
+ if hiWord != 0 {
219
+ length = 4 + ( ( hiWord. bitWidth - hiWord. leadingZeroBitCount) + ( UInt16 . bitWidth - 1 ) ) / UInt16. bitWidth
220
+ mantissaParts. 4 = UInt16 ( truncatingIfNeeded: hiWord >> 0 )
221
+ mantissaParts. 5 = UInt16 ( truncatingIfNeeded: hiWord >> 16 )
222
+ mantissaParts. 6 = UInt16 ( truncatingIfNeeded: hiWord >> 32 )
223
+ mantissaParts. 7 = UInt16 ( truncatingIfNeeded: hiWord >> 48 )
224
+ } else {
225
+ mantissaParts. 4 = 0
226
+ mantissaParts. 5 = 0
227
+ mantissaParts. 6 = 0
228
+ mantissaParts. 7 = 0
229
+ }
230
+
231
+ self = Decimal ( _exponent: exponent, _length: UInt32 ( length) , _isNegative: negative, _isCompact: 1 , _reserved: 0 , _mantissa: mantissaParts)
188
232
}
189
233
190
234
public static func += ( lhs: inout Decimal , rhs: Decimal ) {
@@ -332,11 +376,11 @@ extension Decimal {
332
376
_mantissa: ( 0x6623 , 0x7d57 , 0x16e7 , 0xad0d , 0xaf52 , 0x4641 , 0xdfa7 , 0xec58 )
333
377
)
334
378
335
- @available ( * , unavailable, message: " Decimal does not yet fully adopt FloatingPoint. " )
336
- public static var infinity : Decimal { fatalError ( " Decimal does not yet fully adopt FloatingPoint " ) }
379
+ @available ( * , unavailable, message: " Decimal does not fully adopt FloatingPoint. " )
380
+ public static var infinity : Decimal { fatalError ( " Decimal does not fully adopt FloatingPoint " ) }
337
381
338
- @available ( * , unavailable, message: " Decimal does not yet fully adopt FloatingPoint. " )
339
- public static var signalingNaN : Decimal { fatalError ( " Decimal does not yet fully adopt FloatingPoint " ) }
382
+ @available ( * , unavailable, message: " Decimal does not fully adopt FloatingPoint. " )
383
+ public static var signalingNaN : Decimal { fatalError ( " Decimal does not fully adopt FloatingPoint " ) }
340
384
341
385
public static var quietNaN : Decimal {
342
386
return Decimal (
@@ -411,7 +455,7 @@ extension Decimal {
411
455
}
412
456
413
457
public init ( _ value: Double ) {
414
- precondition ( !value. isInfinite, " Decimal does not yet fully adopt FloatingPoint " )
458
+ precondition ( !value. isInfinite, " Decimal does not fully adopt FloatingPoint " )
415
459
if value. isNaN {
416
460
self = Decimal . nan
417
461
} else if value == 0.0 {
@@ -420,16 +464,36 @@ extension Decimal {
420
464
self = Decimal ( )
421
465
let negative = value < 0
422
466
var val = negative ? - 1 * value : value
423
- var exponent = 0
467
+ var exponent : Int8 = 0
468
+
469
+ // Try to get val as close to UInt64.max whilst adjusting the exponent
470
+ // to reduce the number of digits after the decimal point.
424
471
while val < Double ( UInt64 . max - 1 ) {
472
+ guard exponent > Int8 . min else {
473
+ self = Decimal . nan
474
+ return
475
+ }
425
476
val *= 10.0
426
477
exponent -= 1
427
478
}
428
- while Double ( UInt64 . max - 1 ) < val {
479
+ while Double ( UInt64 . max) <= val {
480
+ guard exponent < Int8 . max else {
481
+ self = Decimal . nan
482
+ return
483
+ }
429
484
val /= 10.0
430
485
exponent += 1
431
486
}
432
- var mantissa = UInt64 ( val)
487
+
488
+ var mantissa : UInt64
489
+ let maxMantissa = Double ( UInt64 . max) . nextDown
490
+ if val > maxMantissa {
491
+ // UInt64(Double(UInt64.max)) gives an overflow error; this is the largest
492
+ // mantissa that can be set.
493
+ mantissa = UInt64 ( maxMantissa)
494
+ } else {
495
+ mantissa = UInt64 ( val)
496
+ }
433
497
434
498
var i : UInt32 = 0
435
499
// This is a bit ugly but it is the closest approximation of the C
@@ -601,8 +665,8 @@ extension Decimal {
601
665
return true
602
666
}
603
667
604
- @available ( * , unavailable, message: " Decimal does not yet fully adopt FloatingPoint. " )
605
- public mutating func formTruncatingRemainder( dividingBy other: Decimal ) { fatalError ( " Decimal does not yet fully adopt FloatingPoint " ) }
668
+ @available ( * , unavailable, message: " Decimal does not fully adopt FloatingPoint. " )
669
+ public mutating func formTruncatingRemainder( dividingBy other: Decimal ) { fatalError ( " Decimal does not fully adopt FloatingPoint " ) }
606
670
}
607
671
608
672
extension Decimal : _ObjectiveCBridgeable {
0 commit comments