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