Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
ded3ef28
Commit
ded3ef28
authored
Jan 06, 2015
by
Tim Hockin
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1185 from lavalamp/numeric
Numeric type for resources
parents
f11f0de4
cd58e49c
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
2820 additions
and
0 deletions
+2820
-0
Godeps.json
Godeps/Godeps.json
+4
-0
LICENSE
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE
+57
-0
benchmark_test.go
...pace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go
+210
-0
dec.go
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go
+615
-0
dec_go1_2_test.go
...pace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go
+33
-0
dec_internal_test.go
...e/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go
+40
-0
dec_test.go
..._workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go
+379
-0
example_test.go
...kspace/src/speter.net/go/exp/math/dec/inf/example_test.go
+62
-0
rounder.go
.../_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go
+145
-0
rounder_example_test.go
...rc/speter.net/go/exp/math/dec/inf/rounder_example_test.go
+72
-0
rounder_test.go
...kspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go
+109
-0
quantity.go
pkg/api/resource/quantity.go
+412
-0
quantity_example_test.go
pkg/api/resource/quantity_example_test.go
+59
-0
quantity_test.go
pkg/api/resource/quantity_test.go
+489
-0
suffix.go
pkg/api/resource/suffix.go
+134
-0
No files found.
Godeps/Godeps.json
View file @
ded3ef28
...
@@ -203,6 +203,10 @@
...
@@ -203,6 +203,10 @@
{
{
"ImportPath"
:
"gopkg.in/v2/yaml"
,
"ImportPath"
:
"gopkg.in/v2/yaml"
,
"Rev"
:
"d466437aa4adc35830964cffc5b5f262c63ddcb4"
"Rev"
:
"d466437aa4adc35830964cffc5b5f262c63ddcb4"
},
{
"ImportPath"
:
"speter.net/go/exp/math/dec/inf"
,
"Rev"
:
"42ca6cd68aa922bc3f32f1e056e61b65945d9ad7"
}
}
]
]
}
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/LICENSE
0 → 100644
View file @
ded3ef28
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.
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/benchmark_test.go
0 → 100644
View file @
ded3ef28
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
))
})
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec.go
0 → 100644
View file @
ded3ef28
// 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
"<nil>"
}
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
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_go1_2_test.go
0 → 100644
View file @
ded3ef28
// +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
)
}
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_internal_test.go
0 → 100644
View file @
ded3ef28
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
)
}
}
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/dec_test.go
0 → 100644
View file @
ded3ef28
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\t
got 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
)
}
}
}
}
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/example_test.go
0 → 100644
View file @
ded3ef28
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: <nil>
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder.go
0 → 100644
View file @
ded3ef28
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
})}
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_example_test.go
0 → 100644
View file @
ded3ef28
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
\t
s
\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 <nil>
// -0.15 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.2 -0.2 <nil>
// -0.12 1 | -0.1 -0.2 -0.1 -0.2 -0.1 -0.1 -0.1 <nil>
// -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 <nil>
// -0.05 1 | 0.0 -0.1 0.0 -0.1 0.0 -0.1 0.0 <nil>
// -0.02 1 | 0.0 -0.1 0.0 -0.1 0.0 0.0 0.0 <nil>
// 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 <nil>
// 0.05 1 | 0.0 0.1 0.1 0.0 0.0 0.1 0.0 <nil>
// 0.08 1 | 0.0 0.1 0.1 0.0 0.1 0.1 0.1 <nil>
// 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 <nil>
// 0.15 1 | 0.1 0.2 0.2 0.1 0.1 0.2 0.2 <nil>
// 0.18 1 | 0.1 0.2 0.2 0.1 0.2 0.2 0.2 <nil>
}
Godeps/_workspace/src/speter.net/go/exp/math/dec/inf/rounder_test.go
0 → 100644
View file @
ded3ef28
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
])
}
}
}
}
pkg/api/resource/quantity.go
0 → 100644
View file @
ded3ef28
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
resource
import
(
"errors"
"flag"
"fmt"
"math/big"
"regexp"
"strings"
"speter.net/go/exp/math/dec/inf"
)
// Quantity is a fixed-point representation of a number.
// It provides convenient marshaling/unmarshaling in JSON and YAML,
// in addition to String() and Int64() accessors.
//
// The serialization format is:
//
// <quantity> ::= <signedNumber><suffix>
// (Note that <suffix> may be empty, from the "" case in <decimalSI>.)
// <digit> ::= 0 | 1 | ... | 9
// <digits> ::= <digit> | <digit><digits>
// <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits>
// <sign> ::= "+" | "-"
// <signedNumber> ::= <number> | <sign><number>
// <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI>
// <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei
// (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html)
// <decimalSI> ::= m | "" | k | M | G | T | P | E
// (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.)
// <decimalExponent> ::= "e" <signedNumber> | "E" <signedNumber>
//
// No matter which of the three exponent forms is used, no quantity may represent
// a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal
// places. Numbers larger or more precise will be capped or rounded up.
// (E.g.: 0.1m will rounded up to 1m.)
// This may be extended in the future if we require larger or smaller quantities.
//
// When a Quantity is parsed from a string, it will remember the type of suffix
// it had, and will use the same type again when it is serialized.
//
// Before serializing, Quantity will be put in "canonical form".
// This means that Exponent/suffix will be adjusted up or down (with a
// corresponding increase or decrease in Mantissa) such that:
// a. No precision is lost
// b. No fractional digits will be emitted
// c. The exponent (or suffix) is as large as possible.
// The sign will be omitted unless the number is negative.
//
// Examples:
// 1.5 will be serialized as "1500m"
// 1.5Gi will be serialized as "1536Mi"
//
// NOTE: We reserve the right to amend this canonical format, perhaps to
// allow 1.5 to be canonical.
// TODO: Remove above disclaimer after all bikeshedding about format is over,
// or after March 2015.
//
// Note that the quantity will NEVER be internally represented by a
// floating point number. That is the whole point of this exercise.
//
// Non-canonical values will still parse as long as they are well formed,
// but will be re-emitted in their canonical form. (So always use canonical
// form, or don't diff.)
//
// This format is intended to make it difficult to use these numbers without
// writing some sort of special handling code in the hopes that that will
// cause implementors to also use a fixed point implementation.
type
Quantity
struct
{
// Amount is public, so you can manipulate it if the accessor
// functions are not sufficient.
Amount
*
inf
.
Dec
// Change Format at will. See the comment for Canonicalize for
// more details.
Format
}
// Format lists the three possible formattings of a quantity.
type
Format
string
const
(
DecimalExponent
=
Format
(
"DecimalExponent"
)
// e.g., 12e6
BinarySI
=
Format
(
"BinarySI"
)
// e.g., 12Mi (12 * 2^20)
DecimalSI
=
Format
(
"DecimalSI"
)
// e.g., 12M (12 * 10^6)
)
// ParseOrDie turns the given string into a quantity or panics; for tests
// or others cases where you know the string is valid.
func
ParseOrDie
(
str
string
)
*
Quantity
{
q
,
err
:=
ParseQuantity
(
str
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"cannot parse '%v': %v"
,
str
,
err
))
}
return
q
}
const
(
// splitREString is used to separate a number from its suffix; as such,
// this is overly permissive, but that's OK-- it will be checked later.
splitREString
=
"^([+-]?[0-9.]+)([eEimkKMGTP]*[-+]?[0-9]*)$"
)
var
(
// splitRE is used to get the various parts of a number.
splitRE
=
regexp
.
MustCompile
(
splitREString
)
// Errors that could happen while parsing a string.
ErrFormatWrong
=
errors
.
New
(
"quantities must match the regular expression '"
+
splitREString
+
"'"
)
ErrNumeric
=
errors
.
New
(
"unable to parse numeric part of quantity"
)
ErrSuffix
=
errors
.
New
(
"unable to parse quantity's suffix"
)
// Commonly needed big.Int values-- treat as read only!
bigTen
=
big
.
NewInt
(
10
)
bigZero
=
big
.
NewInt
(
0
)
bigOne
=
big
.
NewInt
(
1
)
bigThousand
=
big
.
NewInt
(
1000
)
big1024
=
big
.
NewInt
(
1024
)
// Commonly needed inf.Dec values-- treat as read only!
decZero
=
inf
.
NewDec
(
0
,
0
)
decOne
=
inf
.
NewDec
(
1
,
0
)
decMinusOne
=
inf
.
NewDec
(
-
1
,
0
)
decThousand
=
inf
.
NewDec
(
1000
,
0
)
dec1024
=
inf
.
NewDec
(
1024
,
0
)
decMinus1024
=
inf
.
NewDec
(
-
1024
,
0
)
// Largest (in magnitude) number allowed.
maxAllowed
=
inf
.
NewDec
((
1
<<
63
)
-
1
,
0
)
// == max int64
// The maximum value we can represent milli-units for.
// Compare with the return value of Quantity.Value() to
// see if it's safe to use Quantity.MilliValue().
MaxMilliValue
=
((
1
<<
63
)
-
1
)
/
1000
)
// ParseQuantity turns str into a Quantity, or returns an error.
func
ParseQuantity
(
str
string
)
(
*
Quantity
,
error
)
{
parts
:=
splitRE
.
FindStringSubmatch
(
strings
.
TrimSpace
(
str
))
// regexp returns are entire match, followed by an entry for each () section.
if
len
(
parts
)
!=
3
{
return
nil
,
ErrFormatWrong
}
amount
:=
new
(
inf
.
Dec
)
if
_
,
ok
:=
amount
.
SetString
(
parts
[
1
]);
!
ok
{
return
nil
,
ErrNumeric
}
base
,
exponent
,
format
,
ok
:=
quantitySuffixer
.
interpret
(
suffix
(
parts
[
2
]))
if
!
ok
{
return
nil
,
ErrSuffix
}
// So that no bigOne but us has to think about suffixes, remove it.
if
base
==
10
{
amount
.
SetScale
(
amount
.
Scale
()
+
inf
.
Scale
(
-
exponent
))
}
else
if
base
==
2
{
// numericSuffix = 2 ** exponent
numericSuffix
:=
big
.
NewInt
(
1
)
.
Lsh
(
bigOne
,
uint
(
exponent
))
ub
:=
amount
.
UnscaledBig
()
amount
.
SetUnscaledBig
(
ub
.
Mul
(
ub
,
numericSuffix
))
}
// Cap at min/max bounds.
sign
:=
amount
.
Sign
()
if
sign
==
-
1
{
amount
.
Neg
(
amount
)
}
// This rounds non-bigZero values up to the minimum representable
// value, under the theory that if you want some resources, you
// should get some resources, even if you asked for way too small
// of an amount.
// Arguably, this should be inf.RoundHalfUp (normal rounding), but
// that would have the side effect of rounding values < .5m to bigZero.
amount
.
Round
(
amount
,
3
,
inf
.
RoundUp
)
// The max is just a simple cap.
if
amount
.
Cmp
(
maxAllowed
)
>
0
{
amount
.
Set
(
maxAllowed
)
}
if
format
==
BinarySI
&&
amount
.
Cmp
(
decOne
)
<
0
&&
amount
.
Cmp
(
decZero
)
>
0
{
// This avoids rounding and hopefully confusion, too.
format
=
DecimalSI
}
if
sign
==
-
1
{
amount
.
Neg
(
amount
)
}
return
&
Quantity
{
amount
,
format
},
nil
}
// removeFactors divides in a loop; the return values have the property that
// d == result * factor ^ times
// d may be modified in place.
// If d == 0, then the return values will be (0, 0)
func
removeFactors
(
d
,
factor
*
big
.
Int
)
(
result
*
big
.
Int
,
times
int
)
{
q
:=
big
.
NewInt
(
0
)
m
:=
big
.
NewInt
(
0
)
for
d
.
Cmp
(
bigZero
)
!=
0
{
q
.
DivMod
(
d
,
factor
,
m
)
if
m
.
Cmp
(
bigZero
)
!=
0
{
break
}
times
++
d
,
q
=
q
,
d
}
return
d
,
times
}
// Canonicalize returns the canonical form of q and its suffix (see comment on Quantity).
//
// Note about BinarySI:
// * If q.Format is set to BinarySI and q.Amount represents a non-bigZero value between
// -1 and +1, it will be emitted as if q.Format were DecimalSI.
// * Otherwise, if q.Format is set to BinarySI, frational parts of q.Amount will be
// rounded up. (1.1i becomes 2i.)
func
(
q
*
Quantity
)
Canonicalize
()
(
string
,
suffix
)
{
if
q
.
Amount
==
nil
{
return
"0"
,
""
}
format
:=
q
.
Format
switch
format
{
case
DecimalExponent
,
DecimalSI
:
case
BinarySI
:
if
q
.
Amount
.
Cmp
(
decMinus1024
)
>
0
&&
q
.
Amount
.
Cmp
(
dec1024
)
<
0
{
// This avoids rounding and hopefully confusion, too.
format
=
DecimalSI
}
else
{
tmp
:=
&
inf
.
Dec
{}
tmp
.
Round
(
q
.
Amount
,
0
,
inf
.
RoundUp
)
if
tmp
.
Cmp
(
q
.
Amount
)
!=
0
{
// Don't lose precision-- show as DecimalSI
format
=
DecimalSI
}
}
default
:
format
=
DecimalExponent
}
// TODO: If BinarySI formatting is requested but would cause rounding, upgrade to
// bigOne of the other formats.
switch
format
{
case
DecimalExponent
,
DecimalSI
:
mantissa
:=
q
.
Amount
.
UnscaledBig
()
exponent
:=
int
(
-
q
.
Amount
.
Scale
())
amount
:=
big
.
NewInt
(
0
)
.
Set
(
mantissa
)
// move all factors of 10 into the exponent for easy reasoning
amount
,
times
:=
removeFactors
(
amount
,
bigTen
)
exponent
+=
times
// make sure exponent is a multiple of 3
for
exponent
%
3
!=
0
{
amount
.
Mul
(
amount
,
bigTen
)
exponent
--
}
suffix
,
_
:=
quantitySuffixer
.
construct
(
10
,
exponent
,
format
)
number
:=
amount
.
String
()
return
number
,
suffix
case
BinarySI
:
tmp
:=
&
inf
.
Dec
{}
tmp
.
Round
(
q
.
Amount
,
0
,
inf
.
RoundUp
)
amount
,
exponent
:=
removeFactors
(
tmp
.
UnscaledBig
(),
big1024
)
suffix
,
_
:=
quantitySuffixer
.
construct
(
2
,
exponent
*
10
,
format
)
number
:=
amount
.
String
()
return
number
,
suffix
}
return
"0"
,
""
}
// String formats the Quantity as a string.
func
(
q
*
Quantity
)
String
()
string
{
number
,
suffix
:=
q
.
Canonicalize
()
return
number
+
string
(
suffix
)
}
// MarshalJSON implements the json.Marshaller interface.
func
(
q
Quantity
)
MarshalJSON
()
([]
byte
,
error
)
{
return
[]
byte
(
`"`
+
q
.
String
()
+
`"`
),
nil
}
// UnmarshalJSON implements the json.Unmarshaller interface.
func
(
q
*
Quantity
)
UnmarshalJSON
(
value
[]
byte
)
error
{
str
:=
string
(
value
)
parsed
,
err
:=
ParseQuantity
(
strings
.
Trim
(
str
,
`"`
))
if
err
!=
nil
{
return
err
}
// This copy is safe because parsed will not be referred to again.
*
q
=
*
parsed
return
nil
}
// NewQuantity returns a new Quantity representing the given
// value in the given format.
func
NewQuantity
(
value
int64
,
format
Format
)
*
Quantity
{
return
&
Quantity
{
Amount
:
inf
.
NewDec
(
value
,
0
),
Format
:
format
,
}
}
// NewMilliQuantity returns a new Quantity representing the given
// value * 1/1000 in the given format. Note that BinarySI formatting
// will round fractional values, and will be changed to DecimalSI for
// values x where (-1 < x < 1) && (x != 0).
func
NewMilliQuantity
(
value
int64
,
format
Format
)
*
Quantity
{
return
&
Quantity
{
Amount
:
inf
.
NewDec
(
value
,
3
),
Format
:
format
,
}
}
// Value returns the value of q; any fractional part will be lost.
func
(
q
*
Quantity
)
Value
()
int64
{
if
q
.
Amount
==
nil
{
return
0
}
tmp
:=
&
inf
.
Dec
{}
return
tmp
.
Round
(
q
.
Amount
,
0
,
inf
.
RoundUp
)
.
UnscaledBig
()
.
Int64
()
}
// MilliValue returns the value of q * 1000; this could overflow an int64;
// if that's a concern, call Value() first to verify the number is small enough.
func
(
q
*
Quantity
)
MilliValue
()
int64
{
if
q
.
Amount
==
nil
{
return
0
}
tmp
:=
&
inf
.
Dec
{}
return
tmp
.
Round
(
tmp
.
Mul
(
q
.
Amount
,
decThousand
),
0
,
inf
.
RoundUp
)
.
UnscaledBig
()
.
Int64
()
}
// Set sets q's value to be value.
func
(
q
*
Quantity
)
Set
(
value
int64
)
{
if
q
.
Amount
==
nil
{
q
.
Amount
=
&
inf
.
Dec
{}
}
q
.
Amount
.
SetUnscaled
(
value
)
q
.
Amount
.
SetScale
(
0
)
}
// SetMilli sets q's value to be value * 1/1000.
func
(
q
*
Quantity
)
SetMilli
(
value
int64
)
{
if
q
.
Amount
==
nil
{
q
.
Amount
=
&
inf
.
Dec
{}
}
q
.
Amount
.
SetUnscaled
(
value
)
q
.
Amount
.
SetScale
(
3
)
}
// Copy is a convenience function that makes a deep copy for you. Non-deep
// copies of quantities share pointers and you will regret that.
func
(
q
*
Quantity
)
Copy
()
*
Quantity
{
if
q
.
Amount
==
nil
{
return
NewQuantity
(
0
,
q
.
Format
)
}
tmp
:=
&
inf
.
Dec
{}
return
&
Quantity
{
Amount
:
tmp
.
Set
(
q
.
Amount
),
Format
:
q
.
Format
,
}
}
// qFlag is a helper type for the Flag function
type
qFlag
struct
{
dest
*
Quantity
}
func
(
qf
qFlag
)
Set
(
val
string
)
error
{
q
,
err
:=
ParseQuantity
(
val
)
if
err
!=
nil
{
return
err
}
// This copy is OK because q will not be referenced again.
*
qf
.
dest
=
*
q
return
nil
}
func
(
qf
qFlag
)
String
()
string
{
return
qf
.
dest
.
String
()
}
// QuantityFlag is a helper that makes a quantity flag (using standard flag package).
// Will panic if defaultValue is not a valid quantity.
func
QuantityFlag
(
flagName
,
defaultValue
,
description
string
)
*
Quantity
{
q
,
err
:=
ParseQuantity
(
defaultValue
)
if
err
!=
nil
{
panic
(
fmt
.
Errorf
(
"can't use %v as a quantity: %v"
,
defaultValue
,
err
))
}
flag
.
Var
(
qFlag
{
q
},
flagName
,
description
)
return
q
}
pkg/api/resource/quantity_example_test.go
0 → 100644
View file @
ded3ef28
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
resource_test
import
(
"fmt"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/resource"
)
func
ExampleFormat
()
{
memorySize
:=
resource
.
NewQuantity
(
5
*
1024
*
1024
*
1024
,
resource
.
BinarySI
)
fmt
.
Printf
(
"memorySize = %v
\n
"
,
memorySize
)
diskSize
:=
resource
.
NewQuantity
(
5
*
1000
*
1000
*
1000
,
resource
.
DecimalSI
)
fmt
.
Printf
(
"diskSize = %v
\n
"
,
diskSize
)
cores
:=
resource
.
NewMilliQuantity
(
5300
,
resource
.
DecimalSI
)
fmt
.
Printf
(
"cores = %v
\n
"
,
cores
)
// Output:
// memorySize = 5Gi
// diskSize = 5G
// cores = 5300m
}
func
ExampleParseOrDie
()
{
memorySize
:=
resource
.
ParseOrDie
(
"5Gi"
)
fmt
.
Printf
(
"memorySize = %v (%v)
\n
"
,
memorySize
.
Value
(),
memorySize
.
Format
)
diskSize
:=
resource
.
ParseOrDie
(
"5G"
)
fmt
.
Printf
(
"diskSize = %v (%v)
\n
"
,
diskSize
.
Value
(),
diskSize
.
Format
)
cores
:=
resource
.
ParseOrDie
(
"5300m"
)
fmt
.
Printf
(
"milliCores = %v (%v)
\n
"
,
cores
.
MilliValue
(),
cores
.
Format
)
cores2
:=
resource
.
ParseOrDie
(
"5.4"
)
fmt
.
Printf
(
"milliCores = %v (%v)
\n
"
,
cores2
.
MilliValue
(),
cores2
.
Format
)
// Output:
// memorySize = 5368709120 (BinarySI)
// diskSize = 5000000000 (DecimalSI)
// milliCores = 5300 (DecimalSI)
// milliCores = 5400 (DecimalSI)
}
pkg/api/resource/quantity_test.go
0 → 100644
View file @
ded3ef28
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
resource
import
(
//"reflect"
"encoding/json"
"testing"
fuzz
"github.com/google/gofuzz"
"speter.net/go/exp/math/dec/inf"
)
var
(
testQuantityFlag
=
QuantityFlag
(
"quantityFlag"
,
"1M"
,
"dummy flag for testing the quantity flag mechanism"
)
)
func
dec
(
i
int64
,
exponent
int
)
*
inf
.
Dec
{
// See the below test-- scale is the negative of an exponent.
return
inf
.
NewDec
(
i
,
inf
.
Scale
(
-
exponent
))
}
func
TestDec
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
got
*
inf
.
Dec
expect
string
}{
{
dec
(
1
,
0
),
"1"
},
{
dec
(
1
,
1
),
"10"
},
{
dec
(
5
,
2
),
"500"
},
{
dec
(
8
,
3
),
"8000"
},
{
dec
(
2
,
0
),
"2"
},
{
dec
(
1
,
-
1
),
"0.1"
},
{
dec
(
3
,
-
2
),
"0.03"
},
{
dec
(
4
,
-
3
),
"0.004"
},
}
for
_
,
item
:=
range
table
{
if
e
,
a
:=
item
.
expect
,
item
.
got
.
String
();
e
!=
a
{
t
.
Errorf
(
"expected %v, got %v"
,
e
,
a
)
}
}
}
func
TestQuantityParse
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
input
string
expect
Quantity
}{
{
"0"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
{
"0m"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
{
"0Ki"
,
Quantity
{
dec
(
0
,
0
),
BinarySI
}},
{
"0k"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
{
"0Mi"
,
Quantity
{
dec
(
0
,
0
),
BinarySI
}},
{
"0M"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
{
"0Gi"
,
Quantity
{
dec
(
0
,
0
),
BinarySI
}},
{
"0G"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
{
"0Ti"
,
Quantity
{
dec
(
0
,
0
),
BinarySI
}},
{
"0T"
,
Quantity
{
dec
(
0
,
0
),
DecimalSI
}},
// Binary suffixes
{
"1Ki"
,
Quantity
{
dec
(
1024
,
0
),
BinarySI
}},
{
"8Ki"
,
Quantity
{
dec
(
8
*
1024
,
0
),
BinarySI
}},
{
"7Mi"
,
Quantity
{
dec
(
7
*
1024
*
1024
,
0
),
BinarySI
}},
{
"6Gi"
,
Quantity
{
dec
(
6
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"5Ti"
,
Quantity
{
dec
(
5
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"4Pi"
,
Quantity
{
dec
(
4
*
1024
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"3Ei"
,
Quantity
{
dec
(
3
*
1024
*
1024
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"10Ti"
,
Quantity
{
dec
(
10
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
{
"100Ti"
,
Quantity
{
dec
(
100
*
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
}},
// Decimal suffixes
{
"3m"
,
Quantity
{
dec
(
3
,
-
3
),
DecimalSI
}},
{
"9"
,
Quantity
{
dec
(
9
,
0
),
DecimalSI
}},
{
"8k"
,
Quantity
{
dec
(
8
,
3
),
DecimalSI
}},
{
"7M"
,
Quantity
{
dec
(
7
,
6
),
DecimalSI
}},
{
"6G"
,
Quantity
{
dec
(
6
,
9
),
DecimalSI
}},
{
"5T"
,
Quantity
{
dec
(
5
,
12
),
DecimalSI
}},
{
"40T"
,
Quantity
{
dec
(
4
,
13
),
DecimalSI
}},
{
"300T"
,
Quantity
{
dec
(
3
,
14
),
DecimalSI
}},
{
"2P"
,
Quantity
{
dec
(
2
,
15
),
DecimalSI
}},
{
"1E"
,
Quantity
{
dec
(
1
,
18
),
DecimalSI
}},
// Decimal exponents
{
"1E-3"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalExponent
}},
{
"1e3"
,
Quantity
{
dec
(
1
,
3
),
DecimalExponent
}},
{
"1E6"
,
Quantity
{
dec
(
1
,
6
),
DecimalExponent
}},
{
"1e9"
,
Quantity
{
dec
(
1
,
9
),
DecimalExponent
}},
{
"1E12"
,
Quantity
{
dec
(
1
,
12
),
DecimalExponent
}},
{
"1e15"
,
Quantity
{
dec
(
1
,
15
),
DecimalExponent
}},
{
"1E18"
,
Quantity
{
dec
(
1
,
18
),
DecimalExponent
}},
// Nonstandard but still parsable
{
"1e14"
,
Quantity
{
dec
(
1
,
14
),
DecimalExponent
}},
{
"1e13"
,
Quantity
{
dec
(
1
,
13
),
DecimalExponent
}},
{
"1e3"
,
Quantity
{
dec
(
1
,
3
),
DecimalExponent
}},
{
"100.035k"
,
Quantity
{
dec
(
100035
,
0
),
DecimalSI
}},
// Things that look like floating point
{
"0.001"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.0005k"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.005"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalSI
}},
{
"0.05"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalSI
}},
{
"0.5"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.00050k"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.00500"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalSI
}},
{
"0.05000"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalSI
}},
{
"0.50000"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalSI
}},
{
"0.5e0"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalExponent
}},
{
"0.5e-1"
,
Quantity
{
dec
(
5
,
-
2
),
DecimalExponent
}},
{
"0.5e-2"
,
Quantity
{
dec
(
5
,
-
3
),
DecimalExponent
}},
{
"0.5e0"
,
Quantity
{
dec
(
5
,
-
1
),
DecimalExponent
}},
{
"10.035M"
,
Quantity
{
dec
(
10035
,
3
),
DecimalSI
}},
{
"1.2e3"
,
Quantity
{
dec
(
12
,
2
),
DecimalExponent
}},
{
"1.3E+6"
,
Quantity
{
dec
(
13
,
5
),
DecimalExponent
}},
{
"1.40e9"
,
Quantity
{
dec
(
14
,
8
),
DecimalExponent
}},
{
"1.53E12"
,
Quantity
{
dec
(
153
,
10
),
DecimalExponent
}},
{
"1.6e15"
,
Quantity
{
dec
(
16
,
14
),
DecimalExponent
}},
{
"1.7E18"
,
Quantity
{
dec
(
17
,
17
),
DecimalExponent
}},
{
"9.01"
,
Quantity
{
dec
(
901
,
-
2
),
DecimalSI
}},
{
"8.1k"
,
Quantity
{
dec
(
81
,
2
),
DecimalSI
}},
{
"7.123456M"
,
Quantity
{
dec
(
7123456
,
0
),
DecimalSI
}},
{
"6.987654321G"
,
Quantity
{
dec
(
6987654321
,
0
),
DecimalSI
}},
{
"5.444T"
,
Quantity
{
dec
(
5444
,
9
),
DecimalSI
}},
{
"40.1T"
,
Quantity
{
dec
(
401
,
11
),
DecimalSI
}},
{
"300.2T"
,
Quantity
{
dec
(
3002
,
11
),
DecimalSI
}},
{
"2.5P"
,
Quantity
{
dec
(
25
,
14
),
DecimalSI
}},
{
"1.01E"
,
Quantity
{
dec
(
101
,
16
),
DecimalSI
}},
// Things that saturate/round
{
"3.001m"
,
Quantity
{
dec
(
4
,
-
3
),
DecimalSI
}},
{
"1.1E-3"
,
Quantity
{
dec
(
2
,
-
3
),
DecimalExponent
}},
{
"0.0001"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.0005"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.00050"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.5e-3"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalExponent
}},
{
"0.9m"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
"0.12345"
,
Quantity
{
dec
(
124
,
-
3
),
DecimalSI
}},
{
"0.12354"
,
Quantity
{
dec
(
124
,
-
3
),
DecimalSI
}},
{
"9Ei"
,
Quantity
{
maxAllowed
,
BinarySI
}},
{
"9223372036854775807Ki"
,
Quantity
{
maxAllowed
,
BinarySI
}},
{
"12E"
,
Quantity
{
maxAllowed
,
DecimalSI
}},
// We'll accept fractional binary stuff, too.
{
"100.035Ki"
,
Quantity
{
dec
(
10243584
,
-
2
),
BinarySI
}},
{
"0.5Mi"
,
Quantity
{
dec
(
.5
*
1024
*
1024
,
0
),
BinarySI
}},
{
"0.05Gi"
,
Quantity
{
dec
(
536870912
,
-
1
),
BinarySI
}},
{
"0.025Ti"
,
Quantity
{
dec
(
274877906944
,
-
1
),
BinarySI
}},
// Things written by trolls
{
"0.000001Ki"
,
Quantity
{
dec
(
2
,
-
3
),
DecimalSI
}},
// rounds up, changes format
{
".001"
,
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
}},
{
".0001k"
,
Quantity
{
dec
(
100
,
-
3
),
DecimalSI
}},
{
"1."
,
Quantity
{
dec
(
1
,
0
),
DecimalSI
}},
{
"1.G"
,
Quantity
{
dec
(
1
,
9
),
DecimalSI
}},
}
for
_
,
item
:=
range
table
{
got
,
err
:=
ParseQuantity
(
item
.
input
)
if
err
!=
nil
{
t
.
Errorf
(
"%v: unexpected error: %v"
,
item
.
input
,
err
)
continue
}
if
e
,
a
:=
item
.
expect
.
Amount
,
got
.
Amount
;
e
.
Cmp
(
a
)
!=
0
{
t
.
Errorf
(
"%v: expected %v, got %v"
,
item
.
input
,
e
,
a
)
}
if
e
,
a
:=
item
.
expect
.
Format
,
got
.
Format
;
e
!=
a
{
t
.
Errorf
(
"%v: expected %#v, got %#v"
,
item
.
input
,
e
,
a
)
}
}
// Try the negative version of everything
desired
:=
&
inf
.
Dec
{}
for
_
,
item
:=
range
table
{
got
,
err
:=
ParseQuantity
(
"-"
+
item
.
input
)
if
err
!=
nil
{
t
.
Errorf
(
"-%v: unexpected error: %v"
,
item
.
input
,
err
)
continue
}
desired
.
Neg
(
item
.
expect
.
Amount
)
if
e
,
a
:=
desired
,
got
.
Amount
;
e
.
Cmp
(
a
)
!=
0
{
t
.
Errorf
(
"%v: expected %v, got %v"
,
item
.
input
,
e
,
a
)
}
if
e
,
a
:=
item
.
expect
.
Format
,
got
.
Format
;
e
!=
a
{
t
.
Errorf
(
"%v: expected %#v, got %#v"
,
item
.
input
,
e
,
a
)
}
}
// Try everything with an explicit +
for
_
,
item
:=
range
table
{
got
,
err
:=
ParseQuantity
(
"+"
+
item
.
input
)
if
err
!=
nil
{
t
.
Errorf
(
"-%v: unexpected error: %v"
,
item
.
input
,
err
)
continue
}
if
e
,
a
:=
item
.
expect
.
Amount
,
got
.
Amount
;
e
.
Cmp
(
a
)
!=
0
{
t
.
Errorf
(
"%v: expected %v, got %v"
,
item
.
input
,
e
,
a
)
}
if
e
,
a
:=
item
.
expect
.
Format
,
got
.
Format
;
e
!=
a
{
t
.
Errorf
(
"%v: expected %#v, got %#v"
,
item
.
input
,
e
,
a
)
}
}
invalid
:=
[]
string
{
"1.1.M"
,
"1+1.0M"
,
"0.1mi"
,
"0.1am"
,
"aoeu"
,
".5i"
,
"1i"
,
"-3.01i"
,
}
for
_
,
item
:=
range
invalid
{
_
,
err
:=
ParseQuantity
(
item
)
if
err
==
nil
{
t
.
Errorf
(
"%v parsed unexpectedly"
,
item
)
}
}
}
func
TestQuantityString
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
in
Quantity
expect
string
}{
{
Quantity
{
dec
(
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1Gi"
},
{
Quantity
{
dec
(
300
*
1024
*
1024
,
0
),
BinarySI
},
"300Mi"
},
{
Quantity
{
dec
(
6
*
1024
,
0
),
BinarySI
},
"6Ki"
},
{
Quantity
{
dec
(
1001
*
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1001Gi"
},
{
Quantity
{
dec
(
1024
*
1024
*
1024
*
1024
,
0
),
BinarySI
},
"1Ti"
},
{
Quantity
{
dec
(
5
,
0
),
BinarySI
},
"5"
},
{
Quantity
{
dec
(
500
,
-
3
),
BinarySI
},
"500m"
},
{
Quantity
{
dec
(
1
,
9
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000
,
6
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000000
,
3
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1000000000
,
0
),
DecimalSI
},
"1G"
},
{
Quantity
{
dec
(
1
,
-
3
),
DecimalSI
},
"1m"
},
{
Quantity
{
dec
(
80
,
-
3
),
DecimalSI
},
"80m"
},
{
Quantity
{
dec
(
1080
,
-
3
),
DecimalSI
},
"1080m"
},
{
Quantity
{
dec
(
108
,
-
2
),
DecimalSI
},
"1080m"
},
{
Quantity
{
dec
(
10800
,
-
4
),
DecimalSI
},
"1080m"
},
{
Quantity
{
dec
(
300
,
6
),
DecimalSI
},
"300M"
},
{
Quantity
{
dec
(
1
,
12
),
DecimalSI
},
"1T"
},
{
Quantity
{
dec
(
1234567
,
6
),
DecimalSI
},
"1234567M"
},
{
Quantity
{
dec
(
1234567
,
-
3
),
BinarySI
},
"1234567m"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalSI
},
"3k"
},
{
Quantity
{
dec
(
1025
,
0
),
BinarySI
},
"1025"
},
{
Quantity
{
dec
(
0
,
0
),
DecimalSI
},
"0"
},
{
Quantity
{
dec
(
0
,
0
),
BinarySI
},
"0"
},
{
Quantity
{
dec
(
1
,
9
),
DecimalExponent
},
"1e9"
},
{
Quantity
{
dec
(
1
,
-
3
),
DecimalExponent
},
"1e-3"
},
{
Quantity
{
dec
(
80
,
-
3
),
DecimalExponent
},
"80e-3"
},
{
Quantity
{
dec
(
300
,
6
),
DecimalExponent
},
"300e6"
},
{
Quantity
{
dec
(
1
,
12
),
DecimalExponent
},
"1e12"
},
{
Quantity
{
dec
(
1
,
3
),
DecimalExponent
},
"1e3"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalExponent
},
"3e3"
},
{
Quantity
{
dec
(
3
,
3
),
DecimalSI
},
"3k"
},
{
Quantity
{
dec
(
0
,
0
),
DecimalExponent
},
"0"
},
}
for
_
,
item
:=
range
table
{
got
:=
item
.
in
.
String
()
if
e
,
a
:=
item
.
expect
,
got
;
e
!=
a
{
t
.
Errorf
(
"%#v: expected %v, got %v"
,
item
.
in
,
e
,
a
)
}
}
desired
:=
&
inf
.
Dec
{}
// Avoid modifying the values in the table.
for
_
,
item
:=
range
table
{
if
item
.
in
.
Amount
.
Cmp
(
decZero
)
==
0
{
// Don't expect it to print "-0" ever
continue
}
q
:=
item
.
in
q
.
Amount
=
desired
.
Neg
(
q
.
Amount
)
if
e
,
a
:=
"-"
+
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"%#v: expected %v, got %v"
,
item
.
in
,
e
,
a
)
}
}
}
func
TestQuantityParseEmit
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
in
string
expect
string
}{
{
"1Ki"
,
"1Ki"
},
{
"1Mi"
,
"1Mi"
},
{
"1Gi"
,
"1Gi"
},
{
"1024Mi"
,
"1Gi"
},
{
"1000M"
,
"1G"
},
{
".000001Ki"
,
"2m"
},
}
for
_
,
item
:=
range
table
{
q
,
err
:=
ParseQuantity
(
item
.
in
)
if
err
!=
nil
{
t
.
Errorf
(
"Couldn't parse %v"
,
item
.
in
)
continue
}
if
e
,
a
:=
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"%#v: expected %v, got %v"
,
item
.
in
,
e
,
a
)
}
}
for
_
,
item
:=
range
table
{
q
,
err
:=
ParseQuantity
(
"-"
+
item
.
in
)
if
err
!=
nil
{
t
.
Errorf
(
"Couldn't parse %v"
,
item
.
in
)
continue
}
if
q
.
Amount
.
Cmp
(
decZero
)
==
0
{
continue
}
if
e
,
a
:=
"-"
+
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"%#v: expected %v, got %v"
,
item
.
in
,
e
,
a
)
}
}
}
var
fuzzer
=
fuzz
.
New
()
.
Funcs
(
func
(
q
*
Quantity
,
c
fuzz
.
Continue
)
{
q
.
Amount
=
&
inf
.
Dec
{}
if
c
.
RandBool
()
{
q
.
Format
=
BinarySI
if
c
.
RandBool
()
{
q
.
Amount
.
SetScale
(
0
)
q
.
Amount
.
SetUnscaled
(
c
.
Int63
())
return
}
// Be sure to test cases like 1Mi
q
.
Amount
.
SetScale
(
0
)
q
.
Amount
.
SetUnscaled
(
c
.
Int63n
(
1024
)
<<
uint
(
10
*
c
.
Intn
(
5
)))
return
}
if
c
.
RandBool
()
{
q
.
Format
=
DecimalSI
}
else
{
q
.
Format
=
DecimalExponent
}
if
c
.
RandBool
()
{
q
.
Amount
.
SetScale
(
inf
.
Scale
(
c
.
Intn
(
4
)))
q
.
Amount
.
SetUnscaled
(
c
.
Int63
())
return
}
// Be sure to test cases like 1M
q
.
Amount
.
SetScale
(
inf
.
Scale
(
3
-
c
.
Intn
(
15
)))
q
.
Amount
.
SetUnscaled
(
c
.
Int63n
(
1000
))
},
)
func
TestJSON
(
t
*
testing
.
T
)
{
for
i
:=
0
;
i
<
500
;
i
++
{
q
:=
&
Quantity
{}
fuzzer
.
Fuzz
(
q
)
b
,
err
:=
json
.
Marshal
(
q
)
if
err
!=
nil
{
t
.
Errorf
(
"error encoding %v"
,
q
)
}
q2
:=
&
Quantity
{}
err
=
json
.
Unmarshal
(
b
,
q2
)
if
err
!=
nil
{
t
.
Errorf
(
"%v: error decoding %v"
,
q
,
string
(
b
))
}
if
q2
.
Amount
.
Cmp
(
q
.
Amount
)
!=
0
{
t
.
Errorf
(
"Expected equal: %v, %v (json was '%v')"
,
q
,
q2
,
string
(
b
))
}
}
}
func
TestMilliNewSet
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
value
int64
format
Format
expect
string
exact
bool
}{
{
1
,
DecimalSI
,
"1m"
,
true
},
{
1000
,
DecimalSI
,
"1"
,
true
},
{
1234000
,
DecimalSI
,
"1234"
,
true
},
{
1024
,
BinarySI
,
"1024m"
,
false
},
// Format changes
{
1000000
,
"invalidFormatDefaultsToExponent"
,
"1e3"
,
true
},
{
1024
*
1024
,
BinarySI
,
"1048576m"
,
false
},
// Format changes
}
for
_
,
item
:=
range
table
{
q
:=
NewMilliQuantity
(
item
.
value
,
item
.
format
)
if
e
,
a
:=
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v; %#v"
,
e
,
a
,
q
)
}
if
!
item
.
exact
{
continue
}
q2
,
err
:=
ParseQuantity
(
q
.
String
())
if
err
!=
nil
{
t
.
Errorf
(
"Round trip failed on %v"
,
q
)
}
if
e
,
a
:=
item
.
value
,
q2
.
MilliValue
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
}
for
_
,
item
:=
range
table
{
q
:=
NewQuantity
(
0
,
item
.
format
)
q
.
SetMilli
(
item
.
value
)
if
e
,
a
:=
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"Set: Expected %v, got %v; %#v"
,
e
,
a
,
q
)
}
}
}
func
TestNewSet
(
t
*
testing
.
T
)
{
table
:=
[]
struct
{
value
int64
format
Format
expect
string
}{
{
1
,
DecimalSI
,
"1"
},
{
1000
,
DecimalSI
,
"1k"
},
{
1234000
,
DecimalSI
,
"1234k"
},
{
1024
,
BinarySI
,
"1Ki"
},
{
1000000
,
"invalidFormatDefaultsToExponent"
,
"1e6"
},
{
1024
*
1024
,
BinarySI
,
"1Mi"
},
}
for
_
,
item
:=
range
table
{
q
:=
NewQuantity
(
item
.
value
,
item
.
format
)
if
e
,
a
:=
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v; %#v"
,
e
,
a
,
q
)
}
q2
,
err
:=
ParseQuantity
(
q
.
String
())
if
err
!=
nil
{
t
.
Errorf
(
"Round trip failed on %v"
,
q
)
}
if
e
,
a
:=
item
.
value
,
q2
.
Value
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
}
for
_
,
item
:=
range
table
{
q
:=
NewQuantity
(
0
,
item
.
format
)
q
.
Set
(
item
.
value
)
if
e
,
a
:=
item
.
expect
,
q
.
String
();
e
!=
a
{
t
.
Errorf
(
"Set: Expected %v, got %v; %#v"
,
e
,
a
,
q
)
}
}
}
func
TestUninitializedNoCrash
(
t
*
testing
.
T
)
{
var
q
Quantity
q
.
Value
()
q
.
MilliValue
()
q
.
Copy
()
q
.
String
()
q
.
MarshalJSON
()
}
func
TestCopy
(
t
*
testing
.
T
)
{
q
:=
NewQuantity
(
5
,
DecimalSI
)
c
:=
q
.
Copy
()
c
.
Set
(
6
)
if
q
.
Value
()
==
6
{
t
.
Errorf
(
"Copy didn't"
)
}
}
func
TestQFlagSet
(
t
*
testing
.
T
)
{
qf
:=
qFlag
{
&
Quantity
{}}
qf
.
Set
(
"1Ki"
)
if
e
,
a
:=
"1Ki"
,
qf
.
String
();
e
!=
a
{
t
.
Errorf
(
"Unexpected result %v != %v"
,
e
,
a
)
}
}
pkg/api/resource/suffix.go
0 → 100644
View file @
ded3ef28
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package
resource
import
(
"strconv"
)
type
suffix
string
// suffixer can interpret and construct suffixes.
type
suffixer
interface
{
interpret
(
suffix
)
(
base
,
exponent
int
,
fmt
Format
,
ok
bool
)
construct
(
base
,
exponent
int
,
fmt
Format
)
(
s
suffix
,
ok
bool
)
}
// quantitySuffixer handles suffixes for all three formats that quantity
// can handle.
var
quantitySuffixer
=
newSuffixer
()
type
bePair
struct
{
base
,
exponent
int
}
type
listSuffixer
struct
{
suffixToBE
map
[
suffix
]
bePair
beToSuffix
map
[
bePair
]
suffix
}
func
(
ls
*
listSuffixer
)
addSuffix
(
s
suffix
,
pair
bePair
)
{
if
ls
.
suffixToBE
==
nil
{
ls
.
suffixToBE
=
map
[
suffix
]
bePair
{}
}
if
ls
.
beToSuffix
==
nil
{
ls
.
beToSuffix
=
map
[
bePair
]
suffix
{}
}
ls
.
suffixToBE
[
s
]
=
pair
ls
.
beToSuffix
[
pair
]
=
s
}
func
(
ls
*
listSuffixer
)
lookup
(
s
suffix
)
(
base
,
exponent
int
,
ok
bool
)
{
pair
,
ok
:=
ls
.
suffixToBE
[
s
]
if
!
ok
{
return
0
,
0
,
false
}
return
pair
.
base
,
pair
.
exponent
,
true
}
func
(
ls
*
listSuffixer
)
construct
(
base
,
exponent
int
)
(
s
suffix
,
ok
bool
)
{
s
,
ok
=
ls
.
beToSuffix
[
bePair
{
base
,
exponent
}]
return
}
type
suffixHandler
struct
{
decSuffixes
listSuffixer
binSuffixes
listSuffixer
}
func
newSuffixer
()
suffixer
{
sh
:=
&
suffixHandler
{}
sh
.
binSuffixes
.
addSuffix
(
"Ki"
,
bePair
{
2
,
10
})
sh
.
binSuffixes
.
addSuffix
(
"Mi"
,
bePair
{
2
,
20
})
sh
.
binSuffixes
.
addSuffix
(
"Gi"
,
bePair
{
2
,
30
})
sh
.
binSuffixes
.
addSuffix
(
"Ti"
,
bePair
{
2
,
40
})
sh
.
binSuffixes
.
addSuffix
(
"Pi"
,
bePair
{
2
,
50
})
sh
.
binSuffixes
.
addSuffix
(
"Ei"
,
bePair
{
2
,
60
})
// Don't emit an error when trying to produce
// a suffix for 2^0.
sh
.
decSuffixes
.
addSuffix
(
""
,
bePair
{
2
,
0
})
sh
.
decSuffixes
.
addSuffix
(
"m"
,
bePair
{
10
,
-
3
})
sh
.
decSuffixes
.
addSuffix
(
""
,
bePair
{
10
,
0
})
sh
.
decSuffixes
.
addSuffix
(
"k"
,
bePair
{
10
,
3
})
sh
.
decSuffixes
.
addSuffix
(
"M"
,
bePair
{
10
,
6
})
sh
.
decSuffixes
.
addSuffix
(
"G"
,
bePair
{
10
,
9
})
sh
.
decSuffixes
.
addSuffix
(
"T"
,
bePair
{
10
,
12
})
sh
.
decSuffixes
.
addSuffix
(
"P"
,
bePair
{
10
,
15
})
sh
.
decSuffixes
.
addSuffix
(
"E"
,
bePair
{
10
,
18
})
return
sh
}
func
(
sh
*
suffixHandler
)
construct
(
base
,
exponent
int
,
fmt
Format
)
(
s
suffix
,
ok
bool
)
{
switch
fmt
{
case
DecimalSI
:
return
sh
.
decSuffixes
.
construct
(
base
,
exponent
)
case
BinarySI
:
return
sh
.
binSuffixes
.
construct
(
base
,
exponent
)
case
DecimalExponent
:
if
base
!=
10
{
return
""
,
false
}
if
exponent
==
0
{
return
""
,
true
}
return
suffix
(
"e"
+
strconv
.
FormatInt
(
int64
(
exponent
),
10
)),
true
}
return
""
,
false
}
func
(
sh
*
suffixHandler
)
interpret
(
suffix
suffix
)
(
base
,
exponent
int
,
fmt
Format
,
ok
bool
)
{
// Try lookup tables first
if
b
,
e
,
ok
:=
sh
.
decSuffixes
.
lookup
(
suffix
);
ok
{
return
b
,
e
,
DecimalSI
,
true
}
if
b
,
e
,
ok
:=
sh
.
binSuffixes
.
lookup
(
suffix
);
ok
{
return
b
,
e
,
BinarySI
,
true
}
if
len
(
suffix
)
>
1
&&
(
suffix
[
0
]
==
'E'
||
suffix
[
0
]
==
'e'
)
{
parsed
,
err
:=
strconv
.
ParseInt
(
string
(
suffix
[
1
:
]),
10
,
64
)
if
err
!=
nil
{
return
0
,
0
,
DecimalExponent
,
false
}
return
10
,
int
(
parsed
),
DecimalExponent
,
true
}
return
0
,
0
,
DecimalExponent
,
false
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment