OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / internal / number / decimal.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:generate stringer -type RoundingMode
6
7 package number
8
9 import (
10         "math"
11         "strconv"
12 )
13
14 // RoundingMode determines how a number is rounded to the desired precision.
15 type RoundingMode byte
16
17 const (
18         ToNearestEven RoundingMode = iota // towards the nearest integer, or towards an even number if equidistant.
19         ToNearestZero                     // towards the nearest integer, or towards zero if equidistant.
20         ToNearestAway                     // towards the nearest integer, or away from zero if equidistant.
21         ToPositiveInf                     // towards infinity
22         ToNegativeInf                     // towards negative infinity
23         ToZero                            // towards zero
24         AwayFromZero                      // away from zero
25         numModes
26 )
27
28 const maxIntDigits = 20
29
30 // A Decimal represents a floating point number in decimal format.
31 // Digits represents a number [0, 1.0), and the absolute value represented by
32 // Decimal is Digits * 10^Exp. Leading and trailing zeros may be omitted and Exp
33 // may point outside a valid position in Digits.
34 //
35 // Examples:
36 //      Number     Decimal
37 //      12345      Digits: [1, 2, 3, 4, 5], Exp: 5
38 //      12.345     Digits: [1, 2, 3, 4, 5], Exp: 2
39 //      12000      Digits: [1, 2],          Exp: 5
40 //      12000.00   Digits: [1, 2],          Exp: 5
41 //      0.00123    Digits: [1, 2, 3],       Exp: -2
42 //      0          Digits: [],              Exp: 0
43 type Decimal struct {
44         digits
45
46         buf [maxIntDigits]byte
47 }
48
49 type digits struct {
50         Digits []byte // mantissa digits, big-endian
51         Exp    int32  // exponent
52         Neg    bool
53         Inf    bool // Takes precedence over Digits and Exp.
54         NaN    bool // Takes precedence over Inf.
55 }
56
57 // Digits represents a floating point number represented in digits of the
58 // base in which a number is to be displayed. It is similar to Decimal, but
59 // keeps track of trailing fraction zeros and the comma placement for
60 // engineering notation. Digits must have at least one digit.
61 //
62 // Examples:
63 //      Number     Decimal
64 //    decimal
65 //      12345      Digits: [1, 2, 3, 4, 5], Exp: 5  End: 5
66 //      12.345     Digits: [1, 2, 3, 4, 5], Exp: 2  End: 5
67 //      12000      Digits: [1, 2],          Exp: 5  End: 5
68 //      12000.00   Digits: [1, 2],          Exp: 5  End: 7
69 //      0.00123    Digits: [1, 2, 3],       Exp: -2 End: 3
70 //      0          Digits: [],              Exp: 0  End: 1
71 //    scientific (actual exp is Exp - Comma)
72 //      0e0        Digits: [0],             Exp: 1, End: 1, Comma: 1
73 //      .0e0       Digits: [0],             Exp: 0, End: 1, Comma: 0
74 //      0.0e0      Digits: [0],             Exp: 1, End: 2, Comma: 1
75 //      1.23e4     Digits: [1, 2, 3],       Exp: 5, End: 3, Comma: 1
76 //      .123e5     Digits: [1, 2, 3],       Exp: 5, End: 3, Comma: 0
77 //    engineering
78 //      12.3e3     Digits: [1, 2, 3],       Exp: 5, End: 3, Comma: 2
79 type Digits struct {
80         digits
81         // End indicates the end position of the number.
82         End int32 // For decimals Exp <= End. For scientific len(Digits) <= End.
83         // Comma is used for the comma position for scientific (always 0 or 1) and
84         // engineering notation (always 0, 1, 2, or 3).
85         Comma uint8
86         // IsScientific indicates whether this number is to be rendered as a
87         // scientific number.
88         IsScientific bool
89 }
90
91 func (d *Digits) NumFracDigits() int {
92         if d.Exp >= d.End {
93                 return 0
94         }
95         return int(d.End - d.Exp)
96 }
97
98 // normalize returns a new Decimal with leading and trailing zeros removed.
99 func (d *Decimal) normalize() (n Decimal) {
100         n = *d
101         b := n.Digits
102         // Strip leading zeros. Resulting number of digits is significant digits.
103         for len(b) > 0 && b[0] == 0 {
104                 b = b[1:]
105                 n.Exp--
106         }
107         // Strip trailing zeros
108         for len(b) > 0 && b[len(b)-1] == 0 {
109                 b = b[:len(b)-1]
110         }
111         if len(b) == 0 {
112                 n.Exp = 0
113         }
114         n.Digits = b
115         return n
116 }
117
118 func (d *Decimal) clear() {
119         b := d.Digits
120         if b == nil {
121                 b = d.buf[:0]
122         }
123         *d = Decimal{}
124         d.Digits = b[:0]
125 }
126
127 func (x *Decimal) String() string {
128         if x.NaN {
129                 return "NaN"
130         }
131         var buf []byte
132         if x.Neg {
133                 buf = append(buf, '-')
134         }
135         if x.Inf {
136                 buf = append(buf, "Inf"...)
137                 return string(buf)
138         }
139         switch {
140         case len(x.Digits) == 0:
141                 buf = append(buf, '0')
142         case x.Exp <= 0:
143                 // 0.00ddd
144                 buf = append(buf, "0."...)
145                 buf = appendZeros(buf, -int(x.Exp))
146                 buf = appendDigits(buf, x.Digits)
147
148         case /* 0 < */ int(x.Exp) < len(x.Digits):
149                 // dd.ddd
150                 buf = appendDigits(buf, x.Digits[:x.Exp])
151                 buf = append(buf, '.')
152                 buf = appendDigits(buf, x.Digits[x.Exp:])
153
154         default: // len(x.Digits) <= x.Exp
155                 // ddd00
156                 buf = appendDigits(buf, x.Digits)
157                 buf = appendZeros(buf, int(x.Exp)-len(x.Digits))
158         }
159         return string(buf)
160 }
161
162 func appendDigits(buf []byte, digits []byte) []byte {
163         for _, c := range digits {
164                 buf = append(buf, c+'0')
165         }
166         return buf
167 }
168
169 // appendZeros appends n 0 digits to buf and returns buf.
170 func appendZeros(buf []byte, n int) []byte {
171         for ; n > 0; n-- {
172                 buf = append(buf, '0')
173         }
174         return buf
175 }
176
177 func (d *digits) round(mode RoundingMode, n int) {
178         if n >= len(d.Digits) {
179                 return
180         }
181         // Make rounding decision: The result mantissa is truncated ("rounded down")
182         // by default. Decide if we need to increment, or "round up", the (unsigned)
183         // mantissa.
184         inc := false
185         switch mode {
186         case ToNegativeInf:
187                 inc = d.Neg
188         case ToPositiveInf:
189                 inc = !d.Neg
190         case ToZero:
191                 // nothing to do
192         case AwayFromZero:
193                 inc = true
194         case ToNearestEven:
195                 inc = d.Digits[n] > 5 || d.Digits[n] == 5 &&
196                         (len(d.Digits) > n+1 || n == 0 || d.Digits[n-1]&1 != 0)
197         case ToNearestAway:
198                 inc = d.Digits[n] >= 5
199         case ToNearestZero:
200                 inc = d.Digits[n] > 5 || d.Digits[n] == 5 && len(d.Digits) > n+1
201         default:
202                 panic("unreachable")
203         }
204         if inc {
205                 d.roundUp(n)
206         } else {
207                 d.roundDown(n)
208         }
209 }
210
211 // roundFloat rounds a floating point number.
212 func (r RoundingMode) roundFloat(x float64) float64 {
213         // Make rounding decision: The result mantissa is truncated ("rounded down")
214         // by default. Decide if we need to increment, or "round up", the (unsigned)
215         // mantissa.
216         abs := x
217         if x < 0 {
218                 abs = -x
219         }
220         i, f := math.Modf(abs)
221         if f == 0.0 {
222                 return x
223         }
224         inc := false
225         switch r {
226         case ToNegativeInf:
227                 inc = x < 0
228         case ToPositiveInf:
229                 inc = x >= 0
230         case ToZero:
231                 // nothing to do
232         case AwayFromZero:
233                 inc = true
234         case ToNearestEven:
235                 // TODO: check overflow
236                 inc = f > 0.5 || f == 0.5 && int64(i)&1 != 0
237         case ToNearestAway:
238                 inc = f >= 0.5
239         case ToNearestZero:
240                 inc = f > 0.5
241         default:
242                 panic("unreachable")
243         }
244         if inc {
245                 i += 1
246         }
247         if abs != x {
248                 i = -i
249         }
250         return i
251 }
252
253 func (x *digits) roundUp(n int) {
254         if n < 0 || n >= len(x.Digits) {
255                 return // nothing to do
256         }
257         // find first digit < 9
258         for n > 0 && x.Digits[n-1] >= 9 {
259                 n--
260         }
261
262         if n == 0 {
263                 // all digits are 9s => round up to 1 and update exponent
264                 x.Digits[0] = 1 // ok since len(x.Digits) > n
265                 x.Digits = x.Digits[:1]
266                 x.Exp++
267                 return
268         }
269         x.Digits[n-1]++
270         x.Digits = x.Digits[:n]
271         // x already trimmed
272 }
273
274 func (x *digits) roundDown(n int) {
275         if n < 0 || n >= len(x.Digits) {
276                 return // nothing to do
277         }
278         x.Digits = x.Digits[:n]
279         trim(x)
280 }
281
282 // trim cuts off any trailing zeros from x's mantissa;
283 // they are meaningless for the value of x.
284 func trim(x *digits) {
285         i := len(x.Digits)
286         for i > 0 && x.Digits[i-1] == 0 {
287                 i--
288         }
289         x.Digits = x.Digits[:i]
290         if i == 0 {
291                 x.Exp = 0
292         }
293 }
294
295 // A Converter converts a number into decimals according to the given rounding
296 // criteria.
297 type Converter interface {
298         Convert(d *Decimal, r RoundingContext)
299 }
300
301 const (
302         signed   = true
303         unsigned = false
304 )
305
306 // Convert converts the given number to the decimal representation using the
307 // supplied RoundingContext.
308 func (d *Decimal) Convert(r RoundingContext, number interface{}) {
309         switch f := number.(type) {
310         case Converter:
311                 d.clear()
312                 f.Convert(d, r)
313         case float32:
314                 d.ConvertFloat(r, float64(f), 32)
315         case float64:
316                 d.ConvertFloat(r, f, 64)
317         case int:
318                 d.ConvertInt(r, signed, uint64(f))
319         case int8:
320                 d.ConvertInt(r, signed, uint64(f))
321         case int16:
322                 d.ConvertInt(r, signed, uint64(f))
323         case int32:
324                 d.ConvertInt(r, signed, uint64(f))
325         case int64:
326                 d.ConvertInt(r, signed, uint64(f))
327         case uint:
328                 d.ConvertInt(r, unsigned, uint64(f))
329         case uint8:
330                 d.ConvertInt(r, unsigned, uint64(f))
331         case uint16:
332                 d.ConvertInt(r, unsigned, uint64(f))
333         case uint32:
334                 d.ConvertInt(r, unsigned, uint64(f))
335         case uint64:
336                 d.ConvertInt(r, unsigned, f)
337
338         default:
339                 d.NaN = true
340                 // TODO:
341                 // case string: if produced by strconv, allows for easy arbitrary pos.
342                 // case reflect.Value:
343                 // case big.Float
344                 // case big.Int
345                 // case big.Rat?
346                 // catch underlyings using reflect or will this already be done by the
347                 //    message package?
348         }
349 }
350
351 // ConvertInt converts an integer to decimals.
352 func (d *Decimal) ConvertInt(r RoundingContext, signed bool, x uint64) {
353         if r.Increment > 0 {
354                 // TODO: if uint64 is too large, fall back to float64
355                 if signed {
356                         d.ConvertFloat(r, float64(int64(x)), 64)
357                 } else {
358                         d.ConvertFloat(r, float64(x), 64)
359                 }
360                 return
361         }
362         d.clear()
363         if signed && int64(x) < 0 {
364                 x = uint64(-int64(x))
365                 d.Neg = true
366         }
367         d.fillIntDigits(x)
368         d.Exp = int32(len(d.Digits))
369 }
370
371 // ConvertFloat converts a floating point number to decimals.
372 func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) {
373         d.clear()
374         if math.IsNaN(x) {
375                 d.NaN = true
376                 return
377         }
378         // Simple case: decimal notation
379         if r.Increment > 0 {
380                 scale := int(r.IncrementScale)
381                 mult := 1.0
382                 if scale > len(scales) {
383                         mult = math.Pow(10, float64(scale))
384                 } else {
385                         mult = scales[scale]
386                 }
387                 // We multiply x instead of dividing inc as it gives less rounding
388                 // issues.
389                 x *= mult
390                 x /= float64(r.Increment)
391                 x = r.Mode.roundFloat(x)
392                 x *= float64(r.Increment)
393                 x /= mult
394         }
395
396         abs := x
397         if x < 0 {
398                 d.Neg = true
399                 abs = -x
400         }
401         if math.IsInf(abs, 1) {
402                 d.Inf = true
403                 return
404         }
405
406         // By default we get the exact decimal representation.
407         verb := byte('g')
408         prec := -1
409         // Determine rounding, if possible. As the strconv API does not return the
410         // rounding accuracy (exact/rounded up|down), we can only round using
411         // ToNearestEven.
412         //   Something like this would work:
413         //   AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int)
414         if r.Mode == ToNearestEven {
415                 // We can't round if limitations are placed on both the fraction and
416                 // significant digits.
417                 if r.MaxFractionDigits == 0 && r.MaxSignificantDigits > 0 {
418                         prec = int(r.MaxSignificantDigits)
419                 } else if r.isScientific() {
420                         if r.MaxIntegerDigits == 1 && (r.MaxSignificantDigits == 0 ||
421                                 int(r.MaxFractionDigits+1) == int(r.MaxSignificantDigits)) {
422                                 verb = 'e'
423                                 // Note: don't add DigitShift: it is only used for decimals.
424                                 prec = int(r.MaxFractionDigits)
425                                 prec += int(r.DigitShift)
426                         }
427                 } else if r.MaxFractionDigits > 0 && r.MaxSignificantDigits == 0 {
428                         verb = 'f'
429                         prec = int(r.MaxFractionDigits) + int(r.DigitShift)
430                 }
431         }
432
433         b := strconv.AppendFloat(d.Digits[:0], abs, verb, prec, size)
434         i := 0
435         k := 0
436         beforeDot := 1
437         for i < len(b) {
438                 if c := b[i]; '0' <= c && c <= '9' {
439                         b[k] = c - '0'
440                         k++
441                         d.Exp += int32(beforeDot)
442                 } else if c == '.' {
443                         beforeDot = 0
444                         d.Exp = int32(k)
445                 } else {
446                         break
447                 }
448                 i++
449         }
450         d.Digits = b[:k]
451         if i != len(b) {
452                 i += len("e")
453                 pSign := i
454                 exp := 0
455                 for i++; i < len(b); i++ {
456                         exp *= 10
457                         exp += int(b[i] - '0')
458                 }
459                 if b[pSign] == '-' {
460                         exp = -exp
461                 }
462                 d.Exp = int32(exp) + 1
463         }
464 }
465
466 func (d *Decimal) fillIntDigits(x uint64) {
467         if cap(d.Digits) < maxIntDigits {
468                 d.Digits = d.buf[:]
469         } else {
470                 d.Digits = d.buf[:maxIntDigits]
471         }
472         i := 0
473         for ; x > 0; x /= 10 {
474                 d.Digits[i] = byte(x % 10)
475                 i++
476         }
477         d.Digits = d.Digits[:i]
478         for p := 0; p < i; p++ {
479                 i--
480                 d.Digits[p], d.Digits[i] = d.Digits[i], d.Digits[p]
481         }
482 }
483
484 var scales [70]float64
485
486 func init() {
487         x := 1.0
488         for i := range scales {
489                 scales[i] = x
490                 x *= 10
491         }
492 }