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.
5 //go:generate stringer -type RoundingMode
14 // RoundingMode determines how a number is rounded to the desired precision.
15 type RoundingMode byte
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
28 const maxIntDigits = 20
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.
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
46 buf [maxIntDigits]byte
50 Digits []byte // mantissa digits, big-endian
53 Inf bool // Takes precedence over Digits and Exp.
54 NaN bool // Takes precedence over Inf.
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.
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
78 // 12.3e3 Digits: [1, 2, 3], Exp: 5, End: 3, Comma: 2
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).
86 // IsScientific indicates whether this number is to be rendered as a
91 func (d *Digits) NumFracDigits() int {
95 return int(d.End - d.Exp)
98 // normalize returns a new Decimal with leading and trailing zeros removed.
99 func (d *Decimal) normalize() (n Decimal) {
102 // Strip leading zeros. Resulting number of digits is significant digits.
103 for len(b) > 0 && b[0] == 0 {
107 // Strip trailing zeros
108 for len(b) > 0 && b[len(b)-1] == 0 {
118 func (d *Decimal) clear() {
127 func (x *Decimal) String() string {
133 buf = append(buf, '-')
136 buf = append(buf, "Inf"...)
140 case len(x.Digits) == 0:
141 buf = append(buf, '0')
144 buf = append(buf, "0."...)
145 buf = appendZeros(buf, -int(x.Exp))
146 buf = appendDigits(buf, x.Digits)
148 case /* 0 < */ int(x.Exp) < len(x.Digits):
150 buf = appendDigits(buf, x.Digits[:x.Exp])
151 buf = append(buf, '.')
152 buf = appendDigits(buf, x.Digits[x.Exp:])
154 default: // len(x.Digits) <= x.Exp
156 buf = appendDigits(buf, x.Digits)
157 buf = appendZeros(buf, int(x.Exp)-len(x.Digits))
162 func appendDigits(buf []byte, digits []byte) []byte {
163 for _, c := range digits {
164 buf = append(buf, c+'0')
169 // appendZeros appends n 0 digits to buf and returns buf.
170 func appendZeros(buf []byte, n int) []byte {
172 buf = append(buf, '0')
177 func (d *digits) round(mode RoundingMode, n int) {
178 if n >= len(d.Digits) {
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)
195 inc = d.Digits[n] > 5 || d.Digits[n] == 5 &&
196 (len(d.Digits) > n+1 || n == 0 || d.Digits[n-1]&1 != 0)
198 inc = d.Digits[n] >= 5
200 inc = d.Digits[n] > 5 || d.Digits[n] == 5 && len(d.Digits) > n+1
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)
220 i, f := math.Modf(abs)
235 // TODO: check overflow
236 inc = f > 0.5 || f == 0.5 && int64(i)&1 != 0
253 func (x *digits) roundUp(n int) {
254 if n < 0 || n >= len(x.Digits) {
255 return // nothing to do
257 // find first digit < 9
258 for n > 0 && x.Digits[n-1] >= 9 {
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]
270 x.Digits = x.Digits[:n]
274 func (x *digits) roundDown(n int) {
275 if n < 0 || n >= len(x.Digits) {
276 return // nothing to do
278 x.Digits = x.Digits[:n]
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) {
286 for i > 0 && x.Digits[i-1] == 0 {
289 x.Digits = x.Digits[:i]
295 // A Converter converts a number into decimals according to the given rounding
297 type Converter interface {
298 Convert(d *Decimal, r RoundingContext)
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) {
314 d.ConvertFloat(r, float64(f), 32)
316 d.ConvertFloat(r, f, 64)
318 d.ConvertInt(r, signed, uint64(f))
320 d.ConvertInt(r, signed, uint64(f))
322 d.ConvertInt(r, signed, uint64(f))
324 d.ConvertInt(r, signed, uint64(f))
326 d.ConvertInt(r, signed, uint64(f))
328 d.ConvertInt(r, unsigned, uint64(f))
330 d.ConvertInt(r, unsigned, uint64(f))
332 d.ConvertInt(r, unsigned, uint64(f))
334 d.ConvertInt(r, unsigned, uint64(f))
336 d.ConvertInt(r, unsigned, f)
341 // case string: if produced by strconv, allows for easy arbitrary pos.
342 // case reflect.Value:
346 // catch underlyings using reflect or will this already be done by the
351 // ConvertInt converts an integer to decimals.
352 func (d *Decimal) ConvertInt(r RoundingContext, signed bool, x uint64) {
354 // TODO: if uint64 is too large, fall back to float64
356 d.ConvertFloat(r, float64(int64(x)), 64)
358 d.ConvertFloat(r, float64(x), 64)
363 if signed && int64(x) < 0 {
364 x = uint64(-int64(x))
368 d.Exp = int32(len(d.Digits))
371 // ConvertFloat converts a floating point number to decimals.
372 func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) {
378 // Simple case: decimal notation
380 scale := int(r.IncrementScale)
382 if scale > len(scales) {
383 mult = math.Pow(10, float64(scale))
387 // We multiply x instead of dividing inc as it gives less rounding
390 x /= float64(r.Increment)
391 x = r.Mode.roundFloat(x)
392 x *= float64(r.Increment)
401 if math.IsInf(abs, 1) {
406 // By default we get the exact decimal representation.
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
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)) {
423 // Note: don't add DigitShift: it is only used for decimals.
424 prec = int(r.MaxFractionDigits)
425 prec += int(r.DigitShift)
427 } else if r.MaxFractionDigits > 0 && r.MaxSignificantDigits == 0 {
429 prec = int(r.MaxFractionDigits) + int(r.DigitShift)
433 b := strconv.AppendFloat(d.Digits[:0], abs, verb, prec, size)
438 if c := b[i]; '0' <= c && c <= '9' {
441 d.Exp += int32(beforeDot)
455 for i++; i < len(b); i++ {
457 exp += int(b[i] - '0')
462 d.Exp = int32(exp) + 1
466 func (d *Decimal) fillIntDigits(x uint64) {
467 if cap(d.Digits) < maxIntDigits {
470 d.Digits = d.buf[:maxIntDigits]
473 for ; x > 0; x /= 10 {
474 d.Digits[i] = byte(x % 10)
477 d.Digits = d.Digits[:i]
478 for p := 0; p < i; p++ {
480 d.Digits[p], d.Digits[i] = d.Digits[i], d.Digits[p]
484 var scales [70]float64
488 for i := range scales {