@@ -170,16 +170,35 @@ extension Decimal /* : FloatingPoint */ {
170170 self = Decimal ( )
171171 let negative = value < 0
172172 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.
174177 while val < Double ( UInt64 . max - 1 ) {
178+ guard exponent > Int8 . min else {
179+ self = . nan
180+ return
181+ }
175182 val *= 10.0
176183 exponent -= 1
177184 }
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+ }
179190 val /= 10.0
180191 exponent += 1
181192 }
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+ }
183202
184203 var i : UInt32 = 0
185204 // This is a bit ugly but it is the closest approximation of the C
@@ -217,13 +236,24 @@ extension Decimal /* : FloatingPoint */ {
217236 }
218237
219238 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+ }
227257 }
228258
229259 public init ( signOf: Decimal , magnitudeOf magnitude: Decimal ) {
@@ -242,7 +272,7 @@ extension Decimal /* : FloatingPoint */ {
242272
243273 public var significand : Decimal {
244274 return Decimal (
245- _exponent: 0 , _length: _length, _isNegative: _isNegative , _isCompact: _isCompact,
275+ _exponent: 0 , _length: _length, _isNegative: 0 , _isCompact: _isCompact,
246276 _reserved: 0 , _mantissa: _mantissa)
247277 }
248278
@@ -251,9 +281,20 @@ extension Decimal /* : FloatingPoint */ {
251281 }
252282
253283 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+
255296 return Decimal (
256- _exponent: _exponent , _length: 8 , _isNegative: 0 , _isCompact: 1 ,
297+ _exponent: max ( exponent , - 128 ) , _length: 1 , _isNegative: 0 , _isCompact: 1 ,
257298 _reserved: 0 , _mantissa: ( 0x0001 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 , 0x0000 ) )
258299 }
259300
@@ -309,25 +350,38 @@ extension Decimal /* : FloatingPoint */ {
309350 public mutating func formTruncatingRemainder( dividingBy other: Decimal ) { fatalError ( " Decimal does not yet fully adopt FloatingPoint " ) }
310351
311352 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
320381 }
321382
322383 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
331385 }
332386
333387 public func isEqual( to other: Decimal ) -> Bool {
@@ -604,30 +658,38 @@ extension Decimal : SignedNumeric {
604658#endif
605659
606660 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 )
609663 lhs = result. result
664+ } catch {
665+ lhs = . nan
610666 }
611667 }
612668
613669 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 )
616672 lhs = result
673+ } catch {
674+ lhs = . nan
617675 }
618676 }
619677
620678 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 )
623681 lhs = result
682+ } catch {
683+ lhs = . nan
624684 }
625685 }
626686
627687 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 )
630690 lhs = result
691+ } catch {
692+ lhs = . nan
631693 }
632694 }
633695
@@ -664,10 +726,72 @@ extension Decimal : SignedNumeric {
664726@available ( macOS 10 . 10 , iOS 8 . 0 , watchOS 2 . 0 , tvOS 9 . 0 , * )
665727extension Decimal : Strideable {
666728 public func distance( to other: Decimal ) -> Decimal {
667- return self - other
729+ return other - self
668730 }
669731
670732 public func advanced( by n: Decimal ) -> Decimal {
671733 return self + n
672734 }
673735}
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