@@ -170,16 +170,35 @@ extension Decimal /* : FloatingPoint */ {
170
170
self = Decimal ( )
171
171
let negative = value < 0
172
172
var val = negative ? - 1 * value : value
173
- var exponent = 0
173
+ var exponent : Int8 = 0
174
+
175
+ // Try to get val as close to UInt64.max whilst adjusting the exponent
176
+ // to reduce the number of digits after the decimal point.
174
177
while val < Double ( UInt64 . max - 1 ) {
178
+ guard exponent > Int8 . min else {
179
+ self = . nan
180
+ return
181
+ }
175
182
val *= 10.0
176
183
exponent -= 1
177
184
}
178
- while Double ( UInt64 . max - 1 ) < val {
185
+ while Double ( UInt64 . max) <= val {
186
+ guard exponent < Int8 . max else {
187
+ self = . nan
188
+ return
189
+ }
179
190
val /= 10.0
180
191
exponent += 1
181
192
}
182
- var mantissa = UInt64 ( val)
193
+ var mantissa : UInt64
194
+ let maxMantissa = Double ( UInt64 . max) . nextDown
195
+ if val > maxMantissa {
196
+ // UInt64(Double(UInt64.max)) gives an overflow error,
197
+ // this is the largest mantissa that can be set.
198
+ mantissa = UInt64 ( maxMantissa)
199
+ } else {
200
+ mantissa = UInt64 ( val)
201
+ }
183
202
184
203
var i : UInt32 = 0
185
204
// This is a bit ugly but it is the closest approximation of the C
@@ -217,13 +236,24 @@ extension Decimal /* : FloatingPoint */ {
217
236
}
218
237
219
238
public init ( sign: FloatingPointSign , exponent: Int , significand: Decimal ) {
220
- self . init (
221
- _exponent: Int32 ( exponent) + significand. _exponent,
222
- _length: significand. _length,
223
- _isNegative: sign == . plus ? 0 : 1 ,
224
- _isCompact: significand. _isCompact,
225
- _reserved: 0 ,
226
- _mantissa: significand. _mantissa)
239
+ self = significand
240
+ do {
241
+ self = try significand. _multiplyByPowerOfTen (
242
+ power: exponent, roundingMode: . plain)
243
+ } catch {
244
+ guard let actual = error as? Decimal . _CalculationError else {
245
+ self = . nan
246
+ return
247
+ }
248
+ if actual == . underflow {
249
+ self = 0
250
+ } else {
251
+ self = . nan
252
+ }
253
+ }
254
+ if sign == . minus {
255
+ negate ( )
256
+ }
227
257
}
228
258
229
259
public init ( signOf: Decimal , magnitudeOf magnitude: Decimal ) {
@@ -242,7 +272,7 @@ extension Decimal /* : FloatingPoint */ {
242
272
243
273
public var significand : Decimal {
244
274
return Decimal (
245
- _exponent: 0 , _length: _length, _isNegative: _isNegative , _isCompact: _isCompact,
275
+ _exponent: 0 , _length: _length, _isNegative: 0 , _isCompact: _isCompact,
246
276
_reserved: 0 , _mantissa: _mantissa)
247
277
}
248
278
@@ -251,9 +281,20 @@ extension Decimal /* : FloatingPoint */ {
251
281
}
252
282
253
283
public var ulp : Decimal {
254
- if !self . isFinite { return Decimal . nan }
284
+ guard isFinite else { return . nan }
285
+
286
+ let exponent : Int32
287
+ if isZero {
288
+ exponent = . min
289
+ } else {
290
+ let shift = _powersOfTenDividingUInt128Max. firstIndex {
291
+ return significand > $0
292
+ } ?? _powersOfTenDividingUInt128Max. count
293
+ exponent = _exponent &- Int32 ( shift)
294
+ }
295
+
255
296
return Decimal (
256
- _exponent: _exponent , _length: 8 , _isNegative: 0 , _isCompact: 1 ,
297
+ _exponent: max ( exponent , - 128 ) , _length: 1 , _isNegative: 0 , _isCompact: 1 ,
257
298
_reserved: 0 , _mantissa: ( 0x0001 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 ) )
258
299
}
259
300
@@ -309,25 +350,38 @@ extension Decimal /* : FloatingPoint */ {
309
350
public mutating func formTruncatingRemainder( dividingBy other: Decimal ) { fatalError ( " Decimal does not yet fully adopt FloatingPoint " ) }
310
351
311
352
public var nextUp : Decimal {
312
- return self + Decimal(
313
- _exponent: _exponent,
314
- _length: 1 ,
315
- _isNegative: 0 ,
316
- _isCompact: 1 ,
317
- _reserved: 0 ,
318
- _mantissa: ( 0x0001 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 )
319
- )
353
+ if _isNegative == 1 {
354
+ if _exponent > - 128 &&
355
+ ( _mantissa. 0 , _mantissa. 1 , _mantissa. 2 , _mantissa. 3 ) == ( 0x999a , 0x9999 , 0x9999 , 0x9999 ) &&
356
+ ( _mantissa. 4 , _mantissa. 5 , _mantissa. 6 , _mantissa. 7 ) == ( 0x9999 , 0x9999 , 0x9999 , 0x1999 ) {
357
+ return Decimal (
358
+ _exponent: _exponent &- 1 ,
359
+ _length: 8 ,
360
+ _isNegative: 1 ,
361
+ _isCompact: 1 ,
362
+ _reserved: 0 ,
363
+ _mantissa: ( 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff , 0xffff )
364
+ )
365
+ }
366
+ } else {
367
+ if _exponent < 127 &&
368
+ ( _mantissa. 0 , _mantissa. 1 , _mantissa. 2 , _mantissa. 3 ) == ( 0xffff , 0xffff , 0xffff , 0xffff ) &&
369
+ ( _mantissa. 4 , _mantissa. 5 , _mantissa. 6 , _mantissa. 7 ) == ( 0xffff , 0xffff , 0xffff , 0xffff ) {
370
+ return Decimal (
371
+ _exponent: _exponent &+ 1 ,
372
+ _length: 8 ,
373
+ _isNegative: 0 ,
374
+ _isCompact: 1 ,
375
+ _reserved: 0 ,
376
+ _mantissa: ( 0x999a , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x1999 )
377
+ )
378
+ }
379
+ }
380
+ return self + ulp
320
381
}
321
382
322
383
public var nextDown : Decimal {
323
- return self - Decimal(
324
- _exponent: _exponent,
325
- _length: 1 ,
326
- _isNegative: 0 ,
327
- _isCompact: 1 ,
328
- _reserved: 0 ,
329
- _mantissa: ( 0x0001 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 )
330
- )
384
+ return - ( - self ) . nextUp
331
385
}
332
386
333
387
public func isEqual( to other: Decimal ) -> Bool {
@@ -604,30 +658,38 @@ extension Decimal : SignedNumeric {
604
658
#endif
605
659
606
660
public static func += ( lhs: inout Decimal , rhs: Decimal ) {
607
- let result = try ? lhs . _add ( rhs : rhs , roundingMode : . plain )
608
- if let result = result {
661
+ do {
662
+ let result = try lhs . _add ( rhs : rhs , roundingMode : . plain )
609
663
lhs = result. result
664
+ } catch {
665
+ lhs = . nan
610
666
}
611
667
}
612
668
613
669
public static func -= ( lhs: inout Decimal , rhs: Decimal ) {
614
- let result = try ? lhs . _subtract ( rhs : rhs , roundingMode : . plain )
615
- if let result = result {
670
+ do {
671
+ let result = try lhs . _subtract ( rhs : rhs , roundingMode : . plain )
616
672
lhs = result
673
+ } catch {
674
+ lhs = . nan
617
675
}
618
676
}
619
677
620
678
public static func *= ( lhs: inout Decimal , rhs: Decimal ) {
621
- let result = try ? lhs . _multiply ( by : rhs , roundingMode : . plain )
622
- if let result = result {
679
+ do {
680
+ let result = try lhs . _multiply ( by : rhs , roundingMode : . plain )
623
681
lhs = result
682
+ } catch {
683
+ lhs = . nan
624
684
}
625
685
}
626
686
627
687
public static func /= ( lhs: inout Decimal , rhs: Decimal ) {
628
- let result = try ? lhs . _divide ( by : rhs , roundingMode : . plain )
629
- if let result = result {
688
+ do {
689
+ let result = try lhs . _divide ( by : rhs , roundingMode : . plain )
630
690
lhs = result
691
+ } catch {
692
+ lhs = . nan
631
693
}
632
694
}
633
695
@@ -664,10 +726,72 @@ extension Decimal : SignedNumeric {
664
726
@available ( macOS 10 . 10 , iOS 8 . 0 , watchOS 2 . 0 , tvOS 9 . 0 , * )
665
727
extension Decimal : Strideable {
666
728
public func distance( to other: Decimal ) -> Decimal {
667
- return self - other
729
+ return other - self
668
730
}
669
731
670
732
public func advanced( by n: Decimal ) -> Decimal {
671
733
return self + n
672
734
}
673
735
}
736
+
737
+ // Max power
738
+ private extension Decimal {
739
+ // Creates a value with zero exponent.
740
+ // (Used by `_powersOfTenDividingUInt128Max`.)
741
+ init (
742
+ _length: UInt32 ,
743
+ _isCompact: UInt32 ,
744
+ _mantissa: ( UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 , UInt16 )
745
+ ) {
746
+ self . init (
747
+ _exponent: 0 ,
748
+ _length: _length,
749
+ _isNegative: 0 ,
750
+ _isCompact: _isCompact,
751
+ _reserved: 0 ,
752
+ _mantissa: _mantissa
753
+ )
754
+ }
755
+ }
756
+
757
+ private let _powersOfTenDividingUInt128Max = [
758
+ /* 10**00 dividing UInt128.max is deliberately omitted. */
759
+ /* 10**01 */ Decimal ( _length: 8 , _isCompact: 1 , _mantissa: ( 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x9999 , 0x1999 ) ) ,
760
+ /* 10**02 */ Decimal ( _length: 8 , _isCompact: 1 , _mantissa: ( 0xf5c2 , 0x5c28 , 0xc28f , 0x28f5 , 0x8f5c , 0xf5c2 , 0x5c28 , 0x028f ) ) ,
761
+ /* 10**03 */ Decimal ( _length: 8 , _isCompact: 1 , _mantissa: ( 0x1893 , 0x5604 , 0x2d0e , 0x9db2 , 0xa7ef , 0x4bc6 , 0x8937 , 0x0041 ) ) ,
762
+ /* 10**04 */ Decimal ( _length: 8 , _isCompact: 1 , _mantissa: ( 0x0275 , 0x089a , 0x9e1b , 0x295e , 0x10cb , 0xbac7 , 0x8db8 , 0x0006 ) ) ,
763
+ /* 10**05 */ Decimal ( _length: 7 , _isCompact: 1 , _mantissa: ( 0x3372 , 0x80dc , 0x0fcf , 0x8423 , 0x1b47 , 0xac47 , 0xa7c5 , 0 ) ) ,
764
+ /* 10**06 */ Decimal ( _length: 7 , _isCompact: 1 , _mantissa: ( 0x3858 , 0xf349 , 0xb4c7 , 0x8d36 , 0xb5ed , 0xf7a0 , 0x10c6 , 0 ) ) ,
765
+ /* 10**07 */ Decimal ( _length: 7 , _isCompact: 1 , _mantissa: ( 0xec08 , 0x6520 , 0x787a , 0xf485 , 0xabca , 0x7f29 , 0x01ad , 0 ) ) ,
766
+ /* 10**08 */ Decimal ( _length: 7 , _isCompact: 1 , _mantissa: ( 0x4acd , 0x7083 , 0xbf3f , 0x1873 , 0xc461 , 0xf31d , 0x002a , 0 ) ) ,
767
+ /* 10**09 */ Decimal ( _length: 7 , _isCompact: 1 , _mantissa: ( 0x5447 , 0x8b40 , 0x2cb9 , 0xb5a5 , 0xfa09 , 0x4b82 , 0x0004 , 0 ) ) ,
768
+ /* 10**10 */ Decimal ( _length: 6 , _isCompact: 1 , _mantissa: ( 0xa207 , 0x5ab9 , 0xeadf , 0x5ef6 , 0x7f67 , 0x6df3 , 0 , 0 ) ) ,
769
+ /* 10**11 */ Decimal ( _length: 6 , _isCompact: 1 , _mantissa: ( 0xf69a , 0xef78 , 0x4aaf , 0xbcb2 , 0xbff0 , 0x0afe , 0 , 0 ) ) ,
770
+ /* 10**12 */ Decimal ( _length: 6 , _isCompact: 1 , _mantissa: ( 0x7f0f , 0x97f2 , 0xa111 , 0x12de , 0x7998 , 0x0119 , 0 , 0 ) ) ,
771
+ /* 10**13 */ Decimal ( _length: 6 , _isCompact: 0 , _mantissa: ( 0x0cb4 , 0xc265 , 0x7681 , 0x6849 , 0x25c2 , 0x001c , 0 , 0 ) ) ,
772
+ /* 10**14 */ Decimal ( _length: 6 , _isCompact: 1 , _mantissa: ( 0x4e12 , 0x603d , 0x2573 , 0x70d4 , 0xd093 , 0x0002 , 0 , 0 ) ) ,
773
+ /* 10**15 */ Decimal ( _length: 5 , _isCompact: 1 , _mantissa: ( 0x87ce , 0x566c , 0x9d58 , 0xbe7b , 0x480e , 0 , 0 , 0 ) ) ,
774
+ /* 10**16 */ Decimal ( _length: 5 , _isCompact: 1 , _mantissa: ( 0xda61 , 0x6f0a , 0xf622 , 0xaca5 , 0x0734 , 0 , 0 , 0 ) ) ,
775
+ /* 10**17 */ Decimal ( _length: 5 , _isCompact: 1 , _mantissa: ( 0x4909 , 0xa4b4 , 0x3236 , 0x77aa , 0x00b8 , 0 , 0 , 0 ) ) ,
776
+ /* 10**18 */ Decimal ( _length: 5 , _isCompact: 1 , _mantissa: ( 0xa0e7 , 0x43ab , 0xd1d2 , 0x725d , 0x0012 , 0 , 0 , 0 ) ) ,
777
+ /* 10**19 */ Decimal ( _length: 5 , _isCompact: 1 , _mantissa: ( 0xc34a , 0x6d2a , 0x94fb , 0xd83c , 0x0001 , 0 , 0 , 0 ) ) ,
778
+ /* 10**20 */ Decimal ( _length: 4 , _isCompact: 1 , _mantissa: ( 0x46ba , 0x2484 , 0x4219 , 0x2f39 , 0 , 0 , 0 , 0 ) ) ,
779
+ /* 10**21 */ Decimal ( _length: 4 , _isCompact: 1 , _mantissa: ( 0xd3df , 0x83a6 , 0xed02 , 0x04b8 , 0 , 0 , 0 , 0 ) ) ,
780
+ /* 10**22 */ Decimal ( _length: 4 , _isCompact: 1 , _mantissa: ( 0x7b96 , 0x405d , 0xe480 , 0x0078 , 0 , 0 , 0 , 0 ) ) ,
781
+ /* 10**23 */ Decimal ( _length: 4 , _isCompact: 1 , _mantissa: ( 0x5928 , 0xa009 , 0x16d9 , 0x000c , 0 , 0 , 0 , 0 ) ) ,
782
+ /* 10**24 */ Decimal ( _length: 4 , _isCompact: 1 , _mantissa: ( 0x88ea , 0x299a , 0x357c , 0x0001 , 0 , 0 , 0 , 0 ) ) ,
783
+ /* 10**25 */ Decimal ( _length: 3 , _isCompact: 1 , _mantissa: ( 0xda7d , 0xd0f5 , 0x1ef2 , 0 , 0 , 0 , 0 , 0 ) ) ,
784
+ /* 10**26 */ Decimal ( _length: 3 , _isCompact: 1 , _mantissa: ( 0x95d9 , 0x4818 , 0x0318 , 0 , 0 , 0 , 0 , 0 ) ) ,
785
+ /* 10**27 */ Decimal ( _length: 3 , _isCompact: 0 , _mantissa: ( 0xdbc8 , 0x3a68 , 0x004f , 0 , 0 , 0 , 0 , 0 ) ) ,
786
+ /* 10**28 */ Decimal ( _length: 3 , _isCompact: 1 , _mantissa: ( 0xaf94 , 0xec3d , 0x0007 , 0 , 0 , 0 , 0 , 0 ) ) ,
787
+ /* 10**29 */ Decimal ( _length: 2 , _isCompact: 1 , _mantissa: ( 0xf7f5 , 0xcad2 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
788
+ /* 10**30 */ Decimal ( _length: 2 , _isCompact: 1 , _mantissa: ( 0x4bfe , 0x1448 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
789
+ /* 10**31 */ Decimal ( _length: 2 , _isCompact: 1 , _mantissa: ( 0x3acc , 0x0207 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
790
+ /* 10**32 */ Decimal ( _length: 2 , _isCompact: 1 , _mantissa: ( 0xec47 , 0x0033 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
791
+ /* 10**33 */ Decimal ( _length: 2 , _isCompact: 1 , _mantissa: ( 0x313a , 0x0005 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
792
+ /* 10**34 */ Decimal ( _length: 1 , _isCompact: 1 , _mantissa: ( 0x84ec , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
793
+ /* 10**35 */ Decimal ( _length: 1 , _isCompact: 1 , _mantissa: ( 0x0d4a , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
794
+ /* 10**36 */ Decimal ( _length: 1 , _isCompact: 0 , _mantissa: ( 0x0154 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
795
+ /* 10**37 */ Decimal ( _length: 1 , _isCompact: 1 , _mantissa: ( 0x0022 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ) ,
796
+ /* 10**38 */ Decimal ( _length: 1 , _isCompact: 1 , _mantissa: ( 0x0003 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) )
797
+ ]
0 commit comments