@@ -441,12 +441,39 @@ extension Decimal {
441441 self . compact ( )
442442 }
443443 }
444+
444445 public init ( _ value: UInt64 ) {
445- self . init ( Double ( value) )
446+ self = Decimal ( )
447+ if value == 0 {
448+ return
449+ }
450+
451+ var compactValue = value
452+ var exponent : Int32 = 0
453+ while compactValue % 10 == 0 {
454+ compactValue = compactValue / 10
455+ exponent = exponent + 1
456+ }
457+ _isCompact = 1
458+ _exponent = exponent
459+
460+ let wordCount = ( ( UInt64 . bitWidth - compactValue. leadingZeroBitCount) + ( UInt16 . bitWidth - 1 ) ) / UInt16. bitWidth
461+ _length = UInt32 ( wordCount)
462+ _mantissa. 0 = UInt16 ( truncatingIfNeeded: compactValue >> 0 )
463+ _mantissa. 1 = UInt16 ( truncatingIfNeeded: compactValue >> 16 )
464+ _mantissa. 2 = UInt16 ( truncatingIfNeeded: compactValue >> 32 )
465+ _mantissa. 3 = UInt16 ( truncatingIfNeeded: compactValue >> 48 )
446466 }
467+
447468 public init ( _ value: Int64 ) {
448- self . init ( Double ( value) )
469+ if value < 0 {
470+ self . init ( value == Int64 . min ? UInt64 ( Int64 . max) + 1 : UInt64 ( abs ( value) ) )
471+ _isNegative = 1
472+ } else {
473+ self . init ( UInt64 ( value) )
474+ }
449475 }
476+
450477 public init ( _ value: UInt ) {
451478 self . init ( UInt64 ( value) )
452479 }
@@ -1164,62 +1191,60 @@ public func NSDecimalAdd(_ result: UnsafeMutablePointer<Decimal>, _ leftOperand:
11641191}
11651192
11661193fileprivate func integerAdd( _ result: inout WideDecimal , _ left: inout Decimal , _ right: inout Decimal ) -> NSDecimalNumber . CalculationError {
1167- var i : UInt32 = 0
1168- var carry : UInt16 = 0
1169- var accumulator : UInt32 = 0
1170-
1171- let c : UInt32 = min ( left. _length, right. _length)
1194+ var idx : UInt32 = 0
1195+ var carry : UInt16 = 0
1196+ let maxIndex : UInt32 = min ( left. _length, right. _length) // The highest index with bits set in both values
11721197
1173- while i < c {
1174- let li = UInt32 ( left [ i ] )
1175- let ri = UInt32 ( right [ i ] )
1176- accumulator = li + ri + UInt32( carry)
1177- carry = UInt16 ( truncatingIfNeeded: accumulator >> 16 )
1178- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1179- i += 1
1198+ while idx < maxIndex {
1199+ let li = UInt32 ( left [ idx ] )
1200+ let ri = UInt32 ( right [ idx ] )
1201+ let sum = li + ri + UInt32( carry)
1202+ carry = UInt16 ( truncatingIfNeeded: sum >> 16 )
1203+ result [ idx ] = UInt16 ( truncatingIfNeeded: sum )
1204+ idx += 1
11801205 }
11811206
1182- while i < left. _length {
1207+ while idx < left. _length {
11831208 if carry != 0 {
1184- let li = UInt32 ( left [ i ] )
1185- accumulator = li + UInt32( carry)
1186- carry = UInt16 ( truncatingIfNeeded: accumulator >> 16 )
1187- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1188- i += 1
1209+ let li = UInt32 ( left [ idx ] )
1210+ let sum = li + UInt32( carry)
1211+ carry = UInt16 ( truncatingIfNeeded: sum >> 16 )
1212+ result [ idx ] = UInt16 ( truncatingIfNeeded: sum )
1213+ idx += 1
11891214 } else {
1190- while i < left. _length {
1191- result [ i ] = left [ i ]
1192- i += 1
1215+ while idx < left. _length {
1216+ result [ idx ] = left [ idx ]
1217+ idx += 1
11931218 }
11941219 break
11951220 }
11961221 }
1197- while i < right. _length {
1222+ while idx < right. _length {
11981223 if carry != 0 {
1199- let ri = UInt32 ( right [ i ] )
1200- accumulator = ri + UInt32( carry)
1201- carry = UInt16 ( truncatingIfNeeded: accumulator >> 16 )
1202- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1203- i += 1
1224+ let ri = UInt32 ( right [ idx ] )
1225+ let sum = ri + UInt32( carry)
1226+ carry = UInt16 ( truncatingIfNeeded: sum >> 16 )
1227+ result [ idx ] = UInt16 ( truncatingIfNeeded: sum )
1228+ idx += 1
12041229 } else {
1205- while i < right. _length {
1206- result [ i ] = right [ i ]
1207- i += 1
1230+ while idx < right. _length {
1231+ result [ idx ] = right [ idx ]
1232+ idx += 1
12081233 }
12091234 break
12101235 }
12111236 }
1237+ result. _length = idx
12121238
12131239 if carry != 0 {
1214- if result. _length < i {
1215- result. _length = i
1216- return . overflow
1217- } else {
1218- result [ i] = carry
1219- i += 1
1220- }
1240+ result [ idx] = carry
1241+ idx += 1
1242+ result. _length = idx
12211243 }
1222- result. _length = i;
1244+ if idx > Decimal . maxSize {
1245+ return . overflow
1246+ }
1247+
12231248 return . noError;
12241249}
12251250
@@ -1231,49 +1256,48 @@ fileprivate func integerAdd(_ result: inout WideDecimal, _ left: inout Decimal,
12311256// give b-a...
12321257//
12331258fileprivate func integerSubtract( _ result: inout Decimal , _ left: inout Decimal , _ right: inout Decimal ) -> NSDecimalNumber . CalculationError {
1234- var i : UInt32 = 0
1235- var carry : UInt16 = 1
1236- var accumulator : UInt32 = 0
1237-
1238- let c : UInt32 = min ( left . _length , right . _length )
1239-
1240- while i < c {
1241- let li = UInt32 ( left [ i ] )
1242- let ri = UInt32 ( right [ i ] )
1243- accumulator = 0xffff + li - ri + UInt32 ( carry )
1244- carry = UInt16 ( truncatingIfNeeded : accumulator >> 16 )
1245- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1246- i += 1
1247- }
1248-
1249- while i < left. _length {
1250- if carry != 0 {
1251- let li = UInt32 ( left [ i ] )
1252- accumulator = 0xffff + li // + no carry
1253- carry = UInt16 ( truncatingIfNeeded: accumulator >> 16 )
1254- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1255- i += 1
1259+ var idx : UInt32 = 0
1260+ let maxIndex : UInt32 = min ( left . _length , right . _length ) // The highest index with bits set in both values
1261+ var borrow : UInt16 = 0
1262+
1263+ while idx < maxIndex {
1264+ let li = UInt32 ( left [ idx ] )
1265+ let ri = UInt32 ( right [ idx ] )
1266+ // 0x10000 is to borrow in advance to avoid underflow.
1267+ let difference : UInt32 = ( 0x10000 + li ) - UInt32( borrow ) - ri
1268+ result [ idx ] = UInt16 ( truncatingIfNeeded : difference )
1269+ // borrow = 1 if the borrow was used.
1270+ borrow = 1 - UInt16( truncatingIfNeeded: difference >> 16 )
1271+ idx += 1
1272+ }
1273+
1274+ while idx < left. _length {
1275+ if borrow != 0 {
1276+ let li = UInt32 ( left [ idx ] )
1277+ let sum = 0xffff + li // + no carry
1278+ borrow = 1 - UInt16( truncatingIfNeeded: sum >> 16 )
1279+ result [ idx ] = UInt16 ( truncatingIfNeeded: sum )
1280+ idx += 1
12561281 } else {
1257- while i < left. _length {
1258- result [ i ] = left [ i ]
1259- i += 1
1282+ while idx < left. _length {
1283+ result [ idx ] = left [ idx ]
1284+ idx += 1
12601285 }
12611286 break
12621287 }
12631288 }
1264- while i < right. _length {
1265- let ri = UInt32 ( right [ i ] )
1266- accumulator = 0xffff - ri + UInt32( carry )
1267- carry = UInt16 ( truncatingIfNeeded: accumulator >> 16 )
1268- result [ i ] = UInt16 ( truncatingIfNeeded: accumulator )
1269- i += 1
1289+ while idx < right. _length {
1290+ let ri = UInt32 ( right [ idx ] )
1291+ let difference = 0xffff - ri + UInt32( borrow )
1292+ borrow = 1 - UInt16( truncatingIfNeeded: difference >> 16 )
1293+ result [ idx ] = UInt16 ( truncatingIfNeeded: difference )
1294+ idx += 1
12701295 }
12711296
1272- if carry != 0 {
1297+ if borrow != 0 {
12731298 return . overflow
12741299 }
1275- result. _length = i;
1276-
1300+ result. _length = idx;
12771301 result. trimTrailingZeros ( )
12781302
12791303 return . noError;
0 commit comments