• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: 提交

Golang implemented sidechain for Bytom


Commit MetaInfo

修订版4c90195eed7ddee19d646520f06fd6079a322895 (tree)
时间2020-01-22 15:31:09
作者shenao78 <shenao.78@163....>
Commitershenao78

Log Message

fix decimal

更改概述

差异

--- a/application/mov/match/match.go
+++ b/application/mov/match/match.go
@@ -10,6 +10,7 @@ import (
1010 "github.com/bytom/vapor/consensus/segwit"
1111 "github.com/bytom/vapor/errors"
1212 vprMath "github.com/bytom/vapor/math"
13+ "github.com/bytom/vapor/math/decimal"
1314 "github.com/bytom/vapor/protocol/bc"
1415 "github.com/bytom/vapor/protocol/bc/types"
1516 "github.com/bytom/vapor/protocol/vm"
@@ -240,20 +241,18 @@ func IsMatched(orders []*common.Order) bool {
240241 return false
241242 }
242243
243- rate := orderRatio(sortedOrders[0])
244- oppositeRate := big.NewFloat(0).SetInt64(1)
244+ rate := decimal.New(1, 0).Div(orderRatio(sortedOrders[0]))
245+ oppositeRate := decimal.New(1, 0)
245246 for i := 1; i < len(sortedOrders); i++ {
246- oppositeRate.Mul(oppositeRate, orderRatio(sortedOrders[i]))
247+ oppositeRate = oppositeRate.Mul(orderRatio(sortedOrders[i]))
247248 }
248-
249- one := big.NewFloat(0).SetInt64(1)
250- return one.Quo(one, rate).Cmp(oppositeRate) >= 0
249+ return rate.Cmp(oppositeRate) >= 0
251250 }
252251
253-func orderRatio(order *common.Order) *big.Float {
254- ratio := big.NewFloat(0).SetInt64(order.RatioNumerator)
255- ratio.Quo(ratio, big.NewFloat(0).SetInt64(order.RatioDenominator))
256- return ratio
252+func orderRatio(order *common.Order) *decimal.Decimal {
253+ numerator := decimal.New(order.RatioNumerator, 0)
254+ denominator := decimal.New(order.RatioDenominator, 0)
255+ return numerator.Div(denominator)
257256 }
258257
259258 func setMatchTxArguments(txInput *types.TxInput, isPartialTrade bool, position int, receiveAmounts uint64) {
--- a/application/mov/match/match_test.go
+++ b/application/mov/match/match_test.go
@@ -256,3 +256,163 @@ func TestValidateTradePairs(t *testing.T) {
256256 }
257257 }
258258 }
259+
260+func TestIsMatched(t *testing.T) {
261+ cases := []struct {
262+ desc string
263+ orders []*common.Order
264+ wantMatched bool
265+ }{
266+ {
267+ desc: "ratio is equals",
268+ orders: []*common.Order{
269+ {
270+ FromAssetID: &mock.BTC,
271+ ToAssetID: &mock.ETH,
272+ RatioNumerator: 6250,
273+ RatioDenominator: 3,
274+ },
275+ {
276+ FromAssetID: &mock.ETH,
277+ ToAssetID: &mock.BTC,
278+ RatioNumerator: 3,
279+ RatioDenominator: 6250,
280+ },
281+ },
282+ wantMatched: true,
283+ },
284+ {
285+ desc: "ratio is equals, and numerator and denominator are multiples of the opposite",
286+ orders: []*common.Order{
287+ {
288+ FromAssetID: &mock.BTC,
289+ ToAssetID: &mock.ETH,
290+ RatioNumerator: 6250,
291+ RatioDenominator: 3,
292+ },
293+ {
294+ FromAssetID: &mock.ETH,
295+ ToAssetID: &mock.BTC,
296+ RatioNumerator: 9,
297+ RatioDenominator: 18750,
298+ },
299+ },
300+ wantMatched: true,
301+ },
302+ {
303+ desc: "matched with a slight diff",
304+ orders: []*common.Order{
305+ {
306+ FromAssetID: &mock.BTC,
307+ ToAssetID: &mock.ETH,
308+ RatioNumerator: 62500000000000000,
309+ RatioDenominator: 30000000000001,
310+ },
311+ {
312+ FromAssetID: &mock.ETH,
313+ ToAssetID: &mock.BTC,
314+ RatioNumerator: 3,
315+ RatioDenominator: 6250,
316+ },
317+ },
318+ wantMatched: true,
319+ },
320+ {
321+ desc: "not matched with a slight diff",
322+ orders: []*common.Order{
323+ {
324+ FromAssetID: &mock.BTC,
325+ ToAssetID: &mock.ETH,
326+ RatioNumerator: 62500000000000001,
327+ RatioDenominator: 30000000000000,
328+ },
329+ {
330+ FromAssetID: &mock.ETH,
331+ ToAssetID: &mock.BTC,
332+ RatioNumerator: 3,
333+ RatioDenominator: 6250,
334+ },
335+ },
336+ wantMatched: false,
337+ },
338+ {
339+ desc: "ring matched",
340+ orders: []*common.Order{
341+ {
342+ FromAssetID: &mock.BTC,
343+ ToAssetID: &mock.ETH,
344+ RatioNumerator: 2000000003,
345+ RatioDenominator: 100000001,
346+ },
347+ {
348+ FromAssetID: &mock.ETH,
349+ ToAssetID: &mock.EOS,
350+ RatioNumerator: 400000000001,
351+ RatioDenominator: 2000000003,
352+ },
353+ {
354+ FromAssetID: &mock.EOS,
355+ ToAssetID: &mock.BTC,
356+ RatioNumerator: 100000001,
357+ RatioDenominator: 400000000001,
358+ },
359+ },
360+ wantMatched: true,
361+ },
362+ {
363+ desc: "ring matched with a slight diff",
364+ orders: []*common.Order{
365+ {
366+ FromAssetID: &mock.BTC,
367+ ToAssetID: &mock.ETH,
368+ RatioNumerator: 2000000003,
369+ RatioDenominator: 100000001,
370+ },
371+ {
372+ FromAssetID: &mock.ETH,
373+ ToAssetID: &mock.EOS,
374+ RatioNumerator: 400000000001,
375+ RatioDenominator: 2000000003,
376+ },
377+ {
378+ FromAssetID: &mock.EOS,
379+ ToAssetID: &mock.BTC,
380+ RatioNumerator: 100000000,
381+ RatioDenominator: 400000000001,
382+ },
383+ },
384+ wantMatched: true,
385+ },
386+ {
387+ desc: "ring fail matched with a slight diff",
388+ orders: []*common.Order{
389+ {
390+ FromAssetID: &mock.BTC,
391+ ToAssetID: &mock.ETH,
392+ RatioNumerator: 2000000003,
393+ RatioDenominator: 100000001,
394+ },
395+ {
396+ FromAssetID: &mock.ETH,
397+ ToAssetID: &mock.EOS,
398+ RatioNumerator: 400000000001,
399+ RatioDenominator: 2000000003,
400+ },
401+ {
402+ FromAssetID: &mock.EOS,
403+ ToAssetID: &mock.BTC,
404+ RatioNumerator: 100000002,
405+ RatioDenominator: 400000000001,
406+ },
407+ },
408+ wantMatched: false,
409+ },
410+ }
411+
412+ for i, c := range cases {
413+ gotMatched := IsMatched(c.orders)
414+ if gotMatched != c.wantMatched {
415+ t.Errorf("#%d(%s) got matched:%v, want matched:%v", i, c.desc, gotMatched, c.wantMatched)
416+ }
417+ }
418+}
--- /dev/null
+++ b/math/decimal/decimal.go
@@ -0,0 +1,143 @@
1+package decimal
2+
3+import (
4+ "github.com/pingcap/types"
5+ "github.com/sirupsen/logrus"
6+)
7+
8+type Decimal struct {
9+ value *types.MyDecimal
10+}
11+
12+func NewFromString(value string) (*Decimal, error) {
13+ dec := new(types.MyDecimal)
14+ if err := dec.FromString([]byte(value)); err != nil && err != types.ErrTruncated {
15+ return nil, err
16+ }
17+
18+ return &Decimal{value: dec}, nil
19+}
20+
21+func New(value int64, exp int) *Decimal {
22+ dec := types.NewDecFromInt(value)
23+ if exp < 0 {
24+ pow := types.NewDecFromInt(1)
25+ if err := pow.Shift(-exp); err != nil {
26+ logFatal(err,"decimal shift error")
27+ }
28+
29+ if err := types.DecimalDiv(dec, pow, dec, 10); err != nil {
30+ logFatal(err,"decimal divide error")
31+ }
32+ } else {
33+ if err := dec.Shift(exp); err != nil {
34+ logFatal(err,"decimal shift error")
35+ }
36+ }
37+ return &Decimal{value: dec}
38+}
39+
40+func (d *Decimal) Abs() *Decimal {
41+ coefficient := New(1, 0)
42+ if d.value.IsNegative() {
43+ coefficient = New(-1, 0)
44+ }
45+ return d.Mul(coefficient)
46+}
47+
48+func (d *Decimal) Add(d2 *Decimal) *Decimal {
49+ result := new(types.MyDecimal)
50+ if err := types.DecimalAdd(d.value, d2.value, result); err != nil {
51+ logFatal(err,"decimal add error")
52+ }
53+
54+ return &Decimal{value: result}
55+}
56+
57+func (d *Decimal) Sub(d2 *Decimal) *Decimal {
58+ result := new(types.MyDecimal)
59+ if err := types.DecimalSub(d.value, d2.value, result); err != nil {
60+ logFatal(err,"decimal subtract error")
61+ }
62+
63+ return &Decimal{value: result}
64+}
65+
66+func (d *Decimal) Mul(d2 *Decimal) *Decimal {
67+ result := new(types.MyDecimal)
68+ if err := types.DecimalMul(d.value, d2.value, result); err != nil {
69+ logFatal(err,"decimal multiply error")
70+ }
71+
72+ return &Decimal{value: result}
73+}
74+
75+func (d *Decimal) Div(d2 *Decimal) *Decimal {
76+ result := new(types.MyDecimal)
77+ if err := types.DecimalDiv(d.value, d2.value, result, 10); err != nil {
78+ logFatal(err,"decimal divide error")
79+ }
80+
81+ return &Decimal{value: result}
82+}
83+
84+func (d *Decimal) Float64() float64 {
85+ result, err := d.value.ToFloat64()
86+ if err != nil {
87+ logFatal(err,"decimal to float64 error")
88+ }
89+
90+ return result
91+}
92+
93+func (d *Decimal) Int64() int64 {
94+ result, err := d.value.ToInt()
95+ if err != nil {
96+ logFatal(err,"decimal to int64 error")
97+ }
98+
99+ return result
100+}
101+
102+func (d *Decimal) Cmp(d2 *Decimal) int {
103+ return d.value.Compare(d2.value)
104+}
105+
106+func (d *Decimal) LessThanOrEqual(d2 *Decimal) bool {
107+ return d.Cmp(d2) <= 0
108+}
109+
110+func (d *Decimal) GreaterThan(d2 *Decimal) bool {
111+ return d.Cmp(d2) > 0
112+}
113+
114+func (d *Decimal) String() string {
115+ return d.value.String()
116+}
117+
118+func (d *Decimal) StringRoundFixed(places int) string {
119+ result := new(types.MyDecimal)
120+ if err := d.value.Round(result, places, types.ModeHalfEven); err != nil {
121+ logFatal(err, "decimal string round fixed error")
122+ }
123+
124+ return result.String()
125+}
126+
127+func (d *Decimal) StringCeilFixed(places int) string {
128+ fixedRate, err := NewFromString(d.StringRoundFixed(places))
129+ if err != nil {
130+ logFatal(err, "decimal string ceil fixed error")
131+ }
132+
133+ if fixedRate.Cmp(d) != 0 {
134+ fixedRate = fixedRate.Add(New(1, -places))
135+ }
136+ return fixedRate.StringRoundFixed(places)
137+}
138+
139+func logFatal(err error, args ...interface{}) {
140+ if err != types.ErrTruncated {
141+ logrus.WithField("err", err).Fatal(args...)
142+ }
143+}
--- /dev/null
+++ b/vendor/github.com/pingcap/types/helper.go
@@ -0,0 +1,168 @@
1+package types
2+
3+// Copyright 2015 PingCAP, Inc.
4+//
5+// Licensed under the Apache License, Version 2.0 (the "License");
6+// you may not use this file except in compliance with the License.
7+// You may obtain a copy of the License at
8+//
9+// http://www.apache.org/licenses/LICENSE-2.0
10+//
11+// Unless required by applicable law or agreed to in writing, software
12+// distributed under the License is distributed on an "AS IS" BASIS,
13+// See the License for the specific language governing permissions and
14+// limitations under the License.
15+
16+import (
17+ "math"
18+ "strings"
19+ "unicode"
20+
21+ "github.com/sirupsen/logrus"
22+)
23+
24+// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function.
25+// RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html
26+// so rounding use "round half away from zero".
27+// e.g, 1.5 -> 2, -1.5 -> -2.
28+func RoundFloat(f float64) float64 {
29+ if math.Abs(f) < 0.5 {
30+ return 0
31+ }
32+
33+ return math.Trunc(f + math.Copysign(0.5, f))
34+}
35+
36+// Round rounds the argument f to dec decimal places.
37+// dec defaults to 0 if not specified. dec can be negative
38+// to cause dec digits left of the decimal point of the
39+// value f to become zero.
40+func Round(f float64, dec int) float64 {
41+ shift := math.Pow10(dec)
42+ tmp := f * shift
43+ if math.IsInf(tmp, 0) {
44+ return f
45+ }
46+ return RoundFloat(tmp) / shift
47+}
48+
49+// Truncate truncates the argument f to dec decimal places.
50+// dec defaults to 0 if not specified. dec can be negative
51+// to cause dec digits left of the decimal point of the
52+// value f to become zero.
53+func Truncate(f float64, dec int) float64 {
54+ shift := math.Pow10(dec)
55+ tmp := f * shift
56+ if math.IsInf(tmp, 0) {
57+ return f
58+ }
59+ return math.Trunc(tmp) / shift
60+}
61+
62+func isSpace(c byte) bool {
63+ return c == ' ' || c == '\t'
64+}
65+
66+func isDigit(c byte) bool {
67+ return c >= '0' && c <= '9'
68+}
69+
70+func myMax(a, b int) int {
71+ if a > b {
72+ return a
73+ }
74+ return b
75+}
76+
77+func myMaxInt8(a, b int8) int8 {
78+ if a > b {
79+ return a
80+ }
81+ return b
82+}
83+
84+func myMin(a, b int) int {
85+ if a < b {
86+ return a
87+ }
88+ return b
89+}
90+
91+func myMinInt8(a, b int8) int8 {
92+ if a < b {
93+ return a
94+ }
95+ return b
96+}
97+
98+const (
99+ maxUint = uint64(math.MaxUint64)
100+ uintCutOff = maxUint/uint64(10) + 1
101+ intCutOff = uint64(math.MaxInt64) + 1
102+)
103+
104+// strToInt converts a string to an integer in best effort.
105+func strToInt(str string) (int64, error) {
106+ str = strings.TrimSpace(str)
107+ if len(str) == 0 {
108+ return 0, ErrTruncated
109+ }
110+ negative := false
111+ i := 0
112+ if str[i] == '-' {
113+ negative = true
114+ i++
115+ } else if str[i] == '+' {
116+ i++
117+ }
118+
119+ var (
120+ err error
121+ hasNum = false
122+ )
123+ r := uint64(0)
124+ for ; i < len(str); i++ {
125+ if !unicode.IsDigit(rune(str[i])) {
126+ err = ErrTruncated
127+ break
128+ }
129+ hasNum = true
130+ if r >= uintCutOff {
131+ r = 0
132+ err = ErrBadNumber
133+ break
134+ }
135+ r = r * uint64(10)
136+
137+ r1 := r + uint64(str[i]-'0')
138+ if r1 < r || r1 > maxUint {
139+ r = 0
140+ err = ErrBadNumber
141+ break
142+ }
143+ r = r1
144+ }
145+ if !hasNum {
146+ err = ErrTruncated
147+ }
148+
149+ if !negative && r >= intCutOff {
150+ return math.MaxInt64, ErrBadNumber
151+ }
152+
153+ if negative && r > intCutOff {
154+ return math.MinInt64, ErrBadNumber
155+ }
156+
157+ if negative {
158+ r = -r
159+ }
160+ return int64(r), err
161+}
162+
163+// Log logs the error if it is not nil.
164+func Log(err error) {
165+ if err != nil {
166+ logrus.Error("encountered error", err)
167+ }
168+}
--- /dev/null
+++ b/vendor/github.com/pingcap/types/mydecimal.go
@@ -0,0 +1,2332 @@
1+// Copyright 2016 PingCAP, Inc.
2+//
3+// Licensed under the Apache License, Version 2.0 (the "License");
4+// you may not use this file except in compliance with the License.
5+// You may obtain a copy of the License at
6+//
7+// http://www.apache.org/licenses/LICENSE-2.0
8+//
9+// Unless required by applicable law or agreed to in writing, software
10+// distributed under the License is distributed on an "AS IS" BASIS,
11+// See the License for the specific language governing permissions and
12+// limitations under the License.
13+
14+package types
15+
16+import (
17+ "errors"
18+ "math"
19+ "strconv"
20+)
21+
22+// RoundMode is the type for round mode.
23+type RoundMode int32
24+
25+var (
26+ // ErrTruncated is returned when data has been truncated during conversion.
27+ ErrTruncated = errors.New("err truncated")
28+ // ErrOverflow is returned when data is out of range for a field type.
29+ ErrOverflow = errors.New("err overflow")
30+ // ErrDivByZero is return when do division by 0.
31+ ErrDivByZero = errors.New("err div by zero")
32+ // ErrBadNumber is return when parsing an invalid binary decimal number.
33+ ErrBadNumber = errors.New("err bad number")
34+)
35+
36+// constant values.
37+const (
38+ ten0 = 1
39+ ten1 = 10
40+ ten2 = 100
41+ ten3 = 1000
42+ ten4 = 10000
43+ ten5 = 100000
44+ ten6 = 1000000
45+ ten7 = 10000000
46+ ten8 = 100000000
47+ ten9 = 1000000000
48+
49+ maxWordBufLen = 9 // A MyDecimal holds 9 words.
50+ digitsPerWord = 9 // A word holds 9 digits.
51+ wordSize = 4 // A word is 4 bytes int32.
52+ digMask = ten8
53+ wordBase = ten9
54+ wordMax = wordBase - 1
55+ notFixedDec = 31
56+
57+ DivFracIncr = 4
58+
59+ // ModeHalfEven rounds normally.
60+ ModeHalfEven RoundMode = 5
61+ // Truncate just truncates the decimal.
62+ ModeTruncate RoundMode = 10
63+ // Ceiling is not supported now.
64+ modeCeiling RoundMode = 0
65+
66+ MaxDecimalScale = 30
67+)
68+
69+var (
70+ wordBufLen = 9
71+ mod9 = [128]int8{
72+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
73+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
74+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
75+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
76+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
77+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
78+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
79+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
80+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
81+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
82+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
83+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
84+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
85+ 0, 1, 2, 3, 4, 5, 6, 7, 8,
86+ 0, 1,
87+ }
88+ div9 = [128]int{
89+ 0, 0, 0, 0, 0, 0, 0, 0, 0,
90+ 1, 1, 1, 1, 1, 1, 1, 1, 1,
91+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
92+ 3, 3, 3, 3, 3, 3, 3, 3, 3,
93+ 4, 4, 4, 4, 4, 4, 4, 4, 4,
94+ 5, 5, 5, 5, 5, 5, 5, 5, 5,
95+ 6, 6, 6, 6, 6, 6, 6, 6, 6,
96+ 7, 7, 7, 7, 7, 7, 7, 7, 7,
97+ 8, 8, 8, 8, 8, 8, 8, 8, 8,
98+ 9, 9, 9, 9, 9, 9, 9, 9, 9,
99+ 10, 10, 10, 10, 10, 10, 10, 10, 10,
100+ 11, 11, 11, 11, 11, 11, 11, 11, 11,
101+ 12, 12, 12, 12, 12, 12, 12, 12, 12,
102+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
103+ 14, 14,
104+ }
105+ powers10 = [10]int32{ten0, ten1, ten2, ten3, ten4, ten5, ten6, ten7, ten8, ten9}
106+ dig2bytes = [10]int{0, 1, 1, 2, 2, 3, 3, 4, 4, 4}
107+ fracMax = [8]int32{
108+ 900000000,
109+ 990000000,
110+ 999000000,
111+ 999900000,
112+ 999990000,
113+ 999999000,
114+ 999999900,
115+ 999999990,
116+ }
117+ zeroMyDecimal = MyDecimal{}
118+)
119+
120+// get the zero of MyDecimal with the specified result fraction digits
121+func zeroMyDecimalWithFrac(frac int8) MyDecimal {
122+ zero := MyDecimal{}
123+ zero.digitsFrac = frac
124+ zero.resultFrac = frac
125+ return zero
126+}
127+
128+// add adds a and b and carry, returns the sum and new carry.
129+func add(a, b, carry int32) (int32, int32) {
130+ sum := a + b + carry
131+ if sum >= wordBase {
132+ carry = 1
133+ sum -= wordBase
134+ } else {
135+ carry = 0
136+ }
137+ return sum, carry
138+}
139+
140+// add2 adds a and b and carry, returns the sum and new carry.
141+// It is only used in DecimalMul.
142+func add2(a, b, carry int32) (int32, int32) {
143+ sum := int64(a) + int64(b) + int64(carry)
144+ if sum >= wordBase {
145+ carry = 1
146+ sum -= wordBase
147+ } else {
148+ carry = 0
149+ }
150+
151+ if sum >= wordBase {
152+ sum -= wordBase
153+ carry++
154+ }
155+ return int32(sum), carry
156+}
157+
158+// sub subtracts b and carry from a, returns the diff and new carry.
159+func sub(a, b, carry int32) (int32, int32) {
160+ diff := a - b - carry
161+ if diff < 0 {
162+ carry = 1
163+ diff += wordBase
164+ } else {
165+ carry = 0
166+ }
167+ return diff, carry
168+}
169+
170+// sub2 subtracts b and carry from a, returns the diff and new carry.
171+// the new carry may be 2.
172+func sub2(a, b, carry int32) (int32, int32) {
173+ diff := a - b - carry
174+ if diff < 0 {
175+ carry = 1
176+ diff += wordBase
177+ } else {
178+ carry = 0
179+ }
180+ if diff < 0 {
181+ diff += wordBase
182+ carry++
183+ }
184+ return diff, carry
185+}
186+
187+// fixWordCntError limits word count in wordBufLen, and returns overflow or truncate error.
188+func fixWordCntError(wordsInt, wordsFrac int) (newWordsInt int, newWordsFrac int, err error) {
189+ if wordsInt+wordsFrac > wordBufLen {
190+ if wordsInt > wordBufLen {
191+ return wordBufLen, 0, ErrOverflow
192+ }
193+ return wordsInt, wordBufLen - wordsInt, ErrTruncated
194+ }
195+ return wordsInt, wordsFrac, nil
196+}
197+
198+/*
199+ countLeadingZeroes returns the number of leading zeroes that can be removed from fraction.
200+
201+ @param i start index
202+ @param word value to compare against list of powers of 10
203+*/
204+func countLeadingZeroes(i int, word int32) int {
205+ leading := 0
206+ for word < powers10[i] {
207+ i--
208+ leading++
209+ }
210+ return leading
211+}
212+
213+/*
214+ countTrailingZeros returns the number of trailing zeroes that can be removed from fraction.
215+
216+ @param i start index
217+ @param word value to compare against list of powers of 10
218+*/
219+func countTrailingZeroes(i int, word int32) int {
220+ trailing := 0
221+ for word%powers10[i] == 0 {
222+ i++
223+ trailing++
224+ }
225+ return trailing
226+}
227+
228+func digitsToWords(digits int) int {
229+ if digits+digitsPerWord-1 >= 0 && digits+digitsPerWord-1 < 128 {
230+ return div9[digits+digitsPerWord-1]
231+ }
232+ return (digits + digitsPerWord - 1) / digitsPerWord
233+}
234+
235+// MyDecimalStructSize is the struct size of MyDecimal.
236+const MyDecimalStructSize = 40
237+
238+// MyDecimal represents a decimal value.
239+type MyDecimal struct {
240+ digitsInt int8 // the number of *decimal* digits before the point.
241+
242+ digitsFrac int8 // the number of decimal digits after the point.
243+
244+ resultFrac int8 // result fraction digits.
245+
246+ negative bool
247+
248+ // wordBuf is an array of int32 words.
249+ // A word is an int32 value can hold 9 digits.(0 <= word < wordBase)
250+ wordBuf [maxWordBufLen]int32
251+}
252+
253+// IsNegative returns whether a decimal is negative.
254+func (d *MyDecimal) IsNegative() bool {
255+ return d.negative
256+}
257+
258+// GetDigitsFrac returns the digitsFrac.
259+func (d *MyDecimal) GetDigitsFrac() int8 {
260+ return d.digitsFrac
261+}
262+
263+// GetDigitsInt returns the digitsInt.
264+func (d *MyDecimal) GetDigitsInt() int8 {
265+ return d.digitsInt
266+}
267+
268+// String returns the decimal string representation rounded to resultFrac.
269+func (d *MyDecimal) String() string {
270+ tmp := *d
271+ err := tmp.Round(&tmp, int(tmp.resultFrac), ModeHalfEven)
272+ Log(err)
273+ return string(tmp.ToString())
274+}
275+
276+func (d *MyDecimal) stringSize() int {
277+ // sign, zero integer and dot.
278+ return int(d.digitsInt + d.digitsFrac + 3)
279+}
280+
281+func (d *MyDecimal) removeLeadingZeros() (wordIdx int, digitsInt int) {
282+ digitsInt = int(d.digitsInt)
283+ i := ((digitsInt - 1) % digitsPerWord) + 1
284+ for digitsInt > 0 && d.wordBuf[wordIdx] == 0 {
285+ digitsInt -= i
286+ i = digitsPerWord
287+ wordIdx++
288+ }
289+ if digitsInt > 0 {
290+ digitsInt -= countLeadingZeroes((digitsInt-1)%digitsPerWord, d.wordBuf[wordIdx])
291+ } else {
292+ digitsInt = 0
293+ }
294+ return
295+}
296+
297+func (d *MyDecimal) removeTrailingZeros() (lastWordIdx int, digitsFrac int) {
298+ digitsFrac = int(d.digitsFrac)
299+ i := ((digitsFrac - 1) % digitsPerWord) + 1
300+ lastWordIdx = digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))
301+ for digitsFrac > 0 && d.wordBuf[lastWordIdx-1] == 0 {
302+ digitsFrac -= i
303+ i = digitsPerWord
304+ lastWordIdx--
305+ }
306+ if digitsFrac > 0 {
307+ digitsFrac -= countTrailingZeroes(9-((digitsFrac-1)%digitsPerWord), d.wordBuf[lastWordIdx-1])
308+ } else {
309+ digitsFrac = 0
310+ }
311+ return
312+}
313+
314+// ToString converts decimal to its printable string representation without rounding.
315+//
316+// RETURN VALUE
317+//
318+// str - result string
319+// errCode - eDecOK/eDecTruncate/eDecOverflow
320+//
321+func (d *MyDecimal) ToString() (str []byte) {
322+ str = make([]byte, d.stringSize())
323+ digitsFrac := int(d.digitsFrac)
324+ wordStartIdx, digitsInt := d.removeLeadingZeros()
325+ if digitsInt+digitsFrac == 0 {
326+ digitsInt = 1
327+ wordStartIdx = 0
328+ }
329+
330+ digitsIntLen := digitsInt
331+ if digitsIntLen == 0 {
332+ digitsIntLen = 1
333+ }
334+ digitsFracLen := digitsFrac
335+ length := digitsIntLen + digitsFracLen
336+ if d.negative {
337+ length++
338+ }
339+ if digitsFrac > 0 {
340+ length++
341+ }
342+ str = str[:length]
343+ strIdx := 0
344+ if d.negative {
345+ str[strIdx] = '-'
346+ strIdx++
347+ }
348+ var fill int
349+ if digitsFrac > 0 {
350+ fracIdx := strIdx + digitsIntLen
351+ fill = digitsFracLen - digitsFrac
352+ wordIdx := wordStartIdx + digitsToWords(digitsInt)
353+ str[fracIdx] = '.'
354+ fracIdx++
355+ for ; digitsFrac > 0; digitsFrac -= digitsPerWord {
356+ x := d.wordBuf[wordIdx]
357+ wordIdx++
358+ for i := myMin(digitsFrac, digitsPerWord); i > 0; i-- {
359+ y := x / digMask
360+ str[fracIdx] = byte(y) + '0'
361+ fracIdx++
362+ x -= y * digMask
363+ x *= 10
364+ }
365+ }
366+ for ; fill > 0; fill-- {
367+ str[fracIdx] = '0'
368+ fracIdx++
369+ }
370+ }
371+ fill = digitsIntLen - digitsInt
372+ if digitsInt == 0 {
373+ fill-- /* symbol 0 before digital point */
374+ }
375+ for ; fill > 0; fill-- {
376+ str[strIdx] = '0'
377+ strIdx++
378+ }
379+ if digitsInt > 0 {
380+ strIdx += digitsInt
381+ wordIdx := wordStartIdx + digitsToWords(digitsInt)
382+ for ; digitsInt > 0; digitsInt -= digitsPerWord {
383+ wordIdx--
384+ x := d.wordBuf[wordIdx]
385+ for i := myMin(digitsInt, digitsPerWord); i > 0; i-- {
386+ y := x / 10
387+ strIdx--
388+ str[strIdx] = '0' + byte(x-y*10)
389+ x = y
390+ }
391+ }
392+ } else {
393+ str[strIdx] = '0'
394+ }
395+ return
396+}
397+
398+// FromString parses decimal from string.
399+func (d *MyDecimal) FromString(str []byte) error {
400+ for i := 0; i < len(str); i++ {
401+ if !isSpace(str[i]) {
402+ str = str[i:]
403+ break
404+ }
405+ }
406+ if len(str) == 0 {
407+ *d = zeroMyDecimal
408+ return ErrBadNumber
409+ }
410+ switch str[0] {
411+ case '-':
412+ d.negative = true
413+ fallthrough
414+ case '+':
415+ str = str[1:]
416+ }
417+ var strIdx int
418+ for strIdx < len(str) && isDigit(str[strIdx]) {
419+ strIdx++
420+ }
421+ digitsInt := strIdx
422+ var digitsFrac int
423+ var endIdx int
424+ if strIdx < len(str) && str[strIdx] == '.' {
425+ endIdx = strIdx + 1
426+ for endIdx < len(str) && isDigit(str[endIdx]) {
427+ endIdx++
428+ }
429+ digitsFrac = endIdx - strIdx - 1
430+ } else {
431+ digitsFrac = 0
432+ endIdx = strIdx
433+ }
434+ if digitsInt+digitsFrac == 0 {
435+ *d = zeroMyDecimal
436+ return ErrBadNumber
437+ }
438+ wordsInt := digitsToWords(digitsInt)
439+ wordsFrac := digitsToWords(digitsFrac)
440+ wordsInt, wordsFrac, err := fixWordCntError(wordsInt, wordsFrac)
441+ if err != nil {
442+ digitsFrac = wordsFrac * digitsPerWord
443+ if err == ErrOverflow {
444+ digitsInt = wordsInt * digitsPerWord
445+ }
446+ }
447+ d.digitsInt = int8(digitsInt)
448+ d.digitsFrac = int8(digitsFrac)
449+ wordIdx := wordsInt
450+ strIdxTmp := strIdx
451+ var word int32
452+ var innerIdx int
453+ for digitsInt > 0 {
454+ digitsInt--
455+ strIdx--
456+ word += int32(str[strIdx]-'0') * powers10[innerIdx]
457+ innerIdx++
458+ if innerIdx == digitsPerWord {
459+ wordIdx--
460+ d.wordBuf[wordIdx] = word
461+ word = 0
462+ innerIdx = 0
463+ }
464+ }
465+ if innerIdx != 0 {
466+ wordIdx--
467+ d.wordBuf[wordIdx] = word
468+ }
469+
470+ wordIdx = wordsInt
471+ strIdx = strIdxTmp
472+ word = 0
473+ innerIdx = 0
474+ for digitsFrac > 0 {
475+ digitsFrac--
476+ strIdx++
477+ word = int32(str[strIdx]-'0') + word*10
478+ innerIdx++
479+ if innerIdx == digitsPerWord {
480+ d.wordBuf[wordIdx] = word
481+ wordIdx++
482+ word = 0
483+ innerIdx = 0
484+ }
485+ }
486+ if innerIdx != 0 {
487+ d.wordBuf[wordIdx] = word * powers10[digitsPerWord-innerIdx]
488+ }
489+ if endIdx+1 <= len(str) && (str[endIdx] == 'e' || str[endIdx] == 'E') {
490+ exponent, err1 := strToInt(string(str[endIdx+1:]))
491+ if err1 != nil {
492+ err = err1
493+ if err != ErrTruncated {
494+ *d = zeroMyDecimal
495+ }
496+ }
497+ if exponent > math.MaxInt32/2 {
498+ negative := d.negative
499+ maxDecimal(wordBufLen*digitsPerWord, 0, d)
500+ d.negative = negative
501+ err = ErrOverflow
502+ }
503+ if exponent < math.MinInt32/2 && err != ErrOverflow {
504+ *d = zeroMyDecimal
505+ err = ErrTruncated
506+ }
507+ if err != ErrOverflow {
508+ shiftErr := d.Shift(int(exponent))
509+ if shiftErr != nil {
510+ if shiftErr == ErrOverflow {
511+ negative := d.negative
512+ maxDecimal(wordBufLen*digitsPerWord, 0, d)
513+ d.negative = negative
514+ }
515+ err = shiftErr
516+ }
517+ }
518+ }
519+ allZero := true
520+ for i := 0; i < wordBufLen; i++ {
521+ if d.wordBuf[i] != 0 {
522+ allZero = false
523+ break
524+ }
525+ }
526+ if allZero {
527+ d.negative = false
528+ }
529+ d.resultFrac = d.digitsFrac
530+ return err
531+}
532+
533+// Shift shifts decimal digits in given number (with rounding if it need), shift > 0 means shift to left shift,
534+// shift < 0 means right shift. In fact it is multiplying on 10^shift.
535+//
536+// RETURN
537+// eDecOK OK
538+// eDecOverflow operation lead to overflow, number is untoched
539+// eDecTruncated number was rounded to fit into buffer
540+//
541+func (d *MyDecimal) Shift(shift int) error {
542+ var err error
543+ if shift == 0 {
544+ return nil
545+ }
546+ var (
547+ // digitBegin is index of first non zero digit (all indexes from 0).
548+ digitBegin int
549+ // digitEnd is index of position after last decimal digit.
550+ digitEnd int
551+ // point is index of digit position just after point.
552+ point = digitsToWords(int(d.digitsInt)) * digitsPerWord
553+ // new point position.
554+ newPoint = point + shift
555+ // number of digits in result.
556+ digitsInt, digitsFrac int
557+ newFront int
558+ )
559+ digitBegin, digitEnd = d.digitBounds()
560+ if digitBegin == digitEnd {
561+ *d = zeroMyDecimal
562+ return nil
563+ }
564+
565+ digitsInt = newPoint - digitBegin
566+ if digitsInt < 0 {
567+ digitsInt = 0
568+ }
569+ digitsFrac = digitEnd - newPoint
570+ if digitsFrac < 0 {
571+ digitsFrac = 0
572+ }
573+ wordsInt := digitsToWords(digitsInt)
574+ wordsFrac := digitsToWords(digitsFrac)
575+ newLen := wordsInt + wordsFrac
576+ if newLen > wordBufLen {
577+ lack := newLen - wordBufLen
578+ if wordsFrac < lack {
579+ return ErrOverflow
580+ }
581+ /* cut off fraction part to allow new number to fit in our buffer */
582+ err = ErrTruncated
583+ wordsFrac -= lack
584+ diff := digitsFrac - wordsFrac*digitsPerWord
585+ err1 := d.Round(d, digitEnd-point-diff, ModeHalfEven)
586+ if err1 != nil {
587+ return err1
588+ }
589+ digitEnd -= diff
590+ digitsFrac = wordsFrac * digitsPerWord
591+ if digitEnd <= digitBegin {
592+ /*
593+ We lost all digits (they will be shifted out of buffer), so we can
594+ just return 0.
595+ */
596+ *d = zeroMyDecimal
597+ return ErrTruncated
598+ }
599+ }
600+
601+ if shift%digitsPerWord != 0 {
602+ var lMiniShift, rMiniShift, miniShift int
603+ var doLeft bool
604+ /*
605+ Calculate left/right shift to align decimal digits inside our bug
606+ digits correctly.
607+ */
608+ if shift > 0 {
609+ lMiniShift = shift % digitsPerWord
610+ rMiniShift = digitsPerWord - lMiniShift
611+ doLeft = lMiniShift <= digitBegin
612+ } else {
613+ rMiniShift = (-shift) % digitsPerWord
614+ lMiniShift = digitsPerWord - rMiniShift
615+ doLeft = (digitsPerWord*wordBufLen - digitEnd) < rMiniShift
616+ }
617+ if doLeft {
618+ d.doMiniLeftShift(lMiniShift, digitBegin, digitEnd)
619+ miniShift = -lMiniShift
620+ } else {
621+ d.doMiniRightShift(rMiniShift, digitBegin, digitEnd)
622+ miniShift = rMiniShift
623+ }
624+ newPoint += miniShift
625+ /*
626+ If number is shifted and correctly aligned in buffer we can finish.
627+ */
628+ if shift+miniShift == 0 && (newPoint-digitsInt) < digitsPerWord {
629+ d.digitsInt = int8(digitsInt)
630+ d.digitsFrac = int8(digitsFrac)
631+ return err /* already shifted as it should be */
632+ }
633+ digitBegin += miniShift
634+ digitEnd += miniShift
635+ }
636+
637+ /* if new 'decimal front' is in first digit, we do not need move digits */
638+ newFront = newPoint - digitsInt
639+ if newFront >= digitsPerWord || newFront < 0 {
640+ /* need to move digits */
641+ var wordShift int
642+ if newFront > 0 {
643+ /* move left */
644+ wordShift = newFront / digitsPerWord
645+ to := digitBegin/digitsPerWord - wordShift
646+ barier := (digitEnd-1)/digitsPerWord - wordShift
647+ for ; to <= barier; to++ {
648+ d.wordBuf[to] = d.wordBuf[to+wordShift]
649+ }
650+ for barier += wordShift; to <= barier; to++ {
651+ d.wordBuf[to] = 0
652+ }
653+ wordShift = -wordShift
654+ } else {
655+ /* move right */
656+ wordShift = (1 - newFront) / digitsPerWord
657+ to := (digitEnd-1)/digitsPerWord + wordShift
658+ barier := digitBegin/digitsPerWord + wordShift
659+ for ; to >= barier; to-- {
660+ d.wordBuf[to] = d.wordBuf[to-wordShift]
661+ }
662+ for barier -= wordShift; to >= barier; to-- {
663+ d.wordBuf[to] = 0
664+ }
665+ }
666+ digitShift := wordShift * digitsPerWord
667+ digitBegin += digitShift
668+ digitEnd += digitShift
669+ newPoint += digitShift
670+ }
671+ /*
672+ If there are gaps then fill them with 0.
673+
674+ Only one of following 'for' loops will work because wordIdxBegin <= wordIdxEnd.
675+ */
676+ wordIdxBegin := digitBegin / digitsPerWord
677+ wordIdxEnd := (digitEnd - 1) / digitsPerWord
678+ wordIdxNewPoint := 0
679+
680+ /* We don't want negative new_point below */
681+ if newPoint != 0 {
682+ wordIdxNewPoint = (newPoint - 1) / digitsPerWord
683+ }
684+ if wordIdxNewPoint > wordIdxEnd {
685+ for wordIdxNewPoint > wordIdxEnd {
686+ d.wordBuf[wordIdxNewPoint] = 0
687+ wordIdxNewPoint--
688+ }
689+ } else {
690+ for ; wordIdxNewPoint < wordIdxBegin; wordIdxNewPoint++ {
691+ d.wordBuf[wordIdxNewPoint] = 0
692+ }
693+ }
694+ d.digitsInt = int8(digitsInt)
695+ d.digitsFrac = int8(digitsFrac)
696+ return err
697+}
698+
699+/*
700+ digitBounds returns bounds of decimal digits in the number.
701+
702+ start - index (from 0 ) of first decimal digits.
703+ end - index of position just after last decimal digit.
704+*/
705+func (d *MyDecimal) digitBounds() (start, end int) {
706+ var i int
707+ bufBeg := 0
708+ bufLen := digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))
709+ bufEnd := bufLen - 1
710+
711+ /* find non-zero digit from number beginning */
712+ for bufBeg < bufLen && d.wordBuf[bufBeg] == 0 {
713+ bufBeg++
714+ }
715+ if bufBeg >= bufLen {
716+ return 0, 0
717+ }
718+
719+ /* find non-zero decimal digit from number beginning */
720+ if bufBeg == 0 && d.digitsInt > 0 {
721+ i = (int(d.digitsInt) - 1) % digitsPerWord
722+ start = digitsPerWord - i - 1
723+ } else {
724+ i = digitsPerWord - 1
725+ start = bufBeg * digitsPerWord
726+ }
727+ if bufBeg < bufLen {
728+ start += countLeadingZeroes(i, d.wordBuf[bufBeg])
729+ }
730+
731+ /* find non-zero digit at the end */
732+ for bufEnd > bufBeg && d.wordBuf[bufEnd] == 0 {
733+ bufEnd--
734+ }
735+ /* find non-zero decimal digit from the end */
736+ if bufEnd == bufLen-1 && d.digitsFrac > 0 {
737+ i = (int(d.digitsFrac)-1)%digitsPerWord + 1
738+ end = bufEnd*digitsPerWord + i
739+ i = digitsPerWord - i + 1
740+ } else {
741+ end = (bufEnd + 1) * digitsPerWord
742+ i = 1
743+ }
744+ end -= countTrailingZeroes(i, d.wordBuf[bufEnd])
745+ return start, end
746+}
747+
748+/*
749+ doMiniLeftShift does left shift for alignment of data in buffer.
750+
751+ shift number of decimal digits on which it should be shifted
752+ beg/end bounds of decimal digits (see digitsBounds())
753+
754+ NOTE
755+ Result fitting in the buffer should be garanted.
756+ 'shift' have to be from 1 to digitsPerWord-1 (inclusive)
757+*/
758+func (d *MyDecimal) doMiniLeftShift(shift, beg, end int) {
759+ bufFrom := beg / digitsPerWord
760+ bufEnd := (end - 1) / digitsPerWord
761+ cShift := digitsPerWord - shift
762+ if beg%digitsPerWord < shift {
763+ d.wordBuf[bufFrom-1] = d.wordBuf[bufFrom] / powers10[cShift]
764+ }
765+ for bufFrom < bufEnd {
766+ d.wordBuf[bufFrom] = (d.wordBuf[bufFrom]%powers10[cShift])*powers10[shift] + d.wordBuf[bufFrom+1]/powers10[cShift]
767+ bufFrom++
768+ }
769+ d.wordBuf[bufFrom] = (d.wordBuf[bufFrom] % powers10[cShift]) * powers10[shift]
770+}
771+
772+/*
773+ doMiniRightShift does right shift for alignment of data in buffer.
774+
775+ shift number of decimal digits on which it should be shifted
776+ beg/end bounds of decimal digits (see digitsBounds())
777+
778+ NOTE
779+ Result fitting in the buffer should be garanted.
780+ 'shift' have to be from 1 to digitsPerWord-1 (inclusive)
781+*/
782+func (d *MyDecimal) doMiniRightShift(shift, beg, end int) {
783+ bufFrom := (end - 1) / digitsPerWord
784+ bufEnd := beg / digitsPerWord
785+ cShift := digitsPerWord - shift
786+ if digitsPerWord-((end-1)%digitsPerWord+1) < shift {
787+ d.wordBuf[bufFrom+1] = (d.wordBuf[bufFrom] % powers10[shift]) * powers10[cShift]
788+ }
789+ for bufFrom > bufEnd {
790+ d.wordBuf[bufFrom] = d.wordBuf[bufFrom]/powers10[shift] + (d.wordBuf[bufFrom-1]%powers10[shift])*powers10[cShift]
791+ bufFrom--
792+ }
793+ d.wordBuf[bufFrom] = d.wordBuf[bufFrom] / powers10[shift]
794+}
795+
796+// Round rounds the decimal to "frac" digits.
797+//
798+// to - result buffer. d == to is allowed
799+// frac - to what position after fraction point to round. can be negative!
800+// roundMode - round to nearest even or truncate
801+// ModeHalfEven rounds normally.
802+// Truncate just truncates the decimal.
803+//
804+// NOTES
805+// scale can be negative !
806+// one TRUNCATED error (line XXX below) isn't treated very logical :(
807+//
808+// RETURN VALUE
809+// eDecOK/eDecTruncated
810+func (d *MyDecimal) Round(to *MyDecimal, frac int, roundMode RoundMode) (err error) {
811+ // wordsFracTo is the number of fraction words in buffer.
812+ wordsFracTo := (frac + 1) / digitsPerWord
813+ if frac > 0 {
814+ wordsFracTo = digitsToWords(frac)
815+ }
816+ wordsFrac := digitsToWords(int(d.digitsFrac))
817+ wordsInt := digitsToWords(int(d.digitsInt))
818+
819+ roundDigit := int32(roundMode)
820+ /* TODO - fix this code as it won't work for CEILING mode */
821+
822+ if wordsInt+wordsFracTo > wordBufLen {
823+ wordsFracTo = wordBufLen - wordsInt
824+ frac = wordsFracTo * digitsPerWord
825+ err = ErrTruncated
826+ }
827+ if int(d.digitsInt)+frac < 0 {
828+ *to = zeroMyDecimal
829+ return nil
830+ }
831+ if to != d {
832+ copy(to.wordBuf[:], d.wordBuf[:])
833+ to.negative = d.negative
834+ to.digitsInt = int8(myMin(wordsInt, wordBufLen) * digitsPerWord)
835+ }
836+ if wordsFracTo > wordsFrac {
837+ idx := wordsInt + wordsFrac
838+ for wordsFracTo > wordsFrac {
839+ wordsFracTo--
840+ to.wordBuf[idx] = 0
841+ idx++
842+ }
843+ to.digitsFrac = int8(frac)
844+ to.resultFrac = to.digitsFrac
845+ return
846+ }
847+ if frac >= int(d.digitsFrac) {
848+ to.digitsFrac = int8(frac)
849+ to.resultFrac = to.digitsFrac
850+ return
851+ }
852+
853+ // Do increment.
854+ toIdx := wordsInt + wordsFracTo - 1
855+ if frac == wordsFracTo*digitsPerWord {
856+ doInc := false
857+ switch roundMode {
858+ // Notice: No support for ceiling mode now.
859+ case modeCeiling:
860+ // If any word after scale is not zero, do increment.
861+ // e.g ceiling 3.0001 to scale 1, gets 3.1
862+ idx := toIdx + (wordsFrac - wordsFracTo)
863+ for idx > toIdx {
864+ if d.wordBuf[idx] != 0 {
865+ doInc = true
866+ break
867+ }
868+ idx--
869+ }
870+ case ModeHalfEven:
871+ digAfterScale := d.wordBuf[toIdx+1] / digMask // the first digit after scale.
872+ // If first digit after scale is 5 and round even, do increment if digit at scale is odd.
873+ doInc = (digAfterScale > 5) || (digAfterScale == 5)
874+ case ModeTruncate:
875+ // Never round, just truncate.
876+ doInc = false
877+ }
878+ if doInc {
879+ if toIdx >= 0 {
880+ to.wordBuf[toIdx]++
881+ } else {
882+ toIdx++
883+ to.wordBuf[toIdx] = wordBase
884+ }
885+ } else if wordsInt+wordsFracTo == 0 {
886+ *to = zeroMyDecimal
887+ return nil
888+ }
889+ } else {
890+ /* TODO - fix this code as it won't work for CEILING mode */
891+ pos := wordsFracTo*digitsPerWord - frac - 1
892+ shiftedNumber := to.wordBuf[toIdx] / powers10[pos]
893+ digAfterScale := shiftedNumber % 10
894+ if digAfterScale > roundDigit || (roundDigit == 5 && digAfterScale == 5) {
895+ shiftedNumber += 10
896+ }
897+ to.wordBuf[toIdx] = powers10[pos] * (shiftedNumber - digAfterScale)
898+ }
899+ /*
900+ In case we're rounding e.g. 1.5e9 to 2.0e9, the decimal words inside
901+ the buffer are as follows.
902+
903+ Before <1, 5e8>
904+ After <2, 5e8>
905+
906+ Hence we need to set the 2nd field to 0.
907+ The same holds if we round 1.5e-9 to 2e-9.
908+ */
909+ if wordsFracTo < wordsFrac {
910+ idx := wordsInt + wordsFracTo
911+ if frac == 0 && wordsInt == 0 {
912+ idx = 1
913+ }
914+ for idx < wordBufLen {
915+ to.wordBuf[idx] = 0
916+ idx++
917+ }
918+ }
919+
920+ // Handle carry.
921+ var carry int32
922+ if to.wordBuf[toIdx] >= wordBase {
923+ carry = 1
924+ to.wordBuf[toIdx] -= wordBase
925+ for carry == 1 && toIdx > 0 {
926+ toIdx--
927+ to.wordBuf[toIdx], carry = add(to.wordBuf[toIdx], 0, carry)
928+ }
929+ if carry > 0 {
930+ if wordsInt+wordsFracTo >= wordBufLen {
931+ wordsFracTo--
932+ frac = wordsFracTo * digitsPerWord
933+ err = ErrTruncated
934+ }
935+ for toIdx = wordsInt + myMax(wordsFracTo, 0); toIdx > 0; toIdx-- {
936+ if toIdx < wordBufLen {
937+ to.wordBuf[toIdx] = to.wordBuf[toIdx-1]
938+ } else {
939+ err = ErrOverflow
940+ }
941+ }
942+ to.wordBuf[toIdx] = 1
943+ /* We cannot have more than 9 * 9 = 81 digits. */
944+ if int(to.digitsInt) < digitsPerWord*wordBufLen {
945+ to.digitsInt++
946+ } else {
947+ err = ErrOverflow
948+ }
949+ }
950+ } else {
951+ for {
952+ if to.wordBuf[toIdx] != 0 {
953+ break
954+ }
955+ if toIdx == 0 {
956+ /* making 'zero' with the proper scale */
957+ idx := wordsFracTo + 1
958+ to.digitsInt = 1
959+ to.digitsFrac = int8(myMax(frac, 0))
960+ to.negative = false
961+ for toIdx < idx {
962+ to.wordBuf[toIdx] = 0
963+ toIdx++
964+ }
965+ to.resultFrac = to.digitsFrac
966+ return nil
967+ }
968+ toIdx--
969+ }
970+ }
971+ /* Here we check 999.9 -> 1000 case when we need to increase intDigCnt */
972+ firstDig := mod9[to.digitsInt]
973+ if firstDig > 0 && to.wordBuf[toIdx] >= powers10[firstDig] {
974+ to.digitsInt++
975+ }
976+ if frac < 0 {
977+ frac = 0
978+ }
979+ to.digitsFrac = int8(frac)
980+ to.resultFrac = to.digitsFrac
981+ return
982+}
983+
984+// FromInt sets the decimal value from int64.
985+func (d *MyDecimal) FromInt(val int64) *MyDecimal {
986+ var uVal uint64
987+ if val < 0 {
988+ d.negative = true
989+ uVal = uint64(-val)
990+ } else {
991+ uVal = uint64(val)
992+ }
993+ return d.FromUint(uVal)
994+}
995+
996+// FromUint sets the decimal value from uint64.
997+func (d *MyDecimal) FromUint(val uint64) *MyDecimal {
998+ x := val
999+ wordIdx := 1
1000+ for x >= wordBase {
1001+ wordIdx++
1002+ x /= wordBase
1003+ }
1004+ d.digitsFrac = 0
1005+ d.digitsInt = int8(wordIdx * digitsPerWord)
1006+ x = val
1007+ for wordIdx > 0 {
1008+ wordIdx--
1009+ y := x / wordBase
1010+ d.wordBuf[wordIdx] = int32(x - y*wordBase)
1011+ x = y
1012+ }
1013+ return d
1014+}
1015+
1016+// ToInt returns int part of the decimal, returns the result and errcode.
1017+func (d *MyDecimal) ToInt() (int64, error) {
1018+ var x int64
1019+ wordIdx := 0
1020+ for i := d.digitsInt; i > 0; i -= digitsPerWord {
1021+ y := x
1022+ /*
1023+ Attention: trick!
1024+ we're calculating -|from| instead of |from| here
1025+ because |LONGLONG_MIN| > LONGLONG_MAX
1026+ so we can convert -9223372036854775808 correctly
1027+ */
1028+ x = x*wordBase - int64(d.wordBuf[wordIdx])
1029+ wordIdx++
1030+ if y < math.MinInt64/wordBase || x > y {
1031+ /*
1032+ the decimal is bigger than any possible integer
1033+ return border integer depending on the sign
1034+ */
1035+ if d.negative {
1036+ return math.MinInt64, ErrOverflow
1037+ }
1038+ return math.MaxInt64, ErrOverflow
1039+ }
1040+ }
1041+ /* boundary case: 9223372036854775808 */
1042+ if !d.negative && x == math.MinInt64 {
1043+ return math.MaxInt64, ErrOverflow
1044+ }
1045+ if !d.negative {
1046+ x = -x
1047+ }
1048+ for i := d.digitsFrac; i > 0; i -= digitsPerWord {
1049+ if d.wordBuf[wordIdx] != 0 {
1050+ return x, ErrTruncated
1051+ }
1052+ wordIdx++
1053+ }
1054+ return x, nil
1055+}
1056+
1057+// ToUint returns int part of the decimal, returns the result and errcode.
1058+func (d *MyDecimal) ToUint() (uint64, error) {
1059+ if d.negative {
1060+ return 0, ErrOverflow
1061+ }
1062+ var x uint64
1063+ wordIdx := 0
1064+ for i := d.digitsInt; i > 0; i -= digitsPerWord {
1065+ y := x
1066+ x = x*wordBase + uint64(d.wordBuf[wordIdx])
1067+ wordIdx++
1068+ if y > math.MaxUint64/wordBase || x < y {
1069+ return math.MaxUint64, ErrOverflow
1070+ }
1071+ }
1072+ for i := d.digitsFrac; i > 0; i -= digitsPerWord {
1073+ if d.wordBuf[wordIdx] != 0 {
1074+ return x, ErrTruncated
1075+ }
1076+ wordIdx++
1077+ }
1078+ return x, nil
1079+}
1080+
1081+// FromFloat64 creates a decimal from float64 value.
1082+func (d *MyDecimal) FromFloat64(f float64) error {
1083+ s := strconv.FormatFloat(f, 'g', -1, 64)
1084+ return d.FromString([]byte(s))
1085+}
1086+
1087+// ToFloat64 converts decimal to float64 value.
1088+func (d *MyDecimal) ToFloat64() (float64, error) {
1089+ f, err := strconv.ParseFloat(d.String(), 64)
1090+ if err != nil {
1091+ err = ErrOverflow
1092+ }
1093+ return f, err
1094+}
1095+
1096+/*
1097+ToBin converts decimal to its binary fixed-length representation
1098+two representations of the same length can be compared with memcmp
1099+with the correct -1/0/+1 result
1100+
1101+ PARAMS
1102+ precision/frac - if precision is 0, internal value of the decimal will be used,
1103+ then the encoded value is not memory comparable.
1104+
1105+ NOTE
1106+ the buffer is assumed to be of the size DecimalBinSize(precision, frac)
1107+
1108+ RETURN VALUE
1109+ bin - binary value
1110+ errCode - eDecOK/eDecTruncate/eDecOverflow
1111+
1112+ DESCRIPTION
1113+ for storage decimal numbers are converted to the "binary" format.
1114+
1115+ This format has the following properties:
1116+ 1. length of the binary representation depends on the {precision, frac}
1117+ as provided by the caller and NOT on the digitsInt/digitsFrac of the decimal to
1118+ convert.
1119+ 2. binary representations of the same {precision, frac} can be compared
1120+ with memcmp - with the same result as DecimalCompare() of the original
1121+ decimals (not taking into account possible precision loss during
1122+ conversion).
1123+
1124+ This binary format is as follows:
1125+ 1. First the number is converted to have a requested precision and frac.
1126+ 2. Every full digitsPerWord digits of digitsInt part are stored in 4 bytes
1127+ as is
1128+ 3. The first digitsInt % digitesPerWord digits are stored in the reduced
1129+ number of bytes (enough bytes to store this number of digits -
1130+ see dig2bytes)
1131+ 4. same for frac - full word are stored as is,
1132+ the last frac % digitsPerWord digits - in the reduced number of bytes.
1133+ 5. If the number is negative - every byte is inversed.
1134+ 5. The very first bit of the resulting byte array is inverted (because
1135+ memcmp compares unsigned bytes, see property 2 above)
1136+
1137+ Example:
1138+
1139+ 1234567890.1234
1140+
1141+ internally is represented as 3 words
1142+
1143+ 1 234567890 123400000
1144+
1145+ (assuming we want a binary representation with precision=14, frac=4)
1146+ in hex it's
1147+
1148+ 00-00-00-01 0D-FB-38-D2 07-5A-EF-40
1149+
1150+ now, middle word is full - it stores 9 decimal digits. It goes
1151+ into binary representation as is:
1152+
1153+
1154+ ........... 0D-FB-38-D2 ............
1155+
1156+ First word has only one decimal digit. We can store one digit in
1157+ one byte, no need to waste four:
1158+
1159+ 01 0D-FB-38-D2 ............
1160+
1161+ now, last word. It's 123400000. We can store 1234 in two bytes:
1162+
1163+ 01 0D-FB-38-D2 04-D2
1164+
1165+ So, we've packed 12 bytes number in 7 bytes.
1166+ And now we invert the highest bit to get the final result:
1167+
1168+ 81 0D FB 38 D2 04 D2
1169+
1170+ And for -1234567890.1234 it would be
1171+
1172+ 7E F2 04 C7 2D FB 2D
1173+*/
1174+func (d *MyDecimal) ToBin(precision, frac int) ([]byte, error) {
1175+ if precision > digitsPerWord*maxWordBufLen || precision < 0 || frac > MaxDecimalScale || frac < 0 {
1176+ return nil, ErrBadNumber
1177+ }
1178+ var err error
1179+ var mask int32
1180+ if d.negative {
1181+ mask = -1
1182+ }
1183+ digitsInt := precision - frac
1184+ wordsInt := digitsInt / digitsPerWord
1185+ leadingDigits := digitsInt - wordsInt*digitsPerWord
1186+ wordsFrac := frac / digitsPerWord
1187+ trailingDigits := frac - wordsFrac*digitsPerWord
1188+
1189+ wordsFracFrom := int(d.digitsFrac) / digitsPerWord
1190+ trailingDigitsFrom := int(d.digitsFrac) - wordsFracFrom*digitsPerWord
1191+ intSize := wordsInt*wordSize + dig2bytes[leadingDigits]
1192+ fracSize := wordsFrac*wordSize + dig2bytes[trailingDigits]
1193+ fracSizeFrom := wordsFracFrom*wordSize + dig2bytes[trailingDigitsFrom]
1194+ originIntSize := intSize
1195+ originFracSize := fracSize
1196+ bin := make([]byte, intSize+fracSize)
1197+ binIdx := 0
1198+ wordIdxFrom, digitsIntFrom := d.removeLeadingZeros()
1199+ if digitsIntFrom+fracSizeFrom == 0 {
1200+ mask = 0
1201+ digitsInt = 1
1202+ }
1203+
1204+ wordsIntFrom := digitsIntFrom / digitsPerWord
1205+ leadingDigitsFrom := digitsIntFrom - wordsIntFrom*digitsPerWord
1206+ iSizeFrom := wordsIntFrom*wordSize + dig2bytes[leadingDigitsFrom]
1207+
1208+ if digitsInt < digitsIntFrom {
1209+ wordIdxFrom += wordsIntFrom - wordsInt
1210+ if leadingDigitsFrom > 0 {
1211+ wordIdxFrom++
1212+ }
1213+ if leadingDigits > 0 {
1214+ wordIdxFrom--
1215+ }
1216+ wordsIntFrom = wordsInt
1217+ leadingDigitsFrom = leadingDigits
1218+ err = ErrOverflow
1219+ } else if intSize > iSizeFrom {
1220+ for intSize > iSizeFrom {
1221+ intSize--
1222+ bin[binIdx] = byte(mask)
1223+ binIdx++
1224+ }
1225+ }
1226+
1227+ if fracSize < fracSizeFrom {
1228+ wordsFracFrom = wordsFrac
1229+ trailingDigitsFrom = trailingDigits
1230+ err = ErrTruncated
1231+ } else if fracSize > fracSizeFrom && trailingDigitsFrom > 0 {
1232+ if wordsFrac == wordsFracFrom {
1233+ trailingDigitsFrom = trailingDigits
1234+ fracSize = fracSizeFrom
1235+ } else {
1236+ wordsFracFrom++
1237+ trailingDigitsFrom = 0
1238+ }
1239+ }
1240+ // xIntFrom part
1241+ if leadingDigitsFrom > 0 {
1242+ i := dig2bytes[leadingDigitsFrom]
1243+ x := (d.wordBuf[wordIdxFrom] % powers10[leadingDigitsFrom]) ^ mask
1244+ wordIdxFrom++
1245+ writeWord(bin[binIdx:], x, i)
1246+ binIdx += i
1247+ }
1248+
1249+ // wordsInt + wordsFrac part.
1250+ for stop := wordIdxFrom + wordsIntFrom + wordsFracFrom; wordIdxFrom < stop; binIdx += wordSize {
1251+ x := d.wordBuf[wordIdxFrom] ^ mask
1252+ wordIdxFrom++
1253+ writeWord(bin[binIdx:], x, 4)
1254+ }
1255+
1256+ // xFracFrom part
1257+ if trailingDigitsFrom > 0 {
1258+ var x int32
1259+ i := dig2bytes[trailingDigitsFrom]
1260+ lim := trailingDigits
1261+ if wordsFracFrom < wordsFrac {
1262+ lim = digitsPerWord
1263+ }
1264+
1265+ for trailingDigitsFrom < lim && dig2bytes[trailingDigitsFrom] == i {
1266+ trailingDigitsFrom++
1267+ }
1268+ x = (d.wordBuf[wordIdxFrom] / powers10[digitsPerWord-trailingDigitsFrom]) ^ mask
1269+ writeWord(bin[binIdx:], x, i)
1270+ binIdx += i
1271+ }
1272+ if fracSize > fracSizeFrom {
1273+ binIdxEnd := originIntSize + originFracSize
1274+ for fracSize > fracSizeFrom && binIdx < binIdxEnd {
1275+ fracSize--
1276+ bin[binIdx] = byte(mask)
1277+ binIdx++
1278+ }
1279+ }
1280+ bin[0] ^= 0x80
1281+ return bin, err
1282+}
1283+
1284+// ToHashKey removes the leading and trailing zeros and generates a hash key.
1285+// Two Decimals dec0 and dec1 with different fraction will generate the same hash keys if dec0.Compare(dec1) == 0.
1286+func (d *MyDecimal) ToHashKey() ([]byte, error) {
1287+ _, digitsInt := d.removeLeadingZeros()
1288+ _, digitsFrac := d.removeTrailingZeros()
1289+ prec := digitsInt + digitsFrac
1290+ if prec == 0 { // zeroDecimal
1291+ prec = 1
1292+ }
1293+ buf, err := d.ToBin(prec, digitsFrac)
1294+ if err == ErrTruncated {
1295+ // This err is caused by shorter digitsFrac;
1296+ // After removing the trailing zeros from a Decimal,
1297+ // so digitsFrac may be less than the real digitsFrac of the Decimal,
1298+ // thus ErrTruncated may be raised, we can ignore it here.
1299+ err = nil
1300+ }
1301+ return buf, err
1302+}
1303+
1304+// PrecisionAndFrac returns the internal precision and frac number.
1305+func (d *MyDecimal) PrecisionAndFrac() (precision, frac int) {
1306+ frac = int(d.digitsFrac)
1307+ _, digitsInt := d.removeLeadingZeros()
1308+ precision = digitsInt + frac
1309+ if precision == 0 {
1310+ precision = 1
1311+ }
1312+ return
1313+}
1314+
1315+// IsZero checks whether it's a zero decimal.
1316+func (d *MyDecimal) IsZero() bool {
1317+ isZero := true
1318+ for _, val := range d.wordBuf {
1319+ if val != 0 {
1320+ isZero = false
1321+ break
1322+ }
1323+ }
1324+ return isZero
1325+}
1326+
1327+// FromBin Restores decimal from its binary fixed-length representation.
1328+func (d *MyDecimal) FromBin(bin []byte, precision, frac int) (binSize int, err error) {
1329+ if len(bin) == 0 {
1330+ *d = zeroMyDecimal
1331+ return 0, ErrBadNumber
1332+ }
1333+ digitsInt := precision - frac
1334+ wordsInt := digitsInt / digitsPerWord
1335+ leadingDigits := digitsInt - wordsInt*digitsPerWord
1336+ wordsFrac := frac / digitsPerWord
1337+ trailingDigits := frac - wordsFrac*digitsPerWord
1338+ wordsIntTo := wordsInt
1339+ if leadingDigits > 0 {
1340+ wordsIntTo++
1341+ }
1342+ wordsFracTo := wordsFrac
1343+ if trailingDigits > 0 {
1344+ wordsFracTo++
1345+ }
1346+
1347+ binIdx := 0
1348+ mask := int32(-1)
1349+ if bin[binIdx]&0x80 > 0 {
1350+ mask = 0
1351+ }
1352+ binSize = DecimalBinSize(precision, frac)
1353+ dCopy := make([]byte, 40)
1354+ dCopy = dCopy[:binSize]
1355+ copy(dCopy, bin)
1356+ dCopy[0] ^= 0x80
1357+ bin = dCopy
1358+ oldWordsIntTo := wordsIntTo
1359+ wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
1360+ if err != nil {
1361+ if wordsIntTo < oldWordsIntTo {
1362+ binIdx += dig2bytes[leadingDigits] + (wordsInt-wordsIntTo)*wordSize
1363+ } else {
1364+ trailingDigits = 0
1365+ wordsFrac = wordsFracTo
1366+ }
1367+ }
1368+ d.negative = mask != 0
1369+ d.digitsInt = int8(wordsInt*digitsPerWord + leadingDigits)
1370+ d.digitsFrac = int8(wordsFrac*digitsPerWord + trailingDigits)
1371+
1372+ wordIdx := 0
1373+ if leadingDigits > 0 {
1374+ i := dig2bytes[leadingDigits]
1375+ x := readWord(bin[binIdx:], i)
1376+ binIdx += i
1377+ d.wordBuf[wordIdx] = x ^ mask
1378+ if uint64(d.wordBuf[wordIdx]) >= uint64(powers10[leadingDigits+1]) {
1379+ *d = zeroMyDecimal
1380+ return binSize, ErrBadNumber
1381+ }
1382+ if wordIdx > 0 || d.wordBuf[wordIdx] != 0 {
1383+ wordIdx++
1384+ } else {
1385+ d.digitsInt -= int8(leadingDigits)
1386+ }
1387+ }
1388+ for stop := binIdx + wordsInt*wordSize; binIdx < stop; binIdx += wordSize {
1389+ d.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask
1390+ if uint32(d.wordBuf[wordIdx]) > wordMax {
1391+ *d = zeroMyDecimal
1392+ return binSize, ErrBadNumber
1393+ }
1394+ if wordIdx > 0 || d.wordBuf[wordIdx] != 0 {
1395+ wordIdx++
1396+ } else {
1397+ d.digitsInt -= digitsPerWord
1398+ }
1399+ }
1400+
1401+ for stop := binIdx + wordsFrac*wordSize; binIdx < stop; binIdx += wordSize {
1402+ d.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask
1403+ if uint32(d.wordBuf[wordIdx]) > wordMax {
1404+ *d = zeroMyDecimal
1405+ return binSize, ErrBadNumber
1406+ }
1407+ wordIdx++
1408+ }
1409+
1410+ if trailingDigits > 0 {
1411+ i := dig2bytes[trailingDigits]
1412+ x := readWord(bin[binIdx:], i)
1413+ d.wordBuf[wordIdx] = (x ^ mask) * powers10[digitsPerWord-trailingDigits]
1414+ if uint32(d.wordBuf[wordIdx]) > wordMax {
1415+ *d = zeroMyDecimal
1416+ return binSize, ErrBadNumber
1417+ }
1418+ }
1419+
1420+ if d.digitsInt == 0 && d.digitsFrac == 0 {
1421+ *d = zeroMyDecimal
1422+ }
1423+ d.resultFrac = int8(frac)
1424+ return binSize, err
1425+}
1426+
1427+// DecimalBinSize returns the size of array to hold a binary representation of a decimal.
1428+func DecimalBinSize(precision, frac int) int {
1429+ digitsInt := precision - frac
1430+ wordsInt := digitsInt / digitsPerWord
1431+ wordsFrac := frac / digitsPerWord
1432+ xInt := digitsInt - wordsInt*digitsPerWord
1433+ xFrac := frac - wordsFrac*digitsPerWord
1434+ return wordsInt*wordSize + dig2bytes[xInt] + wordsFrac*wordSize + dig2bytes[xFrac]
1435+}
1436+
1437+func readWord(b []byte, size int) int32 {
1438+ var x int32
1439+ switch size {
1440+ case 1:
1441+ x = int32(int8(b[0]))
1442+ case 2:
1443+ x = int32(int8(b[0]))<<8 + int32(b[1])
1444+ case 3:
1445+ if b[0]&128 > 0 {
1446+ x = int32(uint32(255)<<24 | uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
1447+ } else {
1448+ x = int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
1449+ }
1450+ case 4:
1451+ x = int32(b[3]) + int32(b[2])<<8 + int32(b[1])<<16 + int32(int8(b[0]))<<24
1452+ }
1453+ return x
1454+}
1455+
1456+func writeWord(b []byte, word int32, size int) {
1457+ v := uint32(word)
1458+ switch size {
1459+ case 1:
1460+ b[0] = byte(word)
1461+ case 2:
1462+ b[0] = byte(v >> 8)
1463+ b[1] = byte(v)
1464+ case 3:
1465+ b[0] = byte(v >> 16)
1466+ b[1] = byte(v >> 8)
1467+ b[2] = byte(v)
1468+ case 4:
1469+ b[0] = byte(v >> 24)
1470+ b[1] = byte(v >> 16)
1471+ b[2] = byte(v >> 8)
1472+ b[3] = byte(v)
1473+ }
1474+}
1475+
1476+// Compare compares one decimal to another, returns -1/0/1.
1477+func (d *MyDecimal) Compare(to *MyDecimal) int {
1478+ if d.negative == to.negative {
1479+ cmp, err := doSub(d, to, nil)
1480+ Log(err)
1481+ return cmp
1482+ }
1483+ if d.negative {
1484+ return -1
1485+ }
1486+ return 1
1487+}
1488+
1489+// DecimalNeg reverses decimal's sign.
1490+func DecimalNeg(from *MyDecimal) *MyDecimal {
1491+ to := *from
1492+ if from.IsZero() {
1493+ return &to
1494+ }
1495+ to.negative = !from.negative
1496+ return &to
1497+}
1498+
1499+// DecimalAdd adds two decimals, sets the result to 'to'.
1500+// Note: DO NOT use `from1` or `from2` as `to` since the metadata
1501+// of `to` may be changed during evaluating.
1502+func DecimalAdd(from1, from2, to *MyDecimal) error {
1503+ from1, from2, to = validateArgs(from1, from2, to)
1504+ to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
1505+ if from1.negative == from2.negative {
1506+ return doAdd(from1, from2, to)
1507+ }
1508+ _, err := doSub(from1, from2, to)
1509+ return err
1510+}
1511+
1512+// DecimalSub subs one decimal from another, sets the result to 'to'.
1513+func DecimalSub(from1, from2, to *MyDecimal) error {
1514+ from1, from2, to = validateArgs(from1, from2, to)
1515+ to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
1516+ if from1.negative == from2.negative {
1517+ _, err := doSub(from1, from2, to)
1518+ return err
1519+ }
1520+ return doAdd(from1, from2, to)
1521+}
1522+
1523+func validateArgs(f1, f2, to *MyDecimal) (*MyDecimal, *MyDecimal, *MyDecimal) {
1524+ if to == nil {
1525+ return f1, f2, to
1526+ }
1527+ if f1 == to {
1528+ tmp := *f1
1529+ f1 = &tmp
1530+ }
1531+ if f2 == to {
1532+ tmp := *f2
1533+ f2 = &tmp
1534+ }
1535+ to.digitsFrac = 0
1536+ to.digitsInt = 0
1537+ to.resultFrac = 0
1538+ to.negative = false
1539+ for i := range to.wordBuf {
1540+ to.wordBuf[i] = 0
1541+ }
1542+ return f1, f2, to
1543+}
1544+
1545+func doSub(from1, from2, to *MyDecimal) (cmp int, err error) {
1546+ var (
1547+ wordsInt1 = digitsToWords(int(from1.digitsInt))
1548+ wordsFrac1 = digitsToWords(int(from1.digitsFrac))
1549+ wordsInt2 = digitsToWords(int(from2.digitsInt))
1550+ wordsFrac2 = digitsToWords(int(from2.digitsFrac))
1551+ wordsFracTo = myMax(wordsFrac1, wordsFrac2)
1552+
1553+ start1 = 0
1554+ stop1 = wordsInt1
1555+ idx1 = 0
1556+ start2 = 0
1557+ stop2 = wordsInt2
1558+ idx2 = 0
1559+ )
1560+ if from1.wordBuf[idx1] == 0 {
1561+ for idx1 < stop1 && from1.wordBuf[idx1] == 0 {
1562+ idx1++
1563+ }
1564+ start1 = idx1
1565+ wordsInt1 = stop1 - idx1
1566+ }
1567+ if from2.wordBuf[idx2] == 0 {
1568+ for idx2 < stop2 && from2.wordBuf[idx2] == 0 {
1569+ idx2++
1570+ }
1571+ start2 = idx2
1572+ wordsInt2 = stop2 - idx2
1573+ }
1574+
1575+ var carry int32
1576+ if wordsInt2 > wordsInt1 {
1577+ carry = 1
1578+ } else if wordsInt2 == wordsInt1 {
1579+ end1 := stop1 + wordsFrac1 - 1
1580+ end2 := stop2 + wordsFrac2 - 1
1581+ for idx1 <= end1 && from1.wordBuf[end1] == 0 {
1582+ end1--
1583+ }
1584+ for idx2 <= end2 && from2.wordBuf[end2] == 0 {
1585+ end2--
1586+ }
1587+ wordsFrac1 = end1 - stop1 + 1
1588+ wordsFrac2 = end2 - stop2 + 1
1589+ for idx1 <= end1 && idx2 <= end2 && from1.wordBuf[idx1] == from2.wordBuf[idx2] {
1590+ idx1++
1591+ idx2++
1592+ }
1593+ if idx1 <= end1 {
1594+ if idx2 <= end2 && from2.wordBuf[idx2] > from1.wordBuf[idx1] {
1595+ carry = 1
1596+ } else {
1597+ carry = 0
1598+ }
1599+ } else {
1600+ if idx2 <= end2 {
1601+ carry = 1
1602+ } else {
1603+ if to == nil {
1604+ return 0, nil
1605+ }
1606+ *to = zeroMyDecimalWithFrac(to.resultFrac)
1607+ return 0, nil
1608+ }
1609+ }
1610+ }
1611+
1612+ if to == nil {
1613+ if carry > 0 == from1.negative { // from2 is negative too.
1614+ return 1, nil
1615+ }
1616+ return -1, nil
1617+ }
1618+
1619+ to.negative = from1.negative
1620+
1621+ /* ensure that always idx1 > idx2 (and wordsInt1 >= wordsInt2) */
1622+ if carry > 0 {
1623+ from1, from2 = from2, from1
1624+ start1, start2 = start2, start1
1625+ wordsInt1, wordsInt2 = wordsInt2, wordsInt1
1626+ wordsFrac1, wordsFrac2 = wordsFrac2, wordsFrac1
1627+ to.negative = !to.negative
1628+ }
1629+
1630+ wordsInt1, wordsFracTo, err = fixWordCntError(wordsInt1, wordsFracTo)
1631+ idxTo := wordsInt1 + wordsFracTo
1632+ to.digitsFrac = from1.digitsFrac
1633+ if to.digitsFrac < from2.digitsFrac {
1634+ to.digitsFrac = from2.digitsFrac
1635+ }
1636+ to.digitsInt = int8(wordsInt1 * digitsPerWord)
1637+ if err != nil {
1638+ if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
1639+ to.digitsFrac = int8(wordsFracTo * digitsPerWord)
1640+ }
1641+ if wordsFrac1 > wordsFracTo {
1642+ wordsFrac1 = wordsFracTo
1643+ }
1644+ if wordsFrac2 > wordsFracTo {
1645+ wordsFrac2 = wordsFracTo
1646+ }
1647+ if wordsInt2 > wordsInt1 {
1648+ wordsInt2 = wordsInt1
1649+ }
1650+ }
1651+ carry = 0
1652+
1653+ /* part 1 - max(frac) ... min (frac) */
1654+ if wordsFrac1 > wordsFrac2 {
1655+ idx1 = start1 + wordsInt1 + wordsFrac1
1656+ stop1 = start1 + wordsInt1 + wordsFrac2
1657+ idx2 = start2 + wordsInt2 + wordsFrac2
1658+ for wordsFracTo > wordsFrac1 {
1659+ wordsFracTo--
1660+ idxTo--
1661+ to.wordBuf[idxTo] = 0
1662+ }
1663+ for idx1 > stop1 {
1664+ idxTo--
1665+ idx1--
1666+ to.wordBuf[idxTo] = from1.wordBuf[idx1]
1667+ }
1668+ } else {
1669+ idx1 = start1 + wordsInt1 + wordsFrac1
1670+ idx2 = start2 + wordsInt2 + wordsFrac2
1671+ stop2 = start2 + wordsInt2 + wordsFrac1
1672+ for wordsFracTo > wordsFrac2 {
1673+ wordsFracTo--
1674+ idxTo--
1675+ to.wordBuf[idxTo] = 0
1676+ }
1677+ for idx2 > stop2 {
1678+ idxTo--
1679+ idx2--
1680+ to.wordBuf[idxTo], carry = sub(0, from2.wordBuf[idx2], carry)
1681+ }
1682+ }
1683+
1684+ /* part 2 - min(frac) ... wordsInt2 */
1685+ for idx2 > start2 {
1686+ idxTo--
1687+ idx1--
1688+ idx2--
1689+ to.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], from2.wordBuf[idx2], carry)
1690+ }
1691+
1692+ /* part 3 - wordsInt2 ... wordsInt1 */
1693+ for carry > 0 && idx1 > start1 {
1694+ idxTo--
1695+ idx1--
1696+ to.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], 0, carry)
1697+ }
1698+ for idx1 > start1 {
1699+ idxTo--
1700+ idx1--
1701+ to.wordBuf[idxTo] = from1.wordBuf[idx1]
1702+ }
1703+ for idxTo > 0 {
1704+ idxTo--
1705+ to.wordBuf[idxTo] = 0
1706+ }
1707+ return 0, err
1708+}
1709+
1710+func doAdd(from1, from2, to *MyDecimal) error {
1711+ var (
1712+ err error
1713+ wordsInt1 = digitsToWords(int(from1.digitsInt))
1714+ wordsFrac1 = digitsToWords(int(from1.digitsFrac))
1715+ wordsInt2 = digitsToWords(int(from2.digitsInt))
1716+ wordsFrac2 = digitsToWords(int(from2.digitsFrac))
1717+ wordsIntTo = myMax(wordsInt1, wordsInt2)
1718+ wordsFracTo = myMax(wordsFrac1, wordsFrac2)
1719+ )
1720+
1721+ var x int32
1722+ if wordsInt1 > wordsInt2 {
1723+ x = from1.wordBuf[0]
1724+ } else if wordsInt2 > wordsInt1 {
1725+ x = from2.wordBuf[0]
1726+ } else {
1727+ x = from1.wordBuf[0] + from2.wordBuf[0]
1728+ }
1729+ if x > wordMax-1 { /* yes, there is */
1730+ wordsIntTo++
1731+ to.wordBuf[0] = 0 /* safety */
1732+ }
1733+
1734+ wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
1735+ if err == ErrOverflow {
1736+ maxDecimal(wordBufLen*digitsPerWord, 0, to)
1737+ return err
1738+ }
1739+ idxTo := wordsIntTo + wordsFracTo
1740+ to.negative = from1.negative
1741+ to.digitsInt = int8(wordsIntTo * digitsPerWord)
1742+ to.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)
1743+
1744+ if err != nil {
1745+ if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
1746+ to.digitsFrac = int8(wordsFracTo * digitsPerWord)
1747+ }
1748+ if wordsFrac1 > wordsFracTo {
1749+ wordsFrac1 = wordsFracTo
1750+ }
1751+ if wordsFrac2 > wordsFracTo {
1752+ wordsFrac2 = wordsFracTo
1753+ }
1754+ if wordsInt1 > wordsIntTo {
1755+ wordsInt1 = wordsIntTo
1756+ }
1757+ if wordsInt2 > wordsIntTo {
1758+ wordsInt2 = wordsIntTo
1759+ }
1760+ }
1761+ var dec1, dec2 = from1, from2
1762+ var idx1, idx2, stop, stop2 int
1763+ /* part 1 - max(frac) ... min (frac) */
1764+ if wordsFrac1 > wordsFrac2 {
1765+ idx1 = wordsInt1 + wordsFrac1
1766+ stop = wordsInt1 + wordsFrac2
1767+ idx2 = wordsInt2 + wordsFrac2
1768+ if wordsInt1 > wordsInt2 {
1769+ stop2 = wordsInt1 - wordsInt2
1770+ }
1771+ } else {
1772+ idx1 = wordsInt2 + wordsFrac2
1773+ stop = wordsInt2 + wordsFrac1
1774+ idx2 = wordsInt1 + wordsFrac1
1775+ if wordsInt2 > wordsInt1 {
1776+ stop2 = wordsInt2 - wordsInt1
1777+ }
1778+ dec1, dec2 = from2, from1
1779+ }
1780+ for idx1 > stop {
1781+ idxTo--
1782+ idx1--
1783+ to.wordBuf[idxTo] = dec1.wordBuf[idx1]
1784+ }
1785+
1786+ /* part 2 - min(frac) ... min(digitsInt) */
1787+ carry := int32(0)
1788+ for idx1 > stop2 {
1789+ idx1--
1790+ idx2--
1791+ idxTo--
1792+ to.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], dec2.wordBuf[idx2], carry)
1793+ }
1794+
1795+ /* part 3 - min(digitsInt) ... max(digitsInt) */
1796+ stop = 0
1797+ if wordsInt1 > wordsInt2 {
1798+ idx1 = wordsInt1 - wordsInt2
1799+ dec1 = from1
1800+ } else {
1801+ idx1 = wordsInt2 - wordsInt1
1802+ dec1 = from2
1803+ }
1804+ for idx1 > stop {
1805+ idxTo--
1806+ idx1--
1807+ to.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], 0, carry)
1808+ }
1809+ if carry > 0 {
1810+ idxTo--
1811+ to.wordBuf[idxTo] = 1
1812+ }
1813+ return err
1814+}
1815+
1816+func maxDecimal(precision, frac int, to *MyDecimal) {
1817+ digitsInt := precision - frac
1818+ to.negative = false
1819+ to.digitsInt = int8(digitsInt)
1820+ idx := 0
1821+ if digitsInt > 0 {
1822+ firstWordDigits := digitsInt % digitsPerWord
1823+ if firstWordDigits > 0 {
1824+ to.wordBuf[idx] = powers10[firstWordDigits] - 1 /* get 9 99 999 ... */
1825+ idx++
1826+ }
1827+ for digitsInt /= digitsPerWord; digitsInt > 0; digitsInt-- {
1828+ to.wordBuf[idx] = wordMax
1829+ idx++
1830+ }
1831+ }
1832+ to.digitsFrac = int8(frac)
1833+ if frac > 0 {
1834+ lastDigits := frac % digitsPerWord
1835+ for frac /= digitsPerWord; frac > 0; frac-- {
1836+ to.wordBuf[idx] = wordMax
1837+ idx++
1838+ }
1839+ if lastDigits > 0 {
1840+ to.wordBuf[idx] = fracMax[lastDigits-1]
1841+ }
1842+ }
1843+}
1844+
1845+/*
1846+DecimalMul multiplies two decimals.
1847+
1848+ from1, from2 - factors
1849+ to - product
1850+
1851+ RETURN VALUE
1852+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW;
1853+
1854+ NOTES
1855+ in this implementation, with wordSize=4 we have digitsPerWord=9,
1856+ and 63-digit number will take only 7 words (basically a 7-digit
1857+ "base 999999999" number). Thus there's no need in fast multiplication
1858+ algorithms, 7-digit numbers can be multiplied with a naive O(n*n)
1859+ method.
1860+
1861+ XXX if this library is to be used with huge numbers of thousands of
1862+ digits, fast multiplication must be implemented.
1863+*/
1864+func DecimalMul(from1, from2, to *MyDecimal) error {
1865+ from1, from2, to = validateArgs(from1, from2, to)
1866+ var (
1867+ err error
1868+ wordsInt1 = digitsToWords(int(from1.digitsInt))
1869+ wordsFrac1 = digitsToWords(int(from1.digitsFrac))
1870+ wordsInt2 = digitsToWords(int(from2.digitsInt))
1871+ wordsFrac2 = digitsToWords(int(from2.digitsFrac))
1872+ wordsIntTo = digitsToWords(int(from1.digitsInt) + int(from2.digitsInt))
1873+ wordsFracTo = wordsFrac1 + wordsFrac2
1874+ idx1 = wordsInt1
1875+ idx2 = wordsInt2
1876+ idxTo int
1877+ tmp1 = wordsIntTo
1878+ tmp2 = wordsFracTo
1879+ )
1880+ to.resultFrac = myMinInt8(from1.resultFrac+from2.resultFrac, MaxDecimalScale)
1881+ wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
1882+ to.negative = from1.negative != from2.negative
1883+ to.digitsFrac = from1.digitsFrac + from2.digitsFrac
1884+ if to.digitsFrac > notFixedDec {
1885+ to.digitsFrac = notFixedDec
1886+ }
1887+ to.digitsInt = int8(wordsIntTo * digitsPerWord)
1888+ if err == ErrOverflow {
1889+ return err
1890+ }
1891+ if err != nil {
1892+ if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
1893+ to.digitsFrac = int8(wordsFracTo * digitsPerWord)
1894+ }
1895+ if to.digitsInt > int8(wordsIntTo*digitsPerWord) {
1896+ to.digitsInt = int8(wordsIntTo * digitsPerWord)
1897+ }
1898+ if tmp1 > wordsIntTo {
1899+ tmp1 -= wordsIntTo
1900+ tmp2 = tmp1 >> 1
1901+ wordsInt2 -= tmp1 - tmp2
1902+ wordsFrac1 = 0
1903+ wordsFrac2 = 0
1904+ } else {
1905+ tmp2 -= wordsFracTo
1906+ tmp1 = tmp2 >> 1
1907+ if wordsFrac1 <= wordsFrac2 {
1908+ wordsFrac1 -= tmp1
1909+ wordsFrac2 -= tmp2 - tmp1
1910+ } else {
1911+ wordsFrac2 -= tmp1
1912+ wordsFrac1 -= tmp2 - tmp1
1913+ }
1914+ }
1915+ }
1916+ startTo := wordsIntTo + wordsFracTo - 1
1917+ start2 := idx2 + wordsFrac2 - 1
1918+ stop1 := idx1 - wordsInt1
1919+ stop2 := idx2 - wordsInt2
1920+ to.wordBuf = zeroMyDecimal.wordBuf
1921+
1922+ for idx1 += wordsFrac1 - 1; idx1 >= stop1; idx1-- {
1923+ carry := int32(0)
1924+ idxTo = startTo
1925+ idx2 = start2
1926+ for idx2 >= stop2 {
1927+ var hi, lo int32
1928+ p := int64(from1.wordBuf[idx1]) * int64(from2.wordBuf[idx2])
1929+ hi = int32(p / wordBase)
1930+ lo = int32(p - int64(hi)*wordBase)
1931+ to.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], lo, carry)
1932+ carry += hi
1933+ idx2--
1934+ idxTo--
1935+ }
1936+ if carry > 0 {
1937+ if idxTo < 0 {
1938+ return ErrOverflow
1939+ }
1940+ to.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], 0, carry)
1941+ }
1942+ for idxTo--; carry > 0; idxTo-- {
1943+ if idxTo < 0 {
1944+ return ErrOverflow
1945+ }
1946+ to.wordBuf[idxTo], carry = add(to.wordBuf[idxTo], 0, carry)
1947+ }
1948+ startTo--
1949+ }
1950+
1951+ /* Now we have to check for -0.000 case */
1952+ if to.negative {
1953+ idx := 0
1954+ end := wordsIntTo + wordsFracTo
1955+ for {
1956+ if to.wordBuf[idx] != 0 {
1957+ break
1958+ }
1959+ idx++
1960+ /* We got decimal zero */
1961+ if idx == end {
1962+ *to = zeroMyDecimalWithFrac(to.resultFrac)
1963+ break
1964+ }
1965+ }
1966+ }
1967+
1968+ idxTo = 0
1969+ dToMove := wordsIntTo + digitsToWords(int(to.digitsFrac))
1970+ for to.wordBuf[idxTo] == 0 && to.digitsInt > digitsPerWord {
1971+ idxTo++
1972+ to.digitsInt -= digitsPerWord
1973+ dToMove--
1974+ }
1975+ if idxTo > 0 {
1976+ curIdx := 0
1977+ for dToMove > 0 {
1978+ to.wordBuf[curIdx] = to.wordBuf[idxTo]
1979+ curIdx++
1980+ idxTo++
1981+ dToMove--
1982+ }
1983+ }
1984+ return err
1985+}
1986+
1987+// DecimalDiv does division of two decimals.
1988+//
1989+// from1 - dividend
1990+// from2 - divisor
1991+// to - quotient
1992+// fracIncr - increment of fraction
1993+func DecimalDiv(from1, from2, to *MyDecimal, fracIncr int) error {
1994+ from1, from2, to = validateArgs(from1, from2, to)
1995+ to.resultFrac = myMinInt8(from1.resultFrac+int8(fracIncr), MaxDecimalScale)
1996+ return doDivMod(from1, from2, to, nil, fracIncr)
1997+}
1998+
1999+/*
2000+DecimalMod does modulus of two decimals.
2001+
2002+ from1 - dividend
2003+ from2 - divisor
2004+ to - modulus
2005+
2006+ RETURN VALUE
2007+ E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO;
2008+
2009+ NOTES
2010+ see do_div_mod()
2011+
2012+ DESCRIPTION
2013+ the modulus R in R = M mod N
2014+
2015+ is defined as
2016+
2017+ 0 <= |R| < |M|
2018+ sign R == sign M
2019+ R = M - k*N, where k is integer
2020+
2021+ thus, there's no requirement for M or N to be integers
2022+*/
2023+func DecimalMod(from1, from2, to *MyDecimal) error {
2024+ from1, from2, to = validateArgs(from1, from2, to)
2025+ to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
2026+ return doDivMod(from1, from2, nil, to, 0)
2027+}
2028+
2029+func doDivMod(from1, from2, to, mod *MyDecimal, fracIncr int) error {
2030+ var (
2031+ frac1 = digitsToWords(int(from1.digitsFrac)) * digitsPerWord
2032+ prec1 = int(from1.digitsInt) + frac1
2033+ frac2 = digitsToWords(int(from2.digitsFrac)) * digitsPerWord
2034+ prec2 = int(from2.digitsInt) + frac2
2035+ )
2036+ if mod != nil {
2037+ to = mod
2038+ }
2039+
2040+ /* removing all the leading zeros */
2041+ i := ((prec2 - 1) % digitsPerWord) + 1
2042+ idx2 := 0
2043+ for prec2 > 0 && from2.wordBuf[idx2] == 0 {
2044+ prec2 -= i
2045+ i = digitsPerWord
2046+ idx2++
2047+ }
2048+ if prec2 <= 0 {
2049+ /* short-circuit everything: from2 == 0 */
2050+ return ErrDivByZero
2051+ }
2052+
2053+ prec2 -= countLeadingZeroes((prec2-1)%digitsPerWord, from2.wordBuf[idx2])
2054+ i = ((prec1 - 1) % digitsPerWord) + 1
2055+ idx1 := 0
2056+ for prec1 > 0 && from1.wordBuf[idx1] == 0 {
2057+ prec1 -= i
2058+ i = digitsPerWord
2059+ idx1++
2060+ }
2061+ if prec1 <= 0 {
2062+ /* short-circuit everything: from1 == 0 */
2063+ *to = zeroMyDecimalWithFrac(to.resultFrac)
2064+ return nil
2065+ }
2066+ prec1 -= countLeadingZeroes((prec1-1)%digitsPerWord, from1.wordBuf[idx1])
2067+
2068+ /* let's fix fracIncr, taking into account frac1,frac2 increase */
2069+ fracIncr -= frac1 - int(from1.digitsFrac) + frac2 - int(from2.digitsFrac)
2070+ if fracIncr < 0 {
2071+ fracIncr = 0
2072+ }
2073+
2074+ digitsIntTo := (prec1 - frac1) - (prec2 - frac2)
2075+ if from1.wordBuf[idx1] >= from2.wordBuf[idx2] {
2076+ digitsIntTo++
2077+ }
2078+ var wordsIntTo int
2079+ if digitsIntTo < 0 {
2080+ digitsIntTo /= digitsPerWord
2081+ wordsIntTo = 0
2082+ } else {
2083+ wordsIntTo = digitsToWords(digitsIntTo)
2084+ }
2085+ var wordsFracTo int
2086+ var err error
2087+ if mod != nil {
2088+ // we're calculating N1 % N2.
2089+ // The result will have
2090+ // digitsFrac=max(frac1, frac2), as for subtraction
2091+ // digitsInt=from2.digitsInt
2092+ to.negative = from1.negative
2093+ to.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)
2094+ } else {
2095+ wordsFracTo = digitsToWords(frac1 + frac2 + fracIncr)
2096+ wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
2097+ to.negative = from1.negative != from2.negative
2098+ to.digitsInt = int8(wordsIntTo * digitsPerWord)
2099+ to.digitsFrac = int8(wordsFracTo * digitsPerWord)
2100+ }
2101+ idxTo := 0
2102+ stopTo := wordsIntTo + wordsFracTo
2103+ if mod == nil {
2104+ for digitsIntTo < 0 && idxTo < wordBufLen {
2105+ to.wordBuf[idxTo] = 0
2106+ idxTo++
2107+ digitsIntTo++
2108+ }
2109+ }
2110+ i = digitsToWords(prec1)
2111+ len1 := i + digitsToWords(2*frac2+fracIncr+1) + 1
2112+ if len1 < 3 {
2113+ len1 = 3
2114+ }
2115+
2116+ tmp1 := make([]int32, len1)
2117+ copy(tmp1, from1.wordBuf[idx1:idx1+i])
2118+
2119+ start1 := 0
2120+ var stop1 int
2121+ start2 := idx2
2122+ stop2 := idx2 + digitsToWords(prec2) - 1
2123+
2124+ /* removing end zeroes */
2125+ for from2.wordBuf[stop2] == 0 && stop2 >= start2 {
2126+ stop2--
2127+ }
2128+ len2 := stop2 - start2
2129+ stop2++
2130+
2131+ /*
2132+ calculating norm2 (normalized from2.wordBuf[start2]) - we need from2.wordBuf[start2] to be large
2133+ (at least > DIG_BASE/2), but unlike Knuth's Alg. D we don't want to
2134+ normalize input numbers (as we don't make a copy of the divisor).
2135+ Thus we normalize first dec1 of buf2 only, and we'll normalize tmp1[start1]
2136+ on the fly for the purpose of guesstimation only.
2137+ It's also faster, as we're saving on normalization of from2.
2138+ */
2139+ normFactor := wordBase / int64(from2.wordBuf[start2]+1)
2140+ norm2 := int32(normFactor * int64(from2.wordBuf[start2]))
2141+ if len2 > 0 {
2142+ norm2 += int32(normFactor * int64(from2.wordBuf[start2+1]) / wordBase)
2143+ }
2144+ dcarry := int32(0)
2145+ if tmp1[start1] < from2.wordBuf[start2] {
2146+ dcarry = tmp1[start1]
2147+ start1++
2148+ }
2149+
2150+ // main loop
2151+ var guess int64
2152+ for ; idxTo < stopTo; idxTo++ {
2153+ /* short-circuit, if possible */
2154+ if dcarry == 0 && tmp1[start1] < from2.wordBuf[start2] {
2155+ guess = 0
2156+ } else {
2157+ /* D3: make a guess */
2158+ x := int64(tmp1[start1]) + int64(dcarry)*wordBase
2159+ y := int64(tmp1[start1+1])
2160+ guess = (normFactor*x + normFactor*y/wordBase) / int64(norm2)
2161+ if guess >= wordBase {
2162+ guess = wordBase - 1
2163+ }
2164+
2165+ if len2 > 0 {
2166+ /* remove normalization */
2167+ if int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {
2168+ guess--
2169+ }
2170+ if int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {
2171+ guess--
2172+ }
2173+ }
2174+
2175+ /* D4: multiply and subtract */
2176+ idx2 = stop2
2177+ idx1 = start1 + len2
2178+ var carry int32
2179+ for carry = 0; idx2 > start2; idx1-- {
2180+ var hi, lo int32
2181+ idx2--
2182+ x = guess * int64(from2.wordBuf[idx2])
2183+ hi = int32(x / wordBase)
2184+ lo = int32(x - int64(hi)*wordBase)
2185+ tmp1[idx1], carry = sub2(tmp1[idx1], lo, carry)
2186+ carry += hi
2187+ }
2188+ if dcarry < carry {
2189+ carry = 1
2190+ } else {
2191+ carry = 0
2192+ }
2193+
2194+ /* D5: check the remainder */
2195+ if carry > 0 {
2196+ /* D6: correct the guess */
2197+ guess--
2198+ idx2 = stop2
2199+ idx1 = start1 + len2
2200+ for carry = 0; idx2 > start2; idx1-- {
2201+ idx2--
2202+ tmp1[idx1], carry = add(tmp1[idx1], from2.wordBuf[idx2], carry)
2203+ }
2204+ }
2205+ }
2206+ if mod == nil {
2207+ to.wordBuf[idxTo] = int32(guess)
2208+ }
2209+ dcarry = tmp1[start1]
2210+ start1++
2211+ }
2212+ if mod != nil {
2213+ /*
2214+ now the result is in tmp1, it has
2215+ digitsInt=prec1-frac1
2216+ digitsFrac=max(frac1, frac2)
2217+ */
2218+ if dcarry != 0 {
2219+ start1--
2220+ tmp1[start1] = dcarry
2221+ }
2222+ idxTo = 0
2223+
2224+ digitsIntTo = prec1 - frac1 - start1*digitsPerWord
2225+ if digitsIntTo < 0 {
2226+ /* If leading zeroes in the fractional part were earlier stripped */
2227+ wordsIntTo = digitsIntTo / digitsPerWord
2228+ } else {
2229+ wordsIntTo = digitsToWords(digitsIntTo)
2230+ }
2231+
2232+ wordsFracTo = digitsToWords(int(to.digitsFrac))
2233+ err = nil
2234+ if wordsIntTo == 0 && wordsFracTo == 0 {
2235+ *to = zeroMyDecimal
2236+ return err
2237+ }
2238+ if wordsIntTo <= 0 {
2239+ if -wordsIntTo >= wordBufLen {
2240+ *to = zeroMyDecimal
2241+ return ErrTruncated
2242+ }
2243+ stop1 = start1 + wordsIntTo + wordsFracTo
2244+ wordsFracTo += wordsIntTo
2245+ to.digitsInt = 0
2246+ for wordsIntTo < 0 {
2247+ to.wordBuf[idxTo] = 0
2248+ idxTo++
2249+ wordsIntTo++
2250+ }
2251+ } else {
2252+ if wordsIntTo > wordBufLen {
2253+ to.digitsInt = int8(digitsPerWord * wordBufLen)
2254+ to.digitsFrac = 0
2255+ return ErrOverflow
2256+ }
2257+ stop1 = start1 + wordsIntTo + wordsFracTo
2258+ to.digitsInt = int8(myMin(wordsIntTo*digitsPerWord, int(from2.digitsInt)))
2259+ }
2260+ if wordsIntTo+wordsFracTo > wordBufLen {
2261+ stop1 -= wordsIntTo + wordsFracTo - wordBufLen
2262+ wordsFracTo = wordBufLen - wordsIntTo
2263+ to.digitsFrac = int8(wordsFracTo * digitsPerWord)
2264+ err = ErrTruncated
2265+ }
2266+ for start1 < stop1 {
2267+ to.wordBuf[idxTo] = tmp1[start1]
2268+ idxTo++
2269+ start1++
2270+ }
2271+ }
2272+ idxTo, digitsIntTo = to.removeLeadingZeros()
2273+ to.digitsInt = int8(digitsIntTo)
2274+ if idxTo != 0 {
2275+ copy(to.wordBuf[:], to.wordBuf[idxTo:])
2276+ }
2277+ return err
2278+}
2279+
2280+// DecimalPeak returns the length of the encoded decimal.
2281+func DecimalPeak(b []byte) (int, error) {
2282+ if len(b) < 3 {
2283+ return 0, ErrBadNumber
2284+ }
2285+ precision := int(b[0])
2286+ frac := int(b[1])
2287+ return DecimalBinSize(precision, frac) + 2, nil
2288+}
2289+
2290+// NewDecFromInt creates a MyDecimal from int.
2291+func NewDecFromInt(i int64) *MyDecimal {
2292+ return new(MyDecimal).FromInt(i)
2293+}
2294+
2295+// NewDecFromUint creates a MyDecimal from uint.
2296+func NewDecFromUint(i uint64) *MyDecimal {
2297+ return new(MyDecimal).FromUint(i)
2298+}
2299+
2300+// NewDecFromFloatForTest creates a MyDecimal from float, as it returns no error, it should only be used in test.
2301+func NewDecFromFloatForTest(f float64) *MyDecimal {
2302+ dec := new(MyDecimal)
2303+ err := dec.FromFloat64(f)
2304+ Log(err)
2305+ return dec
2306+}
2307+
2308+// NewDecFromStringForTest creates a MyDecimal from string, as it returns no error, it should only be used in test.
2309+func NewDecFromStringForTest(s string) *MyDecimal {
2310+ dec := new(MyDecimal)
2311+ err := dec.FromString([]byte(s))
2312+ Log(err)
2313+ return dec
2314+}
2315+
2316+// NewMaxOrMinDec returns the max or min value decimal for given precision and fraction.
2317+func NewMaxOrMinDec(negative bool, prec, frac int) *MyDecimal {
2318+ str := make([]byte, prec+2)
2319+ for i := 0; i < len(str); i++ {
2320+ str[i] = '9'
2321+ }
2322+ if negative {
2323+ str[0] = '-'
2324+ } else {
2325+ str[0] = '+'
2326+ }
2327+ str[1+prec-frac] = '.'
2328+ dec := new(MyDecimal)
2329+ err := dec.FromString(str)
2330+ Log(err)
2331+ return dec
2332+}
Show on old repository browser