diff options
| author | Rob Pike <r@golang.org> | 2009-06-09 09:53:44 -0700 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2009-06-09 09:53:44 -0700 |
| commit | 7249ea4df2b4f12a4e7ed446f270cea87e4ffd34 (patch) | |
| tree | 7032a11d0cac2ae4d3e90f7a189b575b5a50f848 /src/lib/strconv/decimal.go | |
| parent | acf6ef7a82b3fe61516a1bac4563706552bdf078 (diff) | |
| download | golang-7249ea4df2b4f12a4e7ed446f270cea87e4ffd34.tar.gz | |
mv src/lib to src/pkg
tests: all.bash passes, gobuild still works, godoc still works.
R=rsc
OCL=30096
CL=30102
Diffstat (limited to 'src/lib/strconv/decimal.go')
| -rw-r--r-- | src/lib/strconv/decimal.go | 392 |
1 files changed, 0 insertions, 392 deletions
diff --git a/src/lib/strconv/decimal.go b/src/lib/strconv/decimal.go deleted file mode 100644 index 38d9c47fb..000000000 --- a/src/lib/strconv/decimal.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright 2009 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. - -// Multiprecision decimal numbers. -// For floating-point formatting only; not general purpose. -// Only operations are assign and (binary) left/right shift. -// Can do binary floating point in multiprecision decimal precisely -// because 2 divides 10; cannot do decimal floating point -// in multiprecision binary precisely. - -package strconv - -import "bytes" - -type decimal struct { - // TODO(rsc): Can make d[] a bit smaller and add - // truncated bool; - d [2000] byte; // digits - nd int; // number of digits used - dp int; // decimal point -}; -func (a *decimal) String() string; -func (a *decimal) Assign(v uint64); -func (a *decimal) Shift(k int) *decimal; -func (a *decimal) Round(nd int) *decimal; -func (a *decimal) RoundUp(nd int) *decimal; -func (a *decimal) RoundDown(nd int) *decimal; -func (a *decimal) RoundedInteger() uint64; - - -func digitZero(dst []byte) int; - -func (a *decimal) String() string { - n := 10 + a.nd; - if a.dp > 0 { - n += a.dp; - } - if a.dp < 0 { - n += -a.dp; - } - - buf := make([]byte, n); - w := 0; - switch { - case a.nd == 0: - return "0"; - - case a.dp <= 0: - // zeros fill space between decimal point and digits - buf[w] = '0'; - w++; - buf[w] = '.'; - w++; - w += digitZero(buf[w:w+-a.dp]); - w += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); - - case a.dp < a.nd: - // decimal point in middle of digits - w += bytes.Copy(buf[w:w+a.dp], a.d[0:a.dp]); - buf[w] = '.'; - w++; - w += bytes.Copy(buf[w:w+a.nd-a.dp], a.d[a.dp:a.nd]); - - default: - // zeros fill space between digits and decimal point - w += bytes.Copy(buf[w:w+a.nd], a.d[0:a.nd]); - w += digitZero(buf[w:w+a.dp-a.nd]); - } - return string(buf[0:w]); -} - -func copy(dst []byte, src []byte) int { - for i := 0; i < len(dst); i++ { - dst[i] = src[i]; - } - return len(dst); -} - -func digitZero(dst []byte) int { - for i := 0; i < len(dst); i++ { - dst[i] = '0'; - } - return len(dst); -} - -// trim trailing zeros from number. -// (They are meaningless; the decimal point is tracked -// independent of the number of digits.) -func trim(a *decimal) { - for a.nd > 0 && a.d[a.nd-1] == '0' { - a.nd--; - } - if a.nd == 0 { - a.dp = 0; - } -} - -// Assign v to a. -func (a *decimal) Assign(v uint64) { - var buf [50]byte; - - // Write reversed decimal in buf. - n := 0; - for v > 0 { - v1 := v/10; - v -= 10*v1; - buf[n] = byte(v + '0'); - n++; - v = v1; - } - - // Reverse again to produce forward decimal in a.d. - a.nd = 0; - for n--; n>=0; n-- { - a.d[a.nd] = buf[n]; - a.nd++; - } - a.dp = a.nd; - trim(a); -} - -func newDecimal(i uint64) *decimal { - a := new(decimal); - a.Assign(i); - return a; -} - -// Maximum shift that we can do in one pass without overflow. -// Signed int has 31 bits, and we have to be able to accomodate 9<<k. -const maxShift = 27 - -// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow. -func rightShift(a *decimal, k uint) { - r := 0; // read pointer - w := 0; // write pointer - - // Pick up enough leading digits to cover first shift. - n := 0; - for ; n>>k == 0; r++ { - if r >= a.nd { - if n == 0 { - // a == 0; shouldn't get here, but handle anyway. - a.nd = 0; - return; - } - for n>>k == 0 { - n = n*10; - r++; - } - break; - } - c := int(a.d[r]); - n = n*10 + c-'0'; - } - a.dp -= r-1; - - // Pick up a digit, put down a digit. - for ; r < a.nd; r++ { - c := int(a.d[r]); - dig := n>>k; - n -= dig<<k; - a.d[w] = byte(dig+'0'); - w++; - n = n*10 + c-'0'; - } - - // Put down extra digits. - for n > 0 { - dig := n>>k; - n -= dig<<k; - a.d[w] = byte(dig+'0'); - w++; - n = n*10; - } - - a.nd = w; - trim(a); -} - -// Cheat sheet for left shift: table indexed by shift count giving -// number of new digits that will be introduced by that shift. -// -// For example, leftcheats[4] = {2, "625"}. That means that -// if we are shifting by 4 (multiplying by 16), it will add 2 digits -// when the string prefix is "625" through "999", and one fewer digit -// if the string prefix is "000" through "624". -// -// Credit for this trick goes to Ken. - -type leftCheat struct { - delta int; // number of new digits - cutoff string; // minus one digit if original < a. -} - -var leftcheats = []leftCheat { - // Leading digits of 1/2^i = 5^i. - // 5^23 is not an exact 64-bit floating point number, - // so have to use bc for the math. - /* - seq 27 | sed 's/^/5^/' | bc | - awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," } - { - log2 = log(2)/log(10) - printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n", - int(log2*NR+1), $0, 2**NR) - }' - */ - leftCheat{ 0, "" }, - leftCheat{ 1, "5" }, // * 2 - leftCheat{ 1, "25" }, // * 4 - leftCheat{ 1, "125" }, // * 8 - leftCheat{ 2, "625" }, // * 16 - leftCheat{ 2, "3125" }, // * 32 - leftCheat{ 2, "15625" }, // * 64 - leftCheat{ 3, "78125" }, // * 128 - leftCheat{ 3, "390625" }, // * 256 - leftCheat{ 3, "1953125" }, // * 512 - leftCheat{ 4, "9765625" }, // * 1024 - leftCheat{ 4, "48828125" }, // * 2048 - leftCheat{ 4, "244140625" }, // * 4096 - leftCheat{ 4, "1220703125" }, // * 8192 - leftCheat{ 5, "6103515625" }, // * 16384 - leftCheat{ 5, "30517578125" }, // * 32768 - leftCheat{ 5, "152587890625" }, // * 65536 - leftCheat{ 6, "762939453125" }, // * 131072 - leftCheat{ 6, "3814697265625" }, // * 262144 - leftCheat{ 6, "19073486328125" }, // * 524288 - leftCheat{ 7, "95367431640625" }, // * 1048576 - leftCheat{ 7, "476837158203125" }, // * 2097152 - leftCheat{ 7, "2384185791015625" }, // * 4194304 - leftCheat{ 7, "11920928955078125" }, // * 8388608 - leftCheat{ 8, "59604644775390625" }, // * 16777216 - leftCheat{ 8, "298023223876953125" }, // * 33554432 - leftCheat{ 8, "1490116119384765625" }, // * 67108864 - leftCheat{ 9, "7450580596923828125" }, // * 134217728 -} - -// Is the leading prefix of b lexicographically less than s? -func prefixIsLessThan(b []byte, s string) bool { - for i := 0; i < len(s); i++ { - if i >= len(b) { - return true; - } - if b[i] != s[i] { - return b[i] < s[i]; - } - } - return false; -} - -// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow. -func leftShift(a *decimal, k uint) { - delta := leftcheats[k].delta; - if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { - delta--; - } - - r := a.nd; // read index - w := a.nd + delta; // write index - n := 0; - - // Pick up a digit, put down a digit. - for r--; r >= 0; r-- { - n += (int(a.d[r])-'0') << k; - quo := n/10; - rem := n - 10*quo; - w--; - a.d[w] = byte(rem+'0'); - n = quo; - } - - // Put down extra digits. - for n > 0 { - quo := n/10; - rem := n - 10*quo; - w--; - a.d[w] = byte(rem+'0'); - n = quo; - } - - if w != 0 { - // TODO: Remove - has no business panicking. - panicln("strconv: bad leftShift", w); - } - a.nd += delta; - a.dp += delta; - trim(a); -} - -// Binary shift left (k > 0) or right (k < 0). -// Returns receiver for convenience. -func (a *decimal) Shift(k int) *decimal { - switch { - case a.nd == 0: - // nothing to do: a == 0 - case k > 0: - for k > maxShift { - leftShift(a, maxShift); - k -= maxShift; - } - leftShift(a, uint(k)); - case k < 0: - for k < -maxShift { - rightShift(a, maxShift); - k += maxShift; - } - rightShift(a, uint(-k)); - } - return a; -} - -// If we chop a at nd digits, should we round up? -func shouldRoundUp(a *decimal, nd int) bool { - if nd <= 0 || nd >= a.nd { - return false; - } - if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even - return (a.d[nd-1] - '0') % 2 != 0; - } - // not halfway - digit tells all - return a.d[nd] >= '5'; -} - -// Round a to nd digits (or fewer). -// Returns receiver for convenience. -func (a *decimal) Round(nd int) *decimal { - if nd <= 0 || nd >= a.nd { - return a; - } - if(shouldRoundUp(a, nd)) { - return a.RoundUp(nd); - } - return a.RoundDown(nd); -} - -// Round a down to nd digits (or fewer). -// Returns receiver for convenience. -func (a *decimal) RoundDown(nd int) *decimal { - if nd <= 0 || nd >= a.nd { - return a; - } - a.nd = nd; - trim(a); - return a; -} - -// Round a up to nd digits (or fewer). -// Returns receiver for convenience. -func (a *decimal) RoundUp(nd int) *decimal { - if nd <= 0 || nd >= a.nd { - return a; - } - - // round up - for i := nd-1; i >= 0; i-- { - c := a.d[i]; - if c < '9' { // can stop after this digit - a.d[i]++; - a.nd = i+1; - return a; - } - } - - // Number is all 9s. - // Change to single 1 with adjusted decimal point. - a.d[0] = '1'; - a.nd = 1; - a.dp++; - return a; -} - -// Extract integer part, rounded appropriately. -// No guarantees about overflow. -func (a *decimal) RoundedInteger() uint64 { - if a.dp > 20 { - return 0xFFFFFFFFFFFFFFFF; - } - var i int; - n := uint64(0); - for i = 0; i < a.dp && i < a.nd; i++ { - n = n*10 + uint64(a.d[i] - '0'); - } - for ; i < a.dp; i++ { - n *= 10; - } - if shouldRoundUp(a, a.dp) { - n++; - } - return n; -} - |
