aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/math/big/decimal.go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
commitaf146490bb04205107cb23e301ec7a8ff927b5fc (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/math/big/decimal.go
parent725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff)
downloadgcc-af146490bb04205107cb23e301ec7a8ff927b5fc.zip
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.bz2
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 From-SVN: r229616
Diffstat (limited to 'libgo/go/math/big/decimal.go')
-rw-r--r--libgo/go/math/big/decimal.go264
1 files changed, 264 insertions, 0 deletions
diff --git a/libgo/go/math/big/decimal.go b/libgo/go/math/big/decimal.go
new file mode 100644
index 0000000..2595e5f
--- /dev/null
+++ b/libgo/go/math/big/decimal.go
@@ -0,0 +1,264 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements multi-precision decimal numbers.
+// The implementation is for float to decimal conversion only;
+// not general purpose use.
+// The only operations are precise conversion from binary to
+// decimal and rounding.
+//
+// The key observation and some code (shr) is borrowed from
+// strconv/decimal.go: conversion of binary fractional values can be done
+// precisely in multi-precision decimal because 2 divides 10 (required for
+// >> of mantissa); but conversion of decimal floating-point values cannot
+// be done precisely in binary representation.
+//
+// In contrast to strconv/decimal.go, only right shift is implemented in
+// decimal format - left shift can be done precisely in binary format.
+
+package big
+
+// A decimal represents an unsigned floating-point number in decimal representation.
+// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// with the most-significant mantissa digit at index 0. For the zero decimal, the
+// mantissa length and exponent are 0.
+// The zero value for decimal represents a ready-to-use 0.0.
+type decimal struct {
+ mant []byte // mantissa ASCII digits, big-endian
+ exp int // exponent
+}
+
+// Maximum shift amount that can be done in one pass without overflow.
+// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
+const maxShift = _W - 4
+
+// TODO(gri) Since we know the desired decimal precision when converting
+// a floating-point number, we may be able to limit the number of decimal
+// digits that need to be computed by init by providing an additional
+// precision argument and keeping track of when a number was truncated early
+// (equivalent of "sticky bit" in binary rounding).
+
+// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
+// to avoid "infinitely" long running conversions (until we run out of space).
+
+// Init initializes x to the decimal representation of m << shift (for
+// shift >= 0), or m >> -shift (for shift < 0).
+func (x *decimal) init(m nat, shift int) {
+ // special case 0
+ if len(m) == 0 {
+ x.mant = x.mant[:0]
+ x.exp = 0
+ return
+ }
+
+ // Optimization: If we need to shift right, first remove any trailing
+ // zero bits from m to reduce shift amount that needs to be done in
+ // decimal format (since that is likely slower).
+ if shift < 0 {
+ ntz := m.trailingZeroBits()
+ s := uint(-shift)
+ if s >= ntz {
+ s = ntz // shift at most ntz bits
+ }
+ m = nat(nil).shr(m, s)
+ shift += int(s)
+ }
+
+ // Do any shift left in binary representation.
+ if shift > 0 {
+ m = nat(nil).shl(m, uint(shift))
+ shift = 0
+ }
+
+ // Convert mantissa into decimal representation.
+ s := m.decimalString() // TODO(gri) avoid string conversion here
+ n := len(s)
+ x.exp = n
+ // Trim trailing zeros; instead the exponent is tracking
+ // the decimal point independent of the number of digits.
+ for n > 0 && s[n-1] == '0' {
+ n--
+ }
+ x.mant = append(x.mant[:0], s[:n]...)
+
+ // Do any (remaining) shift right in decimal representation.
+ if shift < 0 {
+ for shift < -maxShift {
+ shr(x, maxShift)
+ shift += maxShift
+ }
+ shr(x, uint(-shift))
+ }
+}
+
+// Possibly optimization: The current implementation of nat.string takes
+// a charset argument. When a right shift is needed, we could provide
+// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
+// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
+// single +'0' pass at the end).
+
+// shr implements x >> s, for s <= maxShift.
+func shr(x *decimal, s uint) {
+ // Division by 1<<s using shift-and-subtract algorithm.
+
+ // pick up enough leading digits to cover first shift
+ r := 0 // read index
+ var n Word
+ for n>>s == 0 && r < len(x.mant) {
+ ch := Word(x.mant[r])
+ r++
+ n = n*10 + ch - '0'
+ }
+ if n == 0 {
+ // x == 0; shouldn't get here, but handle anyway
+ x.mant = x.mant[:0]
+ return
+ }
+ for n>>s == 0 {
+ r++
+ n *= 10
+ }
+ x.exp += 1 - r
+
+ // read a digit, write a digit
+ w := 0 // write index
+ for r < len(x.mant) {
+ ch := Word(x.mant[r])
+ r++
+ d := n >> s
+ n -= d << s
+ x.mant[w] = byte(d + '0')
+ w++
+ n = n*10 + ch - '0'
+ }
+
+ // write extra digits that still fit
+ for n > 0 && w < len(x.mant) {
+ d := n >> s
+ n -= d << s
+ x.mant[w] = byte(d + '0')
+ w++
+ n = n * 10
+ }
+ x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
+
+ // append additional digits that didn't fit
+ for n > 0 {
+ d := n >> s
+ n -= d << s
+ x.mant = append(x.mant, byte(d+'0'))
+ n = n * 10
+ }
+
+ trim(x)
+}
+
+func (x *decimal) String() string {
+ if len(x.mant) == 0 {
+ return "0"
+ }
+
+ var buf []byte
+ switch {
+ case x.exp <= 0:
+ // 0.00ddd
+ buf = append(buf, "0."...)
+ buf = appendZeros(buf, -x.exp)
+ buf = append(buf, x.mant...)
+
+ case /* 0 < */ x.exp < len(x.mant):
+ // dd.ddd
+ buf = append(buf, x.mant[:x.exp]...)
+ buf = append(buf, '.')
+ buf = append(buf, x.mant[x.exp:]...)
+
+ default: // len(x.mant) <= x.exp
+ // ddd00
+ buf = append(buf, x.mant...)
+ buf = appendZeros(buf, x.exp-len(x.mant))
+ }
+
+ return string(buf)
+}
+
+// appendZeros appends n 0 digits to buf and returns buf.
+func appendZeros(buf []byte, n int) []byte {
+ for ; n > 0; n-- {
+ buf = append(buf, '0')
+ }
+ return buf
+}
+
+// shouldRoundUp reports if x should be rounded up
+// if shortened to n digits. n must be a valid index
+// for x.mant.
+func shouldRoundUp(x *decimal, n int) bool {
+ if x.mant[n] == '5' && n+1 == len(x.mant) {
+ // exactly halfway - round to even
+ return n > 0 && (x.mant[n-1]-'0')&1 != 0
+ }
+ // not halfway - digit tells all (x.mant has no trailing zeros)
+ return x.mant[n] >= '5'
+}
+
+// round sets x to (at most) n mantissa digits by rounding it
+// to the nearest even value with n (or fever) mantissa digits.
+// If n < 0, x remains unchanged.
+func (x *decimal) round(n int) {
+ if n < 0 || n >= len(x.mant) {
+ return // nothing to do
+ }
+
+ if shouldRoundUp(x, n) {
+ x.roundUp(n)
+ } else {
+ x.roundDown(n)
+ }
+}
+
+func (x *decimal) roundUp(n int) {
+ if n < 0 || n >= len(x.mant) {
+ return // nothing to do
+ }
+ // 0 <= n < len(x.mant)
+
+ // find first digit < '9'
+ for n > 0 && x.mant[n-1] >= '9' {
+ n--
+ }
+
+ if n == 0 {
+ // all digits are '9's => round up to '1' and update exponent
+ x.mant[0] = '1' // ok since len(x.mant) > n
+ x.mant = x.mant[:1]
+ x.exp++
+ return
+ }
+
+ // n > 0 && x.mant[n-1] < '9'
+ x.mant[n-1]++
+ x.mant = x.mant[:n]
+ // x already trimmed
+}
+
+func (x *decimal) roundDown(n int) {
+ if n < 0 || n >= len(x.mant) {
+ return // nothing to do
+ }
+ x.mant = x.mant[:n]
+ trim(x)
+}
+
+// trim cuts off any trailing zeros from x's mantissa;
+// they are meaningless for the value of x.
+func trim(x *decimal) {
+ i := len(x.mant)
+ for i > 0 && x.mant[i-1] == '0' {
+ i--
+ }
+ x.mant = x.mant[:i]
+ if i == 0 {
+ x.exp = 0
+ }
+}