@@ -109,16 +109,39 @@ func signalNaN64() {
109
109
panic ("sNaN64" )
110
110
}
111
111
112
- func checkSignificandIsNormal (significand uint64 ) {
113
- logicCheck (decimal64Base <= significand , "%d <= %d" , decimal64Base , significand )
114
- logicCheck (significand < 10 * decimal64Base , "%d < %d" , significand , 10 * decimal64Base )
112
+ var small64s = [... ]Decimal64 {
113
+ new64FromInt64 (- 10 ),
114
+ new64FromInt64 (- 9 ),
115
+ new64FromInt64 (- 8 ),
116
+ new64FromInt64 (- 7 ),
117
+ new64FromInt64 (- 6 ),
118
+ new64FromInt64 (- 5 ),
119
+ new64FromInt64 (- 4 ),
120
+ new64FromInt64 (- 3 ),
121
+ new64FromInt64 (- 2 ),
122
+ NegOne64 ,
123
+ Zero64 ,
124
+ One64 ,
125
+ new64FromInt64 (2 ),
126
+ new64FromInt64 (3 ),
127
+ new64FromInt64 (4 ),
128
+ new64FromInt64 (5 ),
129
+ new64FromInt64 (6 ),
130
+ new64FromInt64 (7 ),
131
+ new64FromInt64 (8 ),
132
+ new64FromInt64 (9 ),
133
+ new64FromInt64 (10 ),
115
134
}
116
135
117
136
// New64FromInt64 returns a new Decimal64 with the given value.
118
- func New64FromInt64 (value int64 ) Decimal64 {
119
- if value == 0 {
120
- return Zero64
137
+ func New64FromInt64 (i int64 ) Decimal64 {
138
+ if i >= - 10 && i <= 10 {
139
+ return small64s [ 10 + i ]
121
140
}
141
+ return new64FromInt64 (i )
142
+ }
143
+
144
+ func new64FromInt64 (value int64 ) Decimal64 {
122
145
sign := 0
123
146
if value < 0 {
124
147
sign = 1
@@ -182,21 +205,25 @@ func roundStatus(significand uint64, exp int, targetExp int) discardedDigit {
182
205
// TODO: make this more efficent
183
206
func countTrailingZeros (n uint64 ) int {
184
207
zeros := 0
185
- if n % 10000000000000000 == 0 {
208
+ q := n / 1_0000_0000_0000_0000
209
+ if n == q * 1_0000_0000_0000_0000 {
186
210
zeros += 16
187
- n /= 10000000000000000
211
+ n = q
188
212
}
189
- if n % 100000000 == 0 {
213
+ q = n / 1_0000_0000
214
+ if n == q * 1_0000_0000 {
190
215
zeros += 8
191
- n /= 100000000
216
+ n = q
192
217
}
193
- if n % 10000 == 0 {
218
+ q = n / 10000
219
+ if n == q * 10000 {
194
220
zeros += 4
195
- n /= 10000
221
+ n = q
196
222
}
197
- if n % 100 == 0 {
223
+ q = n / 100
224
+ if n == q * 100 {
198
225
zeros += 2
199
- n /= 100
226
+ n = q
200
227
}
201
228
if n % 10 == 0 {
202
229
zeros ++
@@ -315,28 +342,36 @@ func (d Decimal64) Float64() float64 {
315
342
316
343
// Int64 returns an int64 representation of d, clamped to [[math.MinInt64], [math.MaxInt64]].
317
344
func (d Decimal64 ) Int64 () int64 {
345
+ i , _ := d .Int64x ()
346
+ return i
347
+ }
348
+
349
+ // Int64 returns an int64 representation of d, clamped to [[math.MinInt64],
350
+ // [math.MaxInt64]].
351
+ // The second return value, exact indicates whether New64FromInt64(i) == d.
352
+ func (d Decimal64 ) Int64x () (i int64 , exact bool ) {
318
353
fl , sign , exp , significand := d .parts ()
319
354
switch fl {
320
355
case flInf :
321
356
if sign == 0 {
322
- return math .MaxInt64
357
+ return math .MaxInt64 , false
323
358
}
324
- return math .MinInt64
359
+ return math .MinInt64 , false
325
360
case flQNaN :
326
- return 0
361
+ return 0 , false
327
362
case flSNaN :
328
363
signalNaN64 ()
329
- return 0
364
+ return 0 , false
330
365
}
331
- exp , whole , _ := expWholeFrac (exp , significand )
366
+ exp , whole , frac := expWholeFrac (exp , significand )
332
367
for exp > 0 && whole < math .MaxInt64 / 10 {
333
368
exp --
334
369
whole *= 10
335
370
}
336
371
if exp > 0 {
337
- return math .MaxInt64
372
+ return math .MaxInt64 , false
338
373
}
339
- return int64 (1 - 2 * sign ) * int64 (whole )
374
+ return int64 (1 - 2 * sign ) * int64 (whole ), frac == 0
340
375
}
341
376
342
377
// IsZero returns true if the Decimal encodes a zero value.
@@ -405,6 +440,62 @@ func (d Decimal64) Signbit() bool {
405
440
return d .bits >> 63 == 1
406
441
}
407
442
443
+ func (d Decimal64 ) ScaleB (e Decimal64 ) Decimal64 {
444
+ var dp decParts
445
+ dp .unpack (d )
446
+ var ep decParts
447
+ ep .unpack (e )
448
+ if r , nan := checkNan (& dp , & ep ); nan {
449
+ return r
450
+ }
451
+
452
+ if dp .fl != flNormal || dp .isZero () {
453
+ return d
454
+ }
455
+ if ep .fl != flNormal {
456
+ return QNaN64
457
+ }
458
+
459
+ i , exact := e .Int64x ()
460
+ if ! exact {
461
+ return QNaN64
462
+ }
463
+ return scaleBInt (& dp , int (i ))
464
+ }
465
+
466
+ func (d Decimal64 ) ScaleBInt (i int ) Decimal64 {
467
+ var dp decParts
468
+ dp .unpack (d )
469
+ if dp .fl != flNormal || dp .isZero () {
470
+ return d
471
+ }
472
+ return scaleBInt (& dp , i )
473
+ }
474
+
475
+ func scaleBInt (dp * decParts , i int ) Decimal64 {
476
+ dp .exp += i
477
+
478
+ for dp .significand .lo < decimal64Base && dp .exp > - expOffset {
479
+ dp .exp --
480
+ dp .significand .lo *= 10
481
+ }
482
+
483
+ switch {
484
+ case dp .exp > expMax :
485
+ return Infinity64 .CopySign (dp .original )
486
+ case dp .exp < - expOffset :
487
+ for dp .exp < - expOffset {
488
+ dp .exp ++
489
+ dp .significand .lo /= 10
490
+ }
491
+ if dp .significand .lo == 0 {
492
+ return Zero64 .CopySign (dp .original )
493
+ }
494
+ }
495
+
496
+ return dp .decimal64 ()
497
+ }
498
+
408
499
// Class returns a string representing the number's 'type' that the decimal is.
409
500
// It can be one of the following:
410
501
//
0 commit comments