From 902ecfbb7f64e51256e26cc71d15fd92dc1617f9 Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Mon, 13 Jun 2016 12:31:48 -0500 Subject: [PATCH 1/7] Increased build number --- apiserver/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/build.sh b/apiserver/build.sh index deea8ea2..ea901c07 100755 --- a/apiserver/build.sh +++ b/apiserver/build.sh @@ -2,7 +2,7 @@ BUILD_DATE=`date +%Y-%m-%d\ %H:%M` VERSIONFILE="version.go" -VERSION="1.0-alpha" +VERSION="1.0.1" APP="apiserver" if [ "$1" = "build" ] || [ -z $1 ]; then From db0503aeaac7147ae6797d2d886523e4bfb9369f Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Thu, 30 Jun 2016 13:24:33 -0500 Subject: [PATCH 2/7] Added godep restore --- apiserver/gobuild.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/gobuild.sh b/apiserver/gobuild.sh index 06f3336d..bc665fc5 100755 --- a/apiserver/gobuild.sh +++ b/apiserver/gobuild.sh @@ -2,5 +2,5 @@ cd /go/src/github.com/ndslabs/apiserver go get github.com/tools/godep -#go build -ldflags "-X main.Version=0.1alpha -X main.BuildDate=`date "+%Y-%m-%dT%H:%M:%S"`" +godep restore GOOS=linux GOARCH=amd64 godep go build -o build/bin/apiserver-linux-amd64 From a11223e40a41838a23a61197fa9ea0f66d355635 Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Thu, 30 Jun 2016 13:25:45 -0500 Subject: [PATCH 3/7] Added godep --- apictl/gobuild.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apictl/gobuild.sh b/apictl/gobuild.sh index 6a208c09..17239a92 100755 --- a/apictl/gobuild.sh +++ b/apictl/gobuild.sh @@ -1,5 +1,6 @@ #!/bin/bash cd /go/src/github.com/ndslabs/apictl -go get -GOOS=linux GOARCH=amd64 go build -o build/bin/ndslabsctl-linux-amd64 +go get github.com/tools/godep +godep restore +GOOS=linux GOARCH=amd64 godep go build -o build/bin/apiserver-linux-amd64 From e1db1f7adb545a212dc3d6bfb7b072317ef227ae Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Thu, 30 Jun 2016 13:31:22 -0500 Subject: [PATCH 4/7] Added godep support --- apictl/Godeps/Godeps.json | 131 ++++++++++++++++++++++++++++++++++++++ apictl/Godeps/Readme | 5 ++ 2 files changed, 136 insertions(+) create mode 100644 apictl/Godeps/Godeps.json create mode 100644 apictl/Godeps/Readme diff --git a/apictl/Godeps/Godeps.json b/apictl/Godeps/Godeps.json new file mode 100644 index 00000000..4b08d4e5 --- /dev/null +++ b/apictl/Godeps/Godeps.json @@ -0,0 +1,131 @@ +{ + "ImportPath": "github.com/ndslabs/apictl", + "GoVersion": "go1.5", + "GodepVersion": "v65", + "Deps": [ + { + "ImportPath": "github.com/BurntSushi/toml", + "Comment": "v0.1.0-25-g312db06", + "Rev": "312db06c6c6dbfa9899e58564bacfaa584f18ab7" + }, + { + "ImportPath": "github.com/Sirupsen/logrus", + "Comment": "v0.9.0-8-g57cce1e", + "Rev": "57cce1ed6103dce7791881d3e69e55f90d986aa5" + }, + { + "ImportPath": "github.com/docker/docker/pkg/term", + "Comment": "v1.4.1-4831-g0f5c9d3", + "Rev": "0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d" + }, + { + "ImportPath": "github.com/docker/docker/pkg/term/winconsole", + "Comment": "v1.4.1-4831-g0f5c9d3", + "Rev": "0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d" + }, + { + "ImportPath": "github.com/hashicorp/hcl", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/hcl/ast", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/hcl/parser", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/hcl/scanner", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/hcl/strconv", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/hcl/token", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/json/parser", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/json/scanner", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/hashicorp/hcl/json/token", + "Rev": "1c284ec98f4b398443cbabb0d9197f7f4cc0077c" + }, + { + "ImportPath": "github.com/inconshreveable/mousetrap", + "Rev": "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + }, + { + "ImportPath": "github.com/kr/pretty", + "Comment": "go.weekly.2011-12-22-27-ge6ac2fc", + "Rev": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb" + }, + { + "ImportPath": "github.com/kr/text", + "Rev": "bb797dc4fb8320488f47bf11de07a733d7233e1f" + }, + { + "ImportPath": "github.com/magiconair/properties", + "Comment": "v1.6.0-1-gc81f9d7", + "Rev": "c81f9d71af8f8cba1466501d30326b99a4e56c19" + }, + { + "ImportPath": "github.com/mitchellh/mapstructure", + "Rev": "740c764bc6149d3f1806231418adb9f52c11bcbf" + }, + { + "ImportPath": "github.com/ndslabs/apiserver/types", + "Comment": "testing_NDS-269-39-ga11223e", + "Rev": "a11223e40a41838a23a61197fa9ea0f66d355635" + }, + { + "ImportPath": "github.com/spf13/cast", + "Rev": "ee7b3e0353166ab1f3a605294ac8cd2b77953778" + }, + { + "ImportPath": "github.com/spf13/cobra", + "Rev": "4c05eb1145f16d0e6bb4a3e1b6d769f4713cb41f" + }, + { + "ImportPath": "github.com/spf13/jwalterweatherman", + "Rev": "d00654080cddbd2b082acaa74007cb94a2b40866" + }, + { + "ImportPath": "github.com/spf13/pflag", + "Rev": "08b1a584251b5b62f458943640fc8ebd4d50aaa5" + }, + { + "ImportPath": "github.com/spf13/viper", + "Rev": "c975dc1b4eacf4ec7fdbf0873638de5d090ba323" + }, + { + "ImportPath": "golang.org/x/crypto/ssh/terminal", + "Rev": "1f22c0103821b9390939b6776727195525381532" + }, + { + "ImportPath": "golang.org/x/net/websocket", + "Rev": "c2528b2dd8352441850638a8bb678c2ad056fd3e" + }, + { + "ImportPath": "golang.org/x/sys/unix", + "Rev": "50c6bc5e4292a1d4e65c6e9be5f53be28bcbe28e" + }, + { + "ImportPath": "gopkg.in/fsnotify.v1", + "Comment": "v1.2.9", + "Rev": "8611c35ab31c1c28aa903d33cf8b6e44a399b09e" + }, + { + "ImportPath": "gopkg.in/yaml.v2", + "Rev": "a83829b6f1293c91addabc89d0571c246397bbf4" + } + ] +} diff --git a/apictl/Godeps/Readme b/apictl/Godeps/Readme new file mode 100644 index 00000000..4cdaa53d --- /dev/null +++ b/apictl/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. From b34c6c2db449e527fc0b0ce35c0ca3839ad58876 Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Fri, 1 Jul 2016 15:07:19 -0500 Subject: [PATCH 5/7] Added missing speter.net dependency --- apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf | 1 + 1 file changed, 1 insertion(+) create mode 160000 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf new file mode 160000 index 00000000..42ca6cd6 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf @@ -0,0 +1 @@ +Subproject commit 42ca6cd68aa922bc3f32f1e056e61b65945d9ad7 From 3b7899d4521dc61b6ee345d11546268faf46bd8c Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Fri, 1 Jul 2016 15:20:37 -0500 Subject: [PATCH 6/7] Removed speter --- apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf | 1 - 1 file changed, 1 deletion(-) delete mode 160000 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf deleted file mode 160000 index 42ca6cd6..00000000 --- a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 42ca6cd68aa922bc3f32f1e056e61b65945d9ad7 From bb18e33e482babe034b42f28de65a79d245e1039 Mon Sep 17 00:00:00 2001 From: Craig Willis Date: Fri, 1 Jul 2016 15:21:37 -0500 Subject: [PATCH 7/7] Try again --- .../speter.net/go/exp/math/dec/inf/LICENSE | 57 ++ .../go/exp/math/dec/inf/benchmark_test.go | 210 ++++++ .../src/speter.net/go/exp/math/dec/inf/dec.go | 615 ++++++++++++++++++ .../go/exp/math/dec/inf/dec_go1_2_test.go | 33 + .../go/exp/math/dec/inf/dec_internal_test.go | 40 ++ .../go/exp/math/dec/inf/dec_test.go | 379 +++++++++++ .../go/exp/math/dec/inf/example_test.go | 62 ++ .../speter.net/go/exp/math/dec/inf/rounder.go | 145 +++++ .../exp/math/dec/inf/rounder_example_test.go | 72 ++ .../go/exp/math/dec/inf/rounder_test.go | 109 ++++ 10 files changed, 1722 insertions(+) create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/example_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_example_test.go create mode 100644 apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE new file mode 100644 index 00000000..efa1aa18 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE @@ -0,0 +1,57 @@ +Copyright (c) 2012 Péter Surányi. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +Portions of inf.Dec's source code have been derived from Go and are +covered by the following license: +---------------------------------------------------------------------- + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go new file mode 100644 index 00000000..27071da0 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go @@ -0,0 +1,210 @@ +package inf + +import ( + "fmt" + "math/big" + "math/rand" + "sync" + "testing" +) + +const maxcap = 1024 * 1024 +const bits = 256 +const maxscale = 32 + +var once sync.Once + +var decInput [][2]Dec +var intInput [][2]big.Int + +var initBench = func() { + decInput = make([][2]Dec, maxcap) + intInput = make([][2]big.Int, maxcap) + max := new(big.Int).Lsh(big.NewInt(1), bits) + r := rand.New(rand.NewSource(0)) + for i := 0; i < cap(decInput); i++ { + decInput[i][0].SetUnscaledBig(new(big.Int).Rand(r, max)). + SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale))) + decInput[i][1].SetUnscaledBig(new(big.Int).Rand(r, max)). + SetScale(Scale(r.Int31n(int32(2*maxscale-1)) - int32(maxscale))) + } + for i := 0; i < cap(intInput); i++ { + intInput[i][0].Rand(r, max) + intInput[i][1].Rand(r, max) + } +} + +func doBenchmarkDec1(b *testing.B, f func(z *Dec)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&decInput[i%maxcap][0]) + } +} + +func doBenchmarkDec2(b *testing.B, f func(x, y *Dec)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&decInput[i%maxcap][0], &decInput[i%maxcap][1]) + } +} + +func doBenchmarkInt1(b *testing.B, f func(z *big.Int)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&intInput[i%maxcap][0]) + } +} + +func doBenchmarkInt2(b *testing.B, f func(x, y *big.Int)) { + once.Do(initBench) + b.ResetTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + f(&intInput[i%maxcap][0], &intInput[i%maxcap][1]) + } +} + +func Benchmark_Dec_String(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + x.String() + }) +} + +func Benchmark_Dec_StringScan(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + s := x.String() + d := new(Dec) + fmt.Sscan(s, d) + }) +} + +func Benchmark_Dec_GobEncode(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + x.GobEncode() + }) +} + +func Benchmark_Dec_GobEnDecode(b *testing.B) { + doBenchmarkDec1(b, func(x *Dec) { + g, _ := x.GobEncode() + new(Dec).GobDecode(g) + }) +} + +func Benchmark_Dec_Add(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + ys := y.Scale() + y.SetScale(x.Scale()) + _ = new(Dec).Add(x, y) + y.SetScale(ys) + }) +} + +func Benchmark_Dec_AddMixed(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Add(x, y) + }) +} + +func Benchmark_Dec_Sub(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + ys := y.Scale() + y.SetScale(x.Scale()) + _ = new(Dec).Sub(x, y) + y.SetScale(ys) + }) +} + +func Benchmark_Dec_SubMixed(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Sub(x, y) + }) +} + +func Benchmark_Dec_Mul(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).Mul(x, y) + }) +} + +func Benchmark_Dec_Mul_QuoExact(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + v := new(Dec).Mul(x, y) + _ = new(Dec).QuoExact(v, y) + }) +} + +func Benchmark_Dec_QuoRound_Fixed_Down(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).QuoRound(x, y, 0, RoundDown) + }) +} + +func Benchmark_Dec_QuoRound_Fixed_HalfUp(b *testing.B) { + doBenchmarkDec2(b, func(x, y *Dec) { + _ = new(Dec).QuoRound(x, y, 0, RoundHalfUp) + }) +} + +func Benchmark_Int_String(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + x.String() + }) +} + +func Benchmark_Int_StringScan(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + s := x.String() + d := new(big.Int) + fmt.Sscan(s, d) + }) +} + +func Benchmark_Int_GobEncode(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + x.GobEncode() + }) +} + +func Benchmark_Int_GobEnDecode(b *testing.B) { + doBenchmarkInt1(b, func(x *big.Int) { + g, _ := x.GobEncode() + new(big.Int).GobDecode(g) + }) +} + +func Benchmark_Int_Add(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Add(x, y) + }) +} + +func Benchmark_Int_Sub(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Sub(x, y) + }) +} + +func Benchmark_Int_Mul(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Mul(x, y) + }) +} + +func Benchmark_Int_Quo(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _ = new(big.Int).Quo(x, y) + }) +} + +func Benchmark_Int_QuoRem(b *testing.B) { + doBenchmarkInt2(b, func(x, y *big.Int) { + _, _ = new(big.Int).QuoRem(x, y, new(big.Int)) + }) +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go new file mode 100644 index 00000000..d17ad945 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go @@ -0,0 +1,615 @@ +// Package inf (type inf.Dec) implements "infinite-precision" decimal +// arithmetic. +// "Infinite precision" describes two characteristics: practically unlimited +// precision for decimal number representation and no support for calculating +// with any specific fixed precision. +// (Although there is no practical limit on precision, inf.Dec can only +// represent finite decimals.) +// +// This package is currently in experimental stage and the API may change. +// +// This package does NOT support: +// - rounding to specific precisions (as opposed to specific decimal positions) +// - the notion of context (each rounding must be explicit) +// - NaN and Inf values, and distinguishing between positive and negative zero +// - conversions to and from float32/64 types +// +// Features considered for possible addition: +// + formatting options +// + Exp method +// + combined operations such as AddRound/MulAdd etc +// + exchanging data in decimal32/64/128 formats +// +package inf + +// TODO: +// - avoid excessive deep copying (quo and rounders) + +import ( + "fmt" + "io" + "math/big" + "strings" +) + +// A Dec represents a signed arbitrary-precision decimal. +// It is a combination of a sign, an arbitrary-precision integer coefficient +// value, and a signed fixed-precision exponent value. +// The sign and the coefficient value are handled together as a signed value +// and referred to as the unscaled value. +// (Positive and negative zero values are not distinguished.) +// Since the exponent is most commonly non-positive, it is handled in negated +// form and referred to as scale. +// +// The mathematical value of a Dec equals: +// +// unscaled * 10**(-scale) +// +// Note that different Dec representations may have equal mathematical values. +// +// unscaled scale String() +// ------------------------- +// 0 0 "0" +// 0 2 "0.00" +// 0 -2 "0" +// 1 0 "1" +// 100 2 "1.00" +// 10 0 "10" +// 1 -1 "10" +// +// The zero value for a Dec represents the value 0 with scale 0. +// +// Operations are typically performed through the *Dec type. +// The semantics of the assignment operation "=" for "bare" Dec values is +// undefined and should not be relied on. +// +// Methods are typically of the form: +// +// func (z *Dec) Op(x, y *Dec) *Dec +// +// and implement operations z = x Op y with the result as receiver; if it +// is one of the operands it may be overwritten (and its memory reused). +// To enable chaining of operations, the result is also returned. Methods +// returning a result other than *Dec take one of the operands as the receiver. +// +// A "bare" Quo method (quotient / division operation) is not provided, as the +// result is not always a finite decimal and thus in general cannot be +// represented as a Dec. +// Instead, in the common case when rounding is (potentially) necessary, +// QuoRound should be used with a Scale and a Rounder. +// QuoExact or QuoRound with RoundExact can be used in the special cases when it +// is known that the result is always a finite decimal. +// +type Dec struct { + unscaled big.Int + scale Scale +} + +// Scale represents the type used for the scale of a Dec. +type Scale int32 + +const scaleSize = 4 // bytes in a Scale value + +// Scaler represents a method for obtaining the scale to use for the result of +// an operation on x and y. +type scaler interface { + Scale(x *Dec, y *Dec) Scale +} + +var bigInt = [...]*big.Int{ + big.NewInt(0), big.NewInt(1), big.NewInt(2), big.NewInt(3), big.NewInt(4), + big.NewInt(5), big.NewInt(6), big.NewInt(7), big.NewInt(8), big.NewInt(9), + big.NewInt(10), +} + +var exp10cache [64]big.Int = func() [64]big.Int { + e10, e10i := [64]big.Int{}, bigInt[1] + for i, _ := range e10 { + e10[i].Set(e10i) + e10i = new(big.Int).Mul(e10i, bigInt[10]) + } + return e10 +}() + +// NewDec allocates and returns a new Dec set to the given int64 unscaled value +// and scale. +func NewDec(unscaled int64, scale Scale) *Dec { + return new(Dec).SetUnscaled(unscaled).SetScale(scale) +} + +// NewDecBig allocates and returns a new Dec set to the given *big.Int unscaled +// value and scale. +func NewDecBig(unscaled *big.Int, scale Scale) *Dec { + return new(Dec).SetUnscaledBig(unscaled).SetScale(scale) +} + +// Scale returns the scale of x. +func (x *Dec) Scale() Scale { + return x.scale +} + +// Unscaled returns the unscaled value of x for u and true for ok when the +// unscaled value can be represented as int64; otherwise it returns an undefined +// int64 value for u and false for ok. Use x.UnscaledBig().Int64() to avoid +// checking the validity of the value when the check is known to be redundant. +func (x *Dec) Unscaled() (u int64, ok bool) { + u = x.unscaled.Int64() + var i big.Int + ok = i.SetInt64(u).Cmp(&x.unscaled) == 0 + return +} + +// UnscaledBig returns the unscaled value of x as *big.Int. +func (x *Dec) UnscaledBig() *big.Int { + return &x.unscaled +} + +// SetScale sets the scale of z, with the unscaled value unchanged, and returns +// z. +// The mathematical value of the Dec changes as if it was multiplied by +// 10**(oldscale-scale). +func (z *Dec) SetScale(scale Scale) *Dec { + z.scale = scale + return z +} + +// SetUnscaled sets the unscaled value of z, with the scale unchanged, and +// returns z. +func (z *Dec) SetUnscaled(unscaled int64) *Dec { + z.unscaled.SetInt64(unscaled) + return z +} + +// SetUnscaledBig sets the unscaled value of z, with the scale unchanged, and +// returns z. +func (z *Dec) SetUnscaledBig(unscaled *big.Int) *Dec { + z.unscaled.Set(unscaled) + return z +} + +// Set sets z to the value of x and returns z. +// It does nothing if z == x. +func (z *Dec) Set(x *Dec) *Dec { + if z != x { + z.SetUnscaledBig(x.UnscaledBig()) + z.SetScale(x.Scale()) + } + return z +} + +// Sign returns: +// +// -1 if x < 0 +// 0 if x == 0 +// +1 if x > 0 +// +func (x *Dec) Sign() int { + return x.UnscaledBig().Sign() +} + +// Neg sets z to -x and returns z. +func (z *Dec) Neg(x *Dec) *Dec { + z.SetScale(x.Scale()) + z.UnscaledBig().Neg(x.UnscaledBig()) + return z +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +// +func (x *Dec) Cmp(y *Dec) int { + xx, yy := upscale(x, y) + return xx.UnscaledBig().Cmp(yy.UnscaledBig()) +} + +// Abs sets z to |x| (the absolute value of x) and returns z. +func (z *Dec) Abs(x *Dec) *Dec { + z.SetScale(x.Scale()) + z.UnscaledBig().Abs(x.UnscaledBig()) + return z +} + +// Add sets z to the sum x+y and returns z. +// The scale of z is the greater of the scales of x and y. +func (z *Dec) Add(x, y *Dec) *Dec { + xx, yy := upscale(x, y) + z.SetScale(xx.Scale()) + z.UnscaledBig().Add(xx.UnscaledBig(), yy.UnscaledBig()) + return z +} + +// Sub sets z to the difference x-y and returns z. +// The scale of z is the greater of the scales of x and y. +func (z *Dec) Sub(x, y *Dec) *Dec { + xx, yy := upscale(x, y) + z.SetScale(xx.Scale()) + z.UnscaledBig().Sub(xx.UnscaledBig(), yy.UnscaledBig()) + return z +} + +// Mul sets z to the product x*y and returns z. +// The scale of z is the sum of the scales of x and y. +func (z *Dec) Mul(x, y *Dec) *Dec { + z.SetScale(x.Scale() + y.Scale()) + z.UnscaledBig().Mul(x.UnscaledBig(), y.UnscaledBig()) + return z +} + +// Round sets z to the value of x rounded to Scale s using Rounder r, and +// returns z. +func (z *Dec) Round(x *Dec, s Scale, r Rounder) *Dec { + return z.QuoRound(x, NewDec(1, 0), s, r) +} + +// QuoRound sets z to the quotient x/y, rounded using the given Rounder to the +// specified scale. +// +// If the rounder is RoundExact but the result can not be expressed exactly at +// the specified scale, QuoRound returns nil, and the value of z is undefined. +// +// There is no corresponding Div method; the equivalent can be achieved through +// the choice of Rounder used. +// +func (z *Dec) QuoRound(x, y *Dec, s Scale, r Rounder) *Dec { + return z.quo(x, y, sclr{s}, r) +} + +func (z *Dec) quo(x, y *Dec, s scaler, r Rounder) *Dec { + scl := s.Scale(x, y) + var zzz *Dec + if r.UseRemainder() { + zz, rA, rB := new(Dec).quoRem(x, y, scl, true, new(big.Int), new(big.Int)) + zzz = r.Round(new(Dec), zz, rA, rB) + } else { + zz, _, _ := new(Dec).quoRem(x, y, scl, false, nil, nil) + zzz = r.Round(new(Dec), zz, nil, nil) + } + if zzz == nil { + return nil + } + return z.Set(zzz) +} + +// QuoExact sets z to the quotient x/y and returns z when x/y is a finite +// decimal. Otherwise it returns nil and the value of z is undefined. +// +// The scale of a non-nil result is "x.Scale() - y.Scale()" or greater; it is +// calculated so that the remainder will be zero whenever x/y is a finite +// decimal. +func (z *Dec) QuoExact(x, y *Dec) *Dec { + return z.quo(x, y, scaleQuoExact{}, RoundExact) +} + +// quoRem sets z to the quotient x/y with the scale s, and if useRem is true, +// it sets remNum and remDen to the numerator and denominator of the remainder. +// It returns z, remNum and remDen. +// +// The remainder is normalized to the range -1 < r < 1 to simplify rounding; +// that is, the results satisfy the following equation: +// +// x / y = z + (remNum/remDen) * 10**(-z.Scale()) +// +// See Rounder for more details about rounding. +// +func (z *Dec) quoRem(x, y *Dec, s Scale, useRem bool, + remNum, remDen *big.Int) (*Dec, *big.Int, *big.Int) { + // difference (required adjustment) compared to "canonical" result scale + shift := s - (x.Scale() - y.Scale()) + // pointers to adjusted unscaled dividend and divisor + var ix, iy *big.Int + switch { + case shift > 0: + // increased scale: decimal-shift dividend left + ix = new(big.Int).Mul(x.UnscaledBig(), exp10(shift)) + iy = y.UnscaledBig() + case shift < 0: + // decreased scale: decimal-shift divisor left + ix = x.UnscaledBig() + iy = new(big.Int).Mul(y.UnscaledBig(), exp10(-shift)) + default: + ix = x.UnscaledBig() + iy = y.UnscaledBig() + } + // save a copy of iy in case it to be overwritten with the result + iy2 := iy + if iy == z.UnscaledBig() { + iy2 = new(big.Int).Set(iy) + } + // set scale + z.SetScale(s) + // set unscaled + if useRem { + // Int division + _, intr := z.UnscaledBig().QuoRem(ix, iy, new(big.Int)) + // set remainder + remNum.Set(intr) + remDen.Set(iy2) + } else { + z.UnscaledBig().Quo(ix, iy) + } + return z, remNum, remDen +} + +type sclr struct{ s Scale } + +func (s sclr) Scale(x, y *Dec) Scale { + return s.s +} + +type scaleQuoExact struct{} + +func (sqe scaleQuoExact) Scale(x, y *Dec) Scale { + rem := new(big.Rat).SetFrac(x.UnscaledBig(), y.UnscaledBig()) + f2, f5 := factor2(rem.Denom()), factor(rem.Denom(), bigInt[5]) + var f10 Scale + if f2 > f5 { + f10 = Scale(f2) + } else { + f10 = Scale(f5) + } + return x.Scale() - y.Scale() + f10 +} + +func factor(n *big.Int, p *big.Int) int { + // could be improved for large factors + d, f := n, 0 + for { + dd, dm := new(big.Int).DivMod(d, p, new(big.Int)) + if dm.Sign() == 0 { + f++ + d = dd + } else { + break + } + } + return f +} + +func factor2(n *big.Int) int { + // could be improved for large factors + f := 0 + for ; n.Bit(f) == 0; f++ { + } + return f +} + +func upscale(a, b *Dec) (*Dec, *Dec) { + if a.Scale() == b.Scale() { + return a, b + } + if a.Scale() > b.Scale() { + bb := b.rescale(a.Scale()) + return a, bb + } + aa := a.rescale(b.Scale()) + return aa, b +} + +func exp10(x Scale) *big.Int { + if int(x) < len(exp10cache) { + return &exp10cache[int(x)] + } + return new(big.Int).Exp(bigInt[10], big.NewInt(int64(x)), nil) +} + +func (x *Dec) rescale(newScale Scale) *Dec { + shift := newScale - x.Scale() + switch { + case shift < 0: + e := exp10(-shift) + return NewDecBig(new(big.Int).Quo(x.UnscaledBig(), e), newScale) + case shift > 0: + e := exp10(shift) + return NewDecBig(new(big.Int).Mul(x.UnscaledBig(), e), newScale) + } + return x +} + +var zeros = []byte("00000000000000000000000000000000" + + "00000000000000000000000000000000") +var lzeros = Scale(len(zeros)) + +func appendZeros(s []byte, n Scale) []byte { + for i := Scale(0); i < n; i += lzeros { + if n > i+lzeros { + s = append(s, zeros...) + } else { + s = append(s, zeros[0:n-i]...) + } + } + return s +} + +func (x *Dec) String() string { + if x == nil { + return "" + } + scale := x.Scale() + s := []byte(x.UnscaledBig().String()) + if scale <= 0 { + if scale != 0 && x.unscaled.Sign() != 0 { + s = appendZeros(s, -scale) + } + return string(s) + } + negbit := Scale(-((x.Sign() - 1) / 2)) + // scale > 0 + lens := Scale(len(s)) + if lens-negbit <= scale { + ss := make([]byte, 0, scale+2) + if negbit == 1 { + ss = append(ss, '-') + } + ss = append(ss, '0', '.') + ss = appendZeros(ss, scale-lens+negbit) + ss = append(ss, s[negbit:]...) + return string(ss) + } + // lens > scale + ss := make([]byte, 0, lens+1) + ss = append(ss, s[:lens-scale]...) + ss = append(ss, '.') + ss = append(ss, s[lens-scale:]...) + return string(ss) +} + +// Format is a support routine for fmt.Formatter. It accepts the decimal +// formats 'd' and 'f', and handles both equivalently. +// Width, precision, flags and bases 2, 8, 16 are not supported. +func (x *Dec) Format(s fmt.State, ch rune) { + if ch != 'd' && ch != 'f' && ch != 'v' && ch != 's' { + fmt.Fprintf(s, "%%!%c(dec.Dec=%s)", ch, x.String()) + return + } + fmt.Fprintf(s, x.String()) +} + +func (z *Dec) scan(r io.RuneScanner) (*Dec, error) { + unscaled := make([]byte, 0, 256) // collects chars of unscaled as bytes + dp, dg := -1, -1 // indexes of decimal point, first digit +loop: + for { + ch, _, err := r.ReadRune() + if err == io.EOF { + break loop + } + if err != nil { + return nil, err + } + switch { + case ch == '+' || ch == '-': + if len(unscaled) > 0 || dp >= 0 { // must be first character + r.UnreadRune() + break loop + } + case ch == '.': + if dp >= 0 { + r.UnreadRune() + break loop + } + dp = len(unscaled) + continue // don't add to unscaled + case ch >= '0' && ch <= '9': + if dg == -1 { + dg = len(unscaled) + } + default: + r.UnreadRune() + break loop + } + unscaled = append(unscaled, byte(ch)) + } + if dg == -1 { + return nil, fmt.Errorf("no digits read") + } + if dp >= 0 { + z.SetScale(Scale(len(unscaled) - dp)) + } else { + z.SetScale(0) + } + _, ok := z.UnscaledBig().SetString(string(unscaled), 10) + if !ok { + return nil, fmt.Errorf("invalid decimal: %s", string(unscaled)) + } + return z, nil +} + +// SetString sets z to the value of s, interpreted as a decimal (base 10), +// and returns z and a boolean indicating success. The scale of z is the +// number of digits after the decimal point (including any trailing 0s), +// or 0 if there is no decimal point. If SetString fails, the value of z +// is undefined but the returned value is nil. +func (z *Dec) SetString(s string) (*Dec, bool) { + r := strings.NewReader(s) + _, err := z.scan(r) + if err != nil { + return nil, false + } + _, _, err = r.ReadRune() + if err != io.EOF { + return nil, false + } + // err == io.EOF => scan consumed all of s + return z, true +} + +// Scan is a support routine for fmt.Scanner; it sets z to the value of +// the scanned number. It accepts the decimal formats 'd' and 'f', and +// handles both equivalently. Bases 2, 8, 16 are not supported. +// The scale of z is the number of digits after the decimal point +// (including any trailing 0s), or 0 if there is no decimal point. +func (z *Dec) Scan(s fmt.ScanState, ch rune) error { + if ch != 'd' && ch != 'f' && ch != 's' && ch != 'v' { + return fmt.Errorf("Dec.Scan: invalid verb '%c'", ch) + } + s.SkipSpace() + _, err := z.scan(s) + return err +} + +// Gob encoding version +const decGobVersion byte = 1 + +func scaleBytes(s Scale) []byte { + buf := make([]byte, scaleSize) + i := scaleSize + for j := 0; j < scaleSize; j++ { + i-- + buf[i] = byte(s) + s >>= 8 + } + return buf +} + +func scale(b []byte) (s Scale) { + for j := 0; j < scaleSize; j++ { + s <<= 8 + s |= Scale(b[j]) + } + return +} + +// GobEncode implements the gob.GobEncoder interface. +func (x *Dec) GobEncode() ([]byte, error) { + buf, err := x.UnscaledBig().GobEncode() + if err != nil { + return nil, err + } + buf = append(append(buf, scaleBytes(x.Scale())...), decGobVersion) + return buf, nil +} + +// GobDecode implements the gob.GobDecoder interface. +func (z *Dec) GobDecode(buf []byte) error { + if len(buf) == 0 { + return fmt.Errorf("Dec.GobDecode: no data") + } + b := buf[len(buf)-1] + if b != decGobVersion { + return fmt.Errorf("Dec.GobDecode: encoding version %d not supported", b) + } + l := len(buf) - scaleSize - 1 + err := z.UnscaledBig().GobDecode(buf[:l]) + if err != nil { + return err + } + z.SetScale(scale(buf[l : l+scaleSize])) + return nil +} + +// MarshalText implements the encoding.TextMarshaler interface. +func (x *Dec) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +func (z *Dec) UnmarshalText(data []byte) error { + _, ok := z.SetString(string(data)) + if !ok { + return fmt.Errorf("invalid inf.Dec") + } + return nil +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go new file mode 100644 index 00000000..5df0f7b5 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go @@ -0,0 +1,33 @@ +// +build go1.2 + +package inf + +import ( + "encoding" + "encoding/json" + "testing" +) + +var _ encoding.TextMarshaler = new(Dec) +var _ encoding.TextUnmarshaler = new(Dec) + +type Obj struct { + Val *Dec +} + +func TestDecJsonMarshalUnmarshal(t *testing.T) { + o := Obj{Val: NewDec(123, 2)} + js, err := json.Marshal(o) + if err != nil { + t.Fatalf("json.Marshal(%v): got %v, want ok", o, err) + } + o2 := &Obj{} + err = json.Unmarshal(js, o2) + if err != nil { + t.Fatalf("json.Unmarshal(%#q): got %v, want ok", js, err) + } + if o.Val.Scale() != o2.Val.Scale() || + o.Val.UnscaledBig().Cmp(o2.Val.UnscaledBig()) != 0 { + t.Fatalf("json.Unmarshal(json.Marshal(%v)): want %v, got %v", o, o, o2) + } +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go new file mode 100644 index 00000000..d4fbe3e5 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go @@ -0,0 +1,40 @@ +package inf + +import ( + "math/big" + "testing" +) + +var decQuoRemZZZ = []struct { + z, x, y *Dec + r *big.Rat + srA, srB int +}{ + // basic examples + {NewDec(1, 0), NewDec(2, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(15, 1), NewDec(3, 0), NewDec(2, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(1, 1), NewDec(1, 0), NewDec(10, 0), big.NewRat(0, 1), 0, 1}, + {NewDec(0, 0), NewDec(2, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1}, + {NewDec(0, 0), NewDec(2, 0), NewDec(6, 0), big.NewRat(1, 3), 1, 1}, + {NewDec(1, 1), NewDec(2, 0), NewDec(12, 0), big.NewRat(2, 3), 1, 1}, + + // examples from the Go Language Specification + {NewDec(1, 0), NewDec(5, 0), NewDec(3, 0), big.NewRat(2, 3), 1, 1}, + {NewDec(-1, 0), NewDec(-5, 0), NewDec(3, 0), big.NewRat(-2, 3), -1, 1}, + {NewDec(-1, 0), NewDec(5, 0), NewDec(-3, 0), big.NewRat(-2, 3), 1, -1}, + {NewDec(1, 0), NewDec(-5, 0), NewDec(-3, 0), big.NewRat(2, 3), -1, -1}, +} + +func TestDecQuoRem(t *testing.T) { + for i, a := range decQuoRemZZZ { + z, rA, rB := new(Dec), new(big.Int), new(big.Int) + s := scaleQuoExact{}.Scale(a.x, a.y) + z.quoRem(a.x, a.y, s, true, rA, rB) + if a.z.Cmp(z) != 0 || a.r.Cmp(new(big.Rat).SetFrac(rA, rB)) != 0 { + t.Errorf("#%d QuoRemZZZ got %v, %v, %v; expected %v, %v", i, z, rA, rB, a.z, a.r) + } + if a.srA != rA.Sign() || a.srB != rB.Sign() { + t.Errorf("#%d QuoRemZZZ wrong signs, got %v, %v; expected %v, %v", i, rA.Sign(), rB.Sign(), a.srA, a.srB) + } + } +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go new file mode 100644 index 00000000..01ac7710 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go @@ -0,0 +1,379 @@ +package inf_test + +import ( + "bytes" + "encoding/gob" + "fmt" + "math/big" + "strings" + "testing" + + "speter.net/go/exp/math/dec/inf" +) + +type decFunZZ func(z, x, y *inf.Dec) *inf.Dec +type decArgZZ struct { + z, x, y *inf.Dec +} + +var decSumZZ = []decArgZZ{ + {inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1111111110, 0), inf.NewDec(123456789, 0), inf.NewDec(987654321, 0)}, + {inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(864197532, 0), inf.NewDec(-123456789, 0), inf.NewDec(987654321, 0)}, + {inf.NewDec(-1111111110, 0), inf.NewDec(-123456789, 0), inf.NewDec(-987654321, 0)}, + {inf.NewDec(12, 2), inf.NewDec(1, 1), inf.NewDec(2, 2)}, +} + +var decProdZZ = []decArgZZ{ + {inf.NewDec(0, 0), inf.NewDec(0, 0), inf.NewDec(0, 0)}, + {inf.NewDec(0, 0), inf.NewDec(1, 0), inf.NewDec(0, 0)}, + {inf.NewDec(1, 0), inf.NewDec(1, 0), inf.NewDec(1, 0)}, + {inf.NewDec(-991*991, 0), inf.NewDec(991, 0), inf.NewDec(-991, 0)}, + {inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)}, + {inf.NewDec(2, -3), inf.NewDec(1, -1), inf.NewDec(2, -2)}, + {inf.NewDec(2, 3), inf.NewDec(1, 1), inf.NewDec(2, 2)}, +} + +func TestDecSignZ(t *testing.T) { + var zero inf.Dec + for _, a := range decSumZZ { + s := a.z.Sign() + e := a.z.Cmp(&zero) + if s != e { + t.Errorf("got %d; want %d for z = %v", s, e, a.z) + } + } +} + +func TestDecAbsZ(t *testing.T) { + var zero inf.Dec + for _, a := range decSumZZ { + var z inf.Dec + z.Abs(a.z) + var e inf.Dec + e.Set(a.z) + if e.Cmp(&zero) < 0 { + e.Sub(&zero, &e) + } + if z.Cmp(&e) != 0 { + t.Errorf("got z = %v; want %v", z, e) + } + } +} + +func testDecFunZZ(t *testing.T, msg string, f decFunZZ, a decArgZZ) { + var z inf.Dec + f(&z, a.x, a.y) + if (&z).Cmp(a.z) != 0 { + t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z) + } +} + +func TestDecSumZZ(t *testing.T) { + AddZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Add(x, y) } + SubZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Sub(x, y) } + for _, a := range decSumZZ { + arg := a + testDecFunZZ(t, "AddZZ", AddZZ, arg) + + arg = decArgZZ{a.z, a.y, a.x} + testDecFunZZ(t, "AddZZ symmetric", AddZZ, arg) + + arg = decArgZZ{a.x, a.z, a.y} + testDecFunZZ(t, "SubZZ", SubZZ, arg) + + arg = decArgZZ{a.y, a.z, a.x} + testDecFunZZ(t, "SubZZ symmetric", SubZZ, arg) + } +} + +func TestDecProdZZ(t *testing.T) { + MulZZ := func(z, x, y *inf.Dec) *inf.Dec { return z.Mul(x, y) } + for _, a := range decProdZZ { + arg := a + testDecFunZZ(t, "MulZZ", MulZZ, arg) + + arg = decArgZZ{a.z, a.y, a.x} + testDecFunZZ(t, "MulZZ symmetric", MulZZ, arg) + } +} + +var decUnscaledTests = []struct { + d *inf.Dec + u int64 // ignored when ok == false + ok bool +}{ + {new(inf.Dec), 0, true}, + {inf.NewDec(-1<<63, 0), -1 << 63, true}, + {inf.NewDec(-(-1<<63 + 1), 0), -(-1<<63 + 1), true}, + {new(inf.Dec).Neg(inf.NewDec(-1<<63, 0)), 0, false}, + {new(inf.Dec).Sub(inf.NewDec(-1<<63, 0), inf.NewDec(1, 0)), 0, false}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), 0, false}, +} + +func TestDecUnscaled(t *testing.T) { + for i, tt := range decUnscaledTests { + u, ok := tt.d.Unscaled() + if ok != tt.ok { + t.Errorf("#%d Unscaled: got %v, expected %v", i, ok, tt.ok) + } else if ok && u != tt.u { + t.Errorf("#%d Unscaled: got %v, expected %v", i, u, tt.u) + } + } +} + +var decRoundTests = [...]struct { + in *inf.Dec + s inf.Scale + r inf.Rounder + exp *inf.Dec +}{ + {inf.NewDec(123424999999999993, 15), 2, inf.RoundHalfUp, inf.NewDec(12342, 2)}, + {inf.NewDec(123425000000000001, 15), 2, inf.RoundHalfUp, inf.NewDec(12343, 2)}, + {inf.NewDec(123424999999999993, 15), 15, inf.RoundHalfUp, inf.NewDec(123424999999999993, 15)}, + {inf.NewDec(123424999999999993, 15), 16, inf.RoundHalfUp, inf.NewDec(1234249999999999930, 16)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -1, inf.RoundHalfUp, inf.NewDec(1844674407370955162, -1)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -2, inf.RoundHalfUp, inf.NewDec(184467440737095516, -2)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -3, inf.RoundHalfUp, inf.NewDec(18446744073709552, -3)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -4, inf.RoundHalfUp, inf.NewDec(1844674407370955, -4)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -5, inf.RoundHalfUp, inf.NewDec(184467440737096, -5)}, + {inf.NewDecBig(new(big.Int).Lsh(big.NewInt(1), 64), 0), -6, inf.RoundHalfUp, inf.NewDec(18446744073710, -6)}, +} + +func TestDecRound(t *testing.T) { + for i, tt := range decRoundTests { + z := new(inf.Dec).Round(tt.in, tt.s, tt.r) + if tt.exp.Cmp(z) != 0 { + t.Errorf("#%d Round got %v; expected %v", i, z, tt.exp) + } + } +} + +var decStringTests = []struct { + in string + out string + val int64 + scale inf.Scale // skip SetString if negative + ok bool + scanOk bool +}{ + {in: "", ok: false, scanOk: false}, + {in: "a", ok: false, scanOk: false}, + {in: "z", ok: false, scanOk: false}, + {in: "+", ok: false, scanOk: false}, + {in: "-", ok: false, scanOk: false}, + {in: "g", ok: false, scanOk: false}, + {in: ".", ok: false, scanOk: false}, + {in: ".-0", ok: false, scanOk: false}, + {in: ".+0", ok: false, scanOk: false}, + // Scannable but not SetStringable + {"0b", "ignored", 0, 0, false, true}, + {"0x", "ignored", 0, 0, false, true}, + {"0xg", "ignored", 0, 0, false, true}, + {"0.0g", "ignored", 0, 1, false, true}, + // examples from godoc for Dec + {"0", "0", 0, 0, true, true}, + {"0.00", "0.00", 0, 2, true, true}, + {"ignored", "0", 0, -2, true, false}, + {"1", "1", 1, 0, true, true}, + {"1.00", "1.00", 100, 2, true, true}, + {"10", "10", 10, 0, true, true}, + {"ignored", "10", 1, -1, true, false}, + // other tests + {"+0", "0", 0, 0, true, true}, + {"-0", "0", 0, 0, true, true}, + {"0.0", "0.0", 0, 1, true, true}, + {"0.1", "0.1", 1, 1, true, true}, + {"0.", "0", 0, 0, true, true}, + {"-10", "-10", -1, -1, true, true}, + {"-1", "-1", -1, 0, true, true}, + {"-0.1", "-0.1", -1, 1, true, true}, + {"-0.01", "-0.01", -1, 2, true, true}, + {"+0.", "0", 0, 0, true, true}, + {"-0.", "0", 0, 0, true, true}, + {".0", "0.0", 0, 1, true, true}, + {"+.0", "0.0", 0, 1, true, true}, + {"-.0", "0.0", 0, 1, true, true}, + {"0.0000000000", "0.0000000000", 0, 10, true, true}, + {"0.0000000001", "0.0000000001", 1, 10, true, true}, + {"-0.0000000000", "0.0000000000", 0, 10, true, true}, + {"-0.0000000001", "-0.0000000001", -1, 10, true, true}, + {"-10", "-10", -10, 0, true, true}, + {"+10", "10", 10, 0, true, true}, + {"00", "0", 0, 0, true, true}, + {"023", "23", 23, 0, true, true}, // decimal, not octal + {"-02.3", "-2.3", -23, 1, true, true}, // decimal, not octal +} + +func TestDecGetString(t *testing.T) { + z := new(inf.Dec) + for i, test := range decStringTests { + if !test.ok { + continue + } + z.SetUnscaled(test.val) + z.SetScale(test.scale) + + s := z.String() + if s != test.out { + t.Errorf("#%da got %s; want %s", i, s, test.out) + } + + s = fmt.Sprintf("%d", z) + if s != test.out { + t.Errorf("#%db got %s; want %s", i, s, test.out) + } + } +} + +func TestDecSetString(t *testing.T) { + tmp := new(inf.Dec) + for i, test := range decStringTests { + if test.scale < 0 { + // SetString only supports scale >= 0 + continue + } + // initialize to a non-zero value so that issues with parsing + // 0 are detected + tmp.Set(inf.NewDec(1234567890, 123)) + n1, ok1 := new(inf.Dec).SetString(test.in) + n2, ok2 := tmp.SetString(test.in) + expected := inf.NewDec(test.val, test.scale) + if ok1 != test.ok || ok2 != test.ok { + t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) + continue + } + if !ok1 { + if n1 != nil { + t.Errorf("#%d (input '%s') n1 != nil", i, test.in) + } + continue + } + if !ok2 { + if n2 != nil { + t.Errorf("#%d (input '%s') n2 != nil", i, test.in) + } + continue + } + + if n1.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) + } + if n2.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) + } + } +} + +func TestDecScan(t *testing.T) { + tmp := new(inf.Dec) + for i, test := range decStringTests { + if test.scale < 0 { + // SetString only supports scale >= 0 + continue + } + // initialize to a non-zero value so that issues with parsing + // 0 are detected + tmp.Set(inf.NewDec(1234567890, 123)) + n1, n2 := new(inf.Dec), tmp + nn1, err1 := fmt.Sscan(test.in, n1) + nn2, err2 := fmt.Sscan(test.in, n2) + if !test.scanOk { + if err1 == nil || err2 == nil { + t.Errorf("#%d (input '%s') ok incorrect, should be %t", i, test.in, test.scanOk) + } + continue + } + expected := inf.NewDec(test.val, test.scale) + if nn1 != 1 || err1 != nil || nn2 != 1 || err2 != nil { + t.Errorf("#%d (input '%s') error %d %v, %d %v", i, test.in, nn1, err1, nn2, err2) + continue + } + if n1.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) + } + if n2.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) + } + } +} + +var decScanNextTests = []struct { + in string + ok bool + next rune +}{ + {"", false, 0}, + {"a", false, 'a'}, + {"z", false, 'z'}, + {"+", false, 0}, + {"-", false, 0}, + {"g", false, 'g'}, + {".", false, 0}, + {".-0", false, '-'}, + {".+0", false, '+'}, + {"0b", true, 'b'}, + {"0x", true, 'x'}, + {"0xg", true, 'x'}, + {"0.0g", true, 'g'}, +} + +func TestDecScanNext(t *testing.T) { + for i, test := range decScanNextTests { + rdr := strings.NewReader(test.in) + n1 := new(inf.Dec) + nn1, _ := fmt.Fscan(rdr, n1) + if (test.ok && nn1 == 0) || (!test.ok && nn1 > 0) { + t.Errorf("#%d (input '%s') ok incorrect should be %t", i, test.in, test.ok) + continue + } + r := rune(0) + nn2, err := fmt.Fscanf(rdr, "%c", &r) + if test.next != r { + t.Errorf("#%d (input '%s') next incorrect, got %c should be %c, %d, %v", i, test.in, r, test.next, nn2, err) + } + } +} + +var decGobEncodingTests = []string{ + "0", + "1", + "2", + "10", + "42", + "1234567890", + "298472983472983471903246121093472394872319615612417471234712061", +} + +func TestDecGobEncoding(t *testing.T) { + var medium bytes.Buffer + enc := gob.NewEncoder(&medium) + dec := gob.NewDecoder(&medium) + for i, test := range decGobEncodingTests { + for j := 0; j < 2; j++ { + for k := inf.Scale(-5); k <= 5; k++ { + medium.Reset() // empty buffer for each test case (in case of failures) + stest := test + if j != 0 { + // negative numbers + stest = "-" + test + } + var tx inf.Dec + tx.SetString(stest) + tx.SetScale(k) // test with positive, negative, and zero scale + if err := enc.Encode(&tx); err != nil { + t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err) + } + var rx inf.Dec + if err := dec.Decode(&rx); err != nil { + t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err) + } + if rx.Cmp(&tx) != 0 { + t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx) + } + } + } + } +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/example_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/example_test.go new file mode 100644 index 00000000..52029e08 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/example_test.go @@ -0,0 +1,62 @@ +package inf_test + +import ( + "fmt" + "log" +) + +import "speter.net/go/exp/math/dec/inf" + +func ExampleDec_SetString() { + d := new(inf.Dec) + d.SetString("012345.67890") // decimal; leading 0 ignored; trailing 0 kept + fmt.Println(d) + // Output: 12345.67890 +} + +func ExampleDec_Scan() { + // The Scan function is rarely used directly; + // the fmt package recognizes it as an implementation of fmt.Scanner. + d := new(inf.Dec) + _, err := fmt.Sscan("184467440.73709551617", d) + if err != nil { + log.Println("error scanning value:", err) + } else { + fmt.Println(d) + } + // Output: 184467440.73709551617 +} + +func ExampleDec_QuoRound_scale2RoundDown() { + // 10 / 3 is an infinite decimal; it has no exact Dec representation + x, y := inf.NewDec(10, 0), inf.NewDec(3, 0) + // use 2 digits beyond the decimal point, round towards 0 + z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundDown) + fmt.Println(z) + // Output: 3.33 +} + +func ExampleDec_QuoRound_scale2RoundCeil() { + // -42 / 400 is an finite decimal with 3 digits beyond the decimal point + x, y := inf.NewDec(-42, 0), inf.NewDec(400, 0) + // use 2 digits beyond decimal point, round towards positive infinity + z := new(inf.Dec).QuoRound(x, y, 2, inf.RoundCeil) + fmt.Println(z) + // Output: -0.10 +} + +func ExampleDec_QuoExact_ok() { + // 1 / 25 is a finite decimal; it has exact Dec representation + x, y := inf.NewDec(1, 0), inf.NewDec(25, 0) + z := new(inf.Dec).QuoExact(x, y) + fmt.Println(z) + // Output: 0.04 +} + +func ExampleDec_QuoExact_fail() { + // 1 / 3 is an infinite decimal; it has no exact Dec representation + x, y := inf.NewDec(1, 0), inf.NewDec(3, 0) + z := new(inf.Dec).QuoExact(x, y) + fmt.Println(z) + // Output: +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go new file mode 100644 index 00000000..3a97ef52 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go @@ -0,0 +1,145 @@ +package inf + +import ( + "math/big" +) + +// Rounder represents a method for rounding the (possibly infinite decimal) +// result of a division to a finite Dec. It is used by Dec.Round() and +// Dec.Quo(). +// +// See the Example for results of using each Rounder with some sample values. +// +type Rounder rounder + +// See http://speleotrove.com/decimal/damodel.html#refround for more detailed +// definitions of these rounding modes. +var ( + RoundDown Rounder // towards 0 + RoundUp Rounder // away from 0 + RoundFloor Rounder // towards -infinity + RoundCeil Rounder // towards +infinity + RoundHalfDown Rounder // to nearest; towards 0 if same distance + RoundHalfUp Rounder // to nearest; away from 0 if same distance + RoundHalfEven Rounder // to nearest; even last digit if same distance +) + +// RoundExact is to be used in the case when rounding is not necessary. +// When used with Quo or Round, it returns the result verbatim when it can be +// expressed exactly with the given precision, and it returns nil otherwise. +// QuoExact is a shorthand for using Quo with RoundExact. +var RoundExact Rounder + +type rounder interface { + + // When UseRemainder() returns true, the Round() method is passed the + // remainder of the division, expressed as the numerator and denominator of + // a rational. + UseRemainder() bool + + // Round sets the rounded value of a quotient to z, and returns z. + // quo is rounded down (truncated towards zero) to the scale obtained from + // the Scaler in Quo(). + // + // When the remainder is not used, remNum and remDen are nil. + // When used, the remainder is normalized between -1 and 1; that is: + // + // -|remDen| < remNum < |remDen| + // + // remDen has the same sign as y, and remNum is zero or has the same sign + // as x. + Round(z, quo *Dec, remNum, remDen *big.Int) *Dec +} + +type rndr struct { + useRem bool + round func(z, quo *Dec, remNum, remDen *big.Int) *Dec +} + +func (r rndr) UseRemainder() bool { + return r.useRem +} + +func (r rndr) Round(z, quo *Dec, remNum, remDen *big.Int) *Dec { + return r.round(z, quo, remNum, remDen) +} + +var intSign = []*big.Int{big.NewInt(-1), big.NewInt(0), big.NewInt(1)} + +func roundHalf(f func(c int, odd uint) (roundUp bool)) func(z, q *Dec, rA, rB *big.Int) *Dec { + return func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + brA, brB := rA.BitLen(), rB.BitLen() + if brA < brB-1 { + // brA < brB-1 => |rA| < |rB/2| + return z + } + roundUp := false + srA, srB := rA.Sign(), rB.Sign() + s := srA * srB + if brA == brB-1 { + rA2 := new(big.Int).Lsh(rA, 1) + if s < 0 { + rA2.Neg(rA2) + } + roundUp = f(rA2.Cmp(rB)*srB, z.UnscaledBig().Bit(0)) + } else { + // brA > brB-1 => |rA| > |rB/2| + roundUp = true + } + if roundUp { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[s+1]) + } + return z + } +} + +func init() { + RoundExact = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + if rA.Sign() != 0 { + return nil + } + return z.Set(q) + }} + RoundDown = rndr{false, + func(z, q *Dec, rA, rB *big.Int) *Dec { + return z.Set(q) + }} + RoundUp = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign() != 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[rA.Sign()*rB.Sign()+1]) + } + return z + }} + RoundFloor = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign()*rB.Sign() < 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[0]) + } + return z + }} + RoundCeil = rndr{true, + func(z, q *Dec, rA, rB *big.Int) *Dec { + z.Set(q) + if rA.Sign()*rB.Sign() > 0 { + z.UnscaledBig().Add(z.UnscaledBig(), intSign[2]) + } + return z + }} + RoundHalfDown = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c > 0 + })} + RoundHalfUp = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c >= 0 + })} + RoundHalfEven = rndr{true, roundHalf( + func(c int, odd uint) bool { + return c > 0 || c == 0 && odd == 1 + })} +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_example_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_example_test.go new file mode 100644 index 00000000..5c5e4df9 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_example_test.go @@ -0,0 +1,72 @@ +package inf_test + +import ( + "fmt" + "os" + "text/tabwriter" + + "speter.net/go/exp/math/dec/inf" +) + +// This example displays the results of Dec.Round with each of the Rounders. +// +func ExampleRounder() { + var vals = []struct { + x string + s inf.Scale + }{ + {"-0.18", 1}, {"-0.15", 1}, {"-0.12", 1}, {"-0.10", 1}, + {"-0.08", 1}, {"-0.05", 1}, {"-0.02", 1}, {"0.00", 1}, + {"0.02", 1}, {"0.05", 1}, {"0.08", 1}, {"0.10", 1}, + {"0.12", 1}, {"0.15", 1}, {"0.18", 1}, + } + + var rounders = []struct { + name string + rounder inf.Rounder + }{ + {"RoundDown", inf.RoundDown}, {"RoundUp", inf.RoundUp}, + {"RoundCeil", inf.RoundCeil}, {"RoundFloor", inf.RoundFloor}, + {"RoundHalfDown", inf.RoundHalfDown}, {"RoundHalfUp", inf.RoundHalfUp}, + {"RoundHalfEven", inf.RoundHalfEven}, {"RoundExact", inf.RoundExact}, + } + + fmt.Println("The results of new(inf.Dec).Round(x, s, inf.RoundXXX):\n") + w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight) + fmt.Fprint(w, "x\ts\t|\t") + for _, r := range rounders { + fmt.Fprintf(w, "%s\t", r.name[5:]) + } + fmt.Fprintln(w) + for _, v := range vals { + fmt.Fprintf(w, "%s\t%d\t|\t", v.x, v.s) + for _, r := range rounders { + x, _ := new(inf.Dec).SetString(v.x) + z := new(inf.Dec).Round(x, v.s, r.rounder) + fmt.Fprintf(w, "%d\t", z) + } + fmt.Fprintln(w) + } + w.Flush() + + // Output: + // The results of new(inf.Dec).Round(x, s, inf.RoundXXX): + // + // x s | Down Up Ceil Floor HalfDown HalfUp HalfEven Exact + // -0.18 1 | -0.1 -0.2 -0.1 -0.2 -0.2 -0.2 -0.2 + // -0.15 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.2 -0.2 + // -0.12 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.1 -0.1 + // -0.10 1 | -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 -0.1 + // -0.08 1 | 0.0 -0.1 0.0 -0.1 -0.1 -0.1 -0.1 + // -0.05 1 | 0.0 -0.1 0.0 -0.1 0.0 -0.1 0.0 + // -0.02 1 | 0.0 -0.1 0.0 -0.1 0.0 0.0 0.0 + // 0.00 1 | 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 + // 0.02 1 | 0.0 0.1 0.1 0.0 0.0 0.0 0.0 + // 0.05 1 | 0.0 0.1 0.1 0.0 0.0 0.1 0.0 + // 0.08 1 | 0.0 0.1 0.1 0.0 0.1 0.1 0.1 + // 0.10 1 | 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 + // 0.12 1 | 0.1 0.2 0.2 0.1 0.1 0.1 0.1 + // 0.15 1 | 0.1 0.2 0.2 0.1 0.1 0.2 0.2 + // 0.18 1 | 0.1 0.2 0.2 0.1 0.2 0.2 0.2 + +} diff --git a/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go new file mode 100644 index 00000000..757ab975 --- /dev/null +++ b/apiserver/Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go @@ -0,0 +1,109 @@ +package inf_test + +import ( + "math/big" + "testing" + + "speter.net/go/exp/math/dec/inf" +) + +var decRounderInputs = [...]struct { + quo *inf.Dec + rA, rB *big.Int +}{ + // examples from go language spec + {inf.NewDec(1, 0), big.NewInt(2), big.NewInt(3)}, // 5 / 3 + {inf.NewDec(-1, 0), big.NewInt(-2), big.NewInt(3)}, // -5 / 3 + {inf.NewDec(-1, 0), big.NewInt(2), big.NewInt(-3)}, // 5 / -3 + {inf.NewDec(1, 0), big.NewInt(-2), big.NewInt(-3)}, // -5 / -3 + // examples from godoc + {inf.NewDec(-1, 1), big.NewInt(-8), big.NewInt(10)}, + {inf.NewDec(-1, 1), big.NewInt(-5), big.NewInt(10)}, + {inf.NewDec(-1, 1), big.NewInt(-2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-8), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-5), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(-2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(0), big.NewInt(1)}, + {inf.NewDec(0, 1), big.NewInt(2), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(5), big.NewInt(10)}, + {inf.NewDec(0, 1), big.NewInt(8), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(2), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(5), big.NewInt(10)}, + {inf.NewDec(1, 1), big.NewInt(8), big.NewInt(10)}, +} + +var decRounderResults = [...]struct { + rounder inf.Rounder + results [len(decRounderInputs)]*inf.Dec +}{ + {inf.RoundExact, [...]*inf.Dec{nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, + inf.NewDec(0, 1), nil, nil, nil, nil, nil, nil}}, + {inf.RoundDown, [...]*inf.Dec{ + inf.NewDec(1, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(1, 0), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}}, + {inf.RoundUp, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfDown, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfUp, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundHalfEven, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(2, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-1, 1), + inf.NewDec(-1, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(1, 1), + inf.NewDec(1, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, + {inf.RoundFloor, [...]*inf.Dec{ + inf.NewDec(1, 0), inf.NewDec(-2, 0), inf.NewDec(-2, 0), inf.NewDec(1, 0), + inf.NewDec(-2, 1), inf.NewDec(-2, 1), inf.NewDec(-2, 1), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1)}}, + {inf.RoundCeil, [...]*inf.Dec{ + inf.NewDec(2, 0), inf.NewDec(-1, 0), inf.NewDec(-1, 0), inf.NewDec(2, 0), + inf.NewDec(-1, 1), inf.NewDec(-1, 1), inf.NewDec(-1, 1), + inf.NewDec(0, 1), inf.NewDec(0, 1), inf.NewDec(0, 1), + inf.NewDec(0, 1), + inf.NewDec(1, 1), inf.NewDec(1, 1), inf.NewDec(1, 1), + inf.NewDec(2, 1), inf.NewDec(2, 1), inf.NewDec(2, 1)}}, +} + +func TestDecRounders(t *testing.T) { + for i, a := range decRounderResults { + for j, input := range decRounderInputs { + q := new(inf.Dec).Set(input.quo) + rA, rB := new(big.Int).Set(input.rA), new(big.Int).Set(input.rB) + res := a.rounder.Round(new(inf.Dec), q, rA, rB) + if a.results[j] == nil && res == nil { + continue + } + if (a.results[j] == nil && res != nil) || + (a.results[j] != nil && res == nil) || + a.results[j].Cmp(res) != 0 { + t.Errorf("#%d,%d Rounder got %v; expected %v", i, j, res, a.results[j]) + } + } + } +}