OSDN Git Service

fix decimal fix_decimal
authorshenao78 <shenao.78@163.com>
Wed, 22 Jan 2020 06:31:09 +0000 (14:31 +0800)
committershenao78 <shenao.78@163.com>
Wed, 22 Jan 2020 06:31:09 +0000 (14:31 +0800)
application/mov/match/match.go
application/mov/match/match_test.go
math/decimal/decimal.go [new file with mode: 0644]
vendor/github.com/pingcap/types/helper.go [new file with mode: 0644]
vendor/github.com/pingcap/types/mydecimal.go [new file with mode: 0644]

index 4c0234f..8361a72 100644 (file)
@@ -10,6 +10,7 @@ import (
        "github.com/bytom/vapor/consensus/segwit"
        "github.com/bytom/vapor/errors"
        vprMath "github.com/bytom/vapor/math"
+       "github.com/bytom/vapor/math/decimal"
        "github.com/bytom/vapor/protocol/bc"
        "github.com/bytom/vapor/protocol/bc/types"
        "github.com/bytom/vapor/protocol/vm"
@@ -240,20 +241,18 @@ func IsMatched(orders []*common.Order) bool {
                return false
        }
 
-       rate := orderRatio(sortedOrders[0])
-       oppositeRate := big.NewFloat(0).SetInt64(1)
+       rate := decimal.New(1, 0).Div(orderRatio(sortedOrders[0]))
+       oppositeRate := decimal.New(1, 0)
        for i := 1; i < len(sortedOrders); i++ {
-               oppositeRate.Mul(oppositeRate, orderRatio(sortedOrders[i]))
+               oppositeRate = oppositeRate.Mul(orderRatio(sortedOrders[i]))
        }
-
-       one := big.NewFloat(0).SetInt64(1)
-       return one.Quo(one, rate).Cmp(oppositeRate) >= 0
+       return rate.Cmp(oppositeRate) >= 0
 }
 
-func orderRatio(order *common.Order) *big.Float {
-       ratio := big.NewFloat(0).SetInt64(order.RatioNumerator)
-       ratio.Quo(ratio, big.NewFloat(0).SetInt64(order.RatioDenominator))
-       return ratio
+func orderRatio(order *common.Order) *decimal.Decimal {
+       numerator := decimal.New(order.RatioNumerator, 0)
+       denominator := decimal.New(order.RatioDenominator, 0)
+       return numerator.Div(denominator)
 }
 
 func setMatchTxArguments(txInput *types.TxInput, isPartialTrade bool, position int, receiveAmounts uint64) {
index 640f4cf..7d013ec 100644 (file)
@@ -256,3 +256,163 @@ func TestValidateTradePairs(t *testing.T) {
                }
        }
 }
+
+func TestIsMatched(t *testing.T) {
+       cases := []struct {
+               desc        string
+               orders      []*common.Order
+               wantMatched bool
+       }{
+               {
+                       desc: "ratio is equals",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ratio is equals, and numerator and denominator are multiples of the opposite",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   6250,
+                                       RatioDenominator: 3,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   9,
+                                       RatioDenominator: 18750,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000000,
+                                       RatioDenominator: 30000000000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "not matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   62500000000000001,
+                                       RatioDenominator: 30000000000000,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   3,
+                                       RatioDenominator: 6250,
+                               },
+                       },
+                       wantMatched: false,
+               },
+               {
+                       desc: "ring matched",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000001,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000000,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: true,
+               },
+               {
+                       desc: "ring fail matched with a slight diff",
+                       orders: []*common.Order{
+                               {
+                                       FromAssetID:      &mock.BTC,
+                                       ToAssetID:        &mock.ETH,
+                                       RatioNumerator:   2000000003,
+                                       RatioDenominator: 100000001,
+                               },
+                               {
+                                       FromAssetID:      &mock.ETH,
+                                       ToAssetID:        &mock.EOS,
+                                       RatioNumerator:   400000000001,
+                                       RatioDenominator: 2000000003,
+                               },
+                               {
+                                       FromAssetID:      &mock.EOS,
+                                       ToAssetID:        &mock.BTC,
+                                       RatioNumerator:   100000002,
+                                       RatioDenominator: 400000000001,
+                               },
+                       },
+                       wantMatched: false,
+               },
+       }
+
+       for i, c := range cases {
+               gotMatched := IsMatched(c.orders)
+               if gotMatched != c.wantMatched {
+                       t.Errorf("#%d(%s) got matched:%v, want matched:%v", i, c.desc, gotMatched, c.wantMatched)
+               }
+       }
+}
diff --git a/math/decimal/decimal.go b/math/decimal/decimal.go
new file mode 100644 (file)
index 0000000..a04afca
--- /dev/null
@@ -0,0 +1,143 @@
+package decimal
+
+import (
+       "github.com/pingcap/types"
+       "github.com/sirupsen/logrus"
+)
+
+type Decimal struct {
+       value *types.MyDecimal
+}
+
+func NewFromString(value string) (*Decimal, error) {
+       dec := new(types.MyDecimal)
+       if err := dec.FromString([]byte(value)); err != nil && err != types.ErrTruncated {
+               return nil, err
+       }
+
+       return &Decimal{value: dec}, nil
+}
+
+func New(value int64, exp int) *Decimal {
+       dec := types.NewDecFromInt(value)
+       if exp < 0 {
+               pow := types.NewDecFromInt(1)
+               if err := pow.Shift(-exp); err != nil {
+                       logFatal(err,"decimal shift error")
+               }
+
+               if err := types.DecimalDiv(dec, pow, dec, 10); err != nil {
+                       logFatal(err,"decimal divide error")
+               }
+       } else {
+               if err := dec.Shift(exp); err != nil {
+                       logFatal(err,"decimal shift error")
+               }
+       }
+       return &Decimal{value: dec}
+}
+
+func (d *Decimal) Abs() *Decimal {
+       coefficient := New(1, 0)
+       if d.value.IsNegative() {
+               coefficient = New(-1, 0)
+       }
+       return d.Mul(coefficient)
+}
+
+func (d *Decimal) Add(d2 *Decimal) *Decimal {
+       result := new(types.MyDecimal)
+       if err := types.DecimalAdd(d.value, d2.value, result); err != nil {
+               logFatal(err,"decimal add error")
+       }
+
+       return &Decimal{value: result}
+}
+
+func (d *Decimal) Sub(d2 *Decimal) *Decimal {
+       result := new(types.MyDecimal)
+       if err := types.DecimalSub(d.value, d2.value, result); err != nil {
+               logFatal(err,"decimal subtract error")
+       }
+
+       return &Decimal{value: result}
+}
+
+func (d *Decimal) Mul(d2 *Decimal) *Decimal {
+       result := new(types.MyDecimal)
+       if err := types.DecimalMul(d.value, d2.value, result); err != nil {
+               logFatal(err,"decimal multiply error")
+       }
+
+       return &Decimal{value: result}
+}
+
+func (d *Decimal) Div(d2 *Decimal) *Decimal {
+       result := new(types.MyDecimal)
+       if err := types.DecimalDiv(d.value, d2.value, result, 10); err != nil {
+               logFatal(err,"decimal divide error")
+       }
+
+       return &Decimal{value: result}
+}
+
+func (d *Decimal) Float64() float64 {
+       result, err := d.value.ToFloat64()
+       if err != nil {
+               logFatal(err,"decimal to float64 error")
+       }
+
+       return result
+}
+
+func (d *Decimal) Int64() int64 {
+       result, err := d.value.ToInt()
+       if err != nil {
+               logFatal(err,"decimal to int64 error")
+       }
+
+       return result
+}
+
+func (d *Decimal) Cmp(d2 *Decimal) int {
+       return d.value.Compare(d2.value)
+}
+
+func (d *Decimal) LessThanOrEqual(d2 *Decimal) bool {
+       return d.Cmp(d2) <= 0
+}
+
+func (d *Decimal) GreaterThan(d2 *Decimal) bool {
+       return d.Cmp(d2) > 0
+}
+
+func (d *Decimal) String() string {
+       return d.value.String()
+}
+
+func (d *Decimal) StringRoundFixed(places int) string {
+       result := new(types.MyDecimal)
+       if err := d.value.Round(result, places, types.ModeHalfEven); err != nil {
+               logFatal(err, "decimal string round fixed error")
+       }
+
+       return result.String()
+}
+
+func (d *Decimal) StringCeilFixed(places int) string {
+       fixedRate, err := NewFromString(d.StringRoundFixed(places))
+       if err != nil {
+               logFatal(err, "decimal string ceil fixed error")
+       }
+
+       if fixedRate.Cmp(d) != 0 {
+               fixedRate = fixedRate.Add(New(1, -places))
+       }
+       return fixedRate.StringRoundFixed(places)
+}
+
+func logFatal(err error, args ...interface{}) {
+       if err != types.ErrTruncated {
+               logrus.WithField("err", err).Fatal(args...)
+       }
+}
diff --git a/vendor/github.com/pingcap/types/helper.go b/vendor/github.com/pingcap/types/helper.go
new file mode 100644 (file)
index 0000000..93bc189
--- /dev/null
@@ -0,0 +1,168 @@
+package types
+
+// Copyright 2015 PingCAP, Inc.
+//
+// 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,
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import (
+       "math"
+       "strings"
+       "unicode"
+
+       "github.com/sirupsen/logrus"
+)
+
+// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function.
+// RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html
+// so rounding use "round half away from zero".
+// e.g, 1.5 -> 2, -1.5 -> -2.
+func RoundFloat(f float64) float64 {
+       if math.Abs(f) < 0.5 {
+               return 0
+       }
+
+       return math.Trunc(f + math.Copysign(0.5, f))
+}
+
+// Round rounds the argument f to dec decimal places.
+// dec defaults to 0 if not specified. dec can be negative
+// to cause dec digits left of the decimal point of the
+// value f to become zero.
+func Round(f float64, dec int) float64 {
+       shift := math.Pow10(dec)
+       tmp := f * shift
+       if math.IsInf(tmp, 0) {
+               return f
+       }
+       return RoundFloat(tmp) / shift
+}
+
+// Truncate truncates the argument f to dec decimal places.
+// dec defaults to 0 if not specified. dec can be negative
+// to cause dec digits left of the decimal point of the
+// value f to become zero.
+func Truncate(f float64, dec int) float64 {
+       shift := math.Pow10(dec)
+       tmp := f * shift
+       if math.IsInf(tmp, 0) {
+               return f
+       }
+       return math.Trunc(tmp) / shift
+}
+
+func isSpace(c byte) bool {
+       return c == ' ' || c == '\t'
+}
+
+func isDigit(c byte) bool {
+       return c >= '0' && c <= '9'
+}
+
+func myMax(a, b int) int {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func myMaxInt8(a, b int8) int8 {
+       if a > b {
+               return a
+       }
+       return b
+}
+
+func myMin(a, b int) int {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+func myMinInt8(a, b int8) int8 {
+       if a < b {
+               return a
+       }
+       return b
+}
+
+const (
+       maxUint    = uint64(math.MaxUint64)
+       uintCutOff = maxUint/uint64(10) + 1
+       intCutOff  = uint64(math.MaxInt64) + 1
+)
+
+// strToInt converts a string to an integer in best effort.
+func strToInt(str string) (int64, error) {
+       str = strings.TrimSpace(str)
+       if len(str) == 0 {
+               return 0, ErrTruncated
+       }
+       negative := false
+       i := 0
+       if str[i] == '-' {
+               negative = true
+               i++
+       } else if str[i] == '+' {
+               i++
+       }
+
+       var (
+               err    error
+               hasNum = false
+       )
+       r := uint64(0)
+       for ; i < len(str); i++ {
+               if !unicode.IsDigit(rune(str[i])) {
+                       err = ErrTruncated
+                       break
+               }
+               hasNum = true
+               if r >= uintCutOff {
+                       r = 0
+                       err = ErrBadNumber
+                       break
+               }
+               r = r * uint64(10)
+
+               r1 := r + uint64(str[i]-'0')
+               if r1 < r || r1 > maxUint {
+                       r = 0
+                       err = ErrBadNumber
+                       break
+               }
+               r = r1
+       }
+       if !hasNum {
+               err = ErrTruncated
+       }
+
+       if !negative && r >= intCutOff {
+               return math.MaxInt64, ErrBadNumber
+       }
+
+       if negative && r > intCutOff {
+               return math.MinInt64, ErrBadNumber
+       }
+
+       if negative {
+               r = -r
+       }
+       return int64(r), err
+}
+
+// Log logs the error if it is not nil.
+func Log(err error) {
+       if err != nil {
+               logrus.Error("encountered error", err)
+       }
+}
diff --git a/vendor/github.com/pingcap/types/mydecimal.go b/vendor/github.com/pingcap/types/mydecimal.go
new file mode 100644 (file)
index 0000000..cc2966b
--- /dev/null
@@ -0,0 +1,2332 @@
+// Copyright 2016 PingCAP, Inc.
+//
+// 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,
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package types
+
+import (
+       "errors"
+       "math"
+       "strconv"
+)
+
+// RoundMode is the type for round mode.
+type RoundMode int32
+
+var (
+       // ErrTruncated is returned when data has been truncated during conversion.
+       ErrTruncated = errors.New("err truncated")
+       // ErrOverflow is returned when data is out of range for a field type.
+       ErrOverflow = errors.New("err overflow")
+       // ErrDivByZero is return when do division by 0.
+       ErrDivByZero = errors.New("err div by zero")
+       // ErrBadNumber is return when parsing an invalid binary decimal number.
+       ErrBadNumber = errors.New("err bad number")
+)
+
+// constant values.
+const (
+       ten0 = 1
+       ten1 = 10
+       ten2 = 100
+       ten3 = 1000
+       ten4 = 10000
+       ten5 = 100000
+       ten6 = 1000000
+       ten7 = 10000000
+       ten8 = 100000000
+       ten9 = 1000000000
+
+       maxWordBufLen = 9 // A MyDecimal holds 9 words.
+       digitsPerWord = 9 // A word holds 9 digits.
+       wordSize      = 4 // A word is 4 bytes int32.
+       digMask       = ten8
+       wordBase      = ten9
+       wordMax       = wordBase - 1
+       notFixedDec   = 31
+
+       DivFracIncr = 4
+
+       // ModeHalfEven rounds normally.
+       ModeHalfEven RoundMode = 5
+       // Truncate just truncates the decimal.
+       ModeTruncate RoundMode = 10
+       // Ceiling is not supported now.
+       modeCeiling RoundMode = 0
+
+       MaxDecimalScale = 30
+)
+
+var (
+       wordBufLen = 9
+       mod9       = [128]int8{
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1, 2, 3, 4, 5, 6, 7, 8,
+               0, 1,
+       }
+       div9 = [128]int{
+               0, 0, 0, 0, 0, 0, 0, 0, 0,
+               1, 1, 1, 1, 1, 1, 1, 1, 1,
+               2, 2, 2, 2, 2, 2, 2, 2, 2,
+               3, 3, 3, 3, 3, 3, 3, 3, 3,
+               4, 4, 4, 4, 4, 4, 4, 4, 4,
+               5, 5, 5, 5, 5, 5, 5, 5, 5,
+               6, 6, 6, 6, 6, 6, 6, 6, 6,
+               7, 7, 7, 7, 7, 7, 7, 7, 7,
+               8, 8, 8, 8, 8, 8, 8, 8, 8,
+               9, 9, 9, 9, 9, 9, 9, 9, 9,
+               10, 10, 10, 10, 10, 10, 10, 10, 10,
+               11, 11, 11, 11, 11, 11, 11, 11, 11,
+               12, 12, 12, 12, 12, 12, 12, 12, 12,
+               13, 13, 13, 13, 13, 13, 13, 13, 13,
+               14, 14,
+       }
+       powers10  = [10]int32{ten0, ten1, ten2, ten3, ten4, ten5, ten6, ten7, ten8, ten9}
+       dig2bytes = [10]int{0, 1, 1, 2, 2, 3, 3, 4, 4, 4}
+       fracMax   = [8]int32{
+               900000000,
+               990000000,
+               999000000,
+               999900000,
+               999990000,
+               999999000,
+               999999900,
+               999999990,
+       }
+       zeroMyDecimal = MyDecimal{}
+)
+
+// get the zero of MyDecimal with the specified result fraction digits
+func zeroMyDecimalWithFrac(frac int8) MyDecimal {
+       zero := MyDecimal{}
+       zero.digitsFrac = frac
+       zero.resultFrac = frac
+       return zero
+}
+
+// add adds a and b and carry, returns the sum and new carry.
+func add(a, b, carry int32) (int32, int32) {
+       sum := a + b + carry
+       if sum >= wordBase {
+               carry = 1
+               sum -= wordBase
+       } else {
+               carry = 0
+       }
+       return sum, carry
+}
+
+// add2 adds a and b and carry, returns the sum and new carry.
+// It is only used in DecimalMul.
+func add2(a, b, carry int32) (int32, int32) {
+       sum := int64(a) + int64(b) + int64(carry)
+       if sum >= wordBase {
+               carry = 1
+               sum -= wordBase
+       } else {
+               carry = 0
+       }
+
+       if sum >= wordBase {
+               sum -= wordBase
+               carry++
+       }
+       return int32(sum), carry
+}
+
+// sub subtracts b and carry from a, returns the diff and new carry.
+func sub(a, b, carry int32) (int32, int32) {
+       diff := a - b - carry
+       if diff < 0 {
+               carry = 1
+               diff += wordBase
+       } else {
+               carry = 0
+       }
+       return diff, carry
+}
+
+// sub2 subtracts b and carry from a, returns the diff and new carry.
+// the new carry may be 2.
+func sub2(a, b, carry int32) (int32, int32) {
+       diff := a - b - carry
+       if diff < 0 {
+               carry = 1
+               diff += wordBase
+       } else {
+               carry = 0
+       }
+       if diff < 0 {
+               diff += wordBase
+               carry++
+       }
+       return diff, carry
+}
+
+// fixWordCntError limits word count in wordBufLen, and returns overflow or truncate error.
+func fixWordCntError(wordsInt, wordsFrac int) (newWordsInt int, newWordsFrac int, err error) {
+       if wordsInt+wordsFrac > wordBufLen {
+               if wordsInt > wordBufLen {
+                       return wordBufLen, 0, ErrOverflow
+               }
+               return wordsInt, wordBufLen - wordsInt, ErrTruncated
+       }
+       return wordsInt, wordsFrac, nil
+}
+
+/*
+  countLeadingZeroes returns the number of leading zeroes that can be removed from fraction.
+
+  @param   i    start index
+  @param   word value to compare against list of powers of 10
+*/
+func countLeadingZeroes(i int, word int32) int {
+       leading := 0
+       for word < powers10[i] {
+               i--
+               leading++
+       }
+       return leading
+}
+
+/*
+  countTrailingZeros returns the number of trailing zeroes that can be removed from fraction.
+
+  @param   i    start index
+  @param   word  value to compare against list of powers of 10
+*/
+func countTrailingZeroes(i int, word int32) int {
+       trailing := 0
+       for word%powers10[i] == 0 {
+               i++
+               trailing++
+       }
+       return trailing
+}
+
+func digitsToWords(digits int) int {
+       if digits+digitsPerWord-1 >= 0 && digits+digitsPerWord-1 < 128 {
+               return div9[digits+digitsPerWord-1]
+       }
+       return (digits + digitsPerWord - 1) / digitsPerWord
+}
+
+// MyDecimalStructSize is the struct size of MyDecimal.
+const MyDecimalStructSize = 40
+
+// MyDecimal represents a decimal value.
+type MyDecimal struct {
+       digitsInt int8 // the number of *decimal* digits before the point.
+
+       digitsFrac int8 // the number of decimal digits after the point.
+
+       resultFrac int8 // result fraction digits.
+
+       negative bool
+
+       //  wordBuf is an array of int32 words.
+       // A word is an int32 value can hold 9 digits.(0 <= word < wordBase)
+       wordBuf [maxWordBufLen]int32
+}
+
+// IsNegative returns whether a decimal is negative.
+func (d *MyDecimal) IsNegative() bool {
+       return d.negative
+}
+
+// GetDigitsFrac returns the digitsFrac.
+func (d *MyDecimal) GetDigitsFrac() int8 {
+       return d.digitsFrac
+}
+
+// GetDigitsInt returns the digitsInt.
+func (d *MyDecimal) GetDigitsInt() int8 {
+       return d.digitsInt
+}
+
+// String returns the decimal string representation rounded to resultFrac.
+func (d *MyDecimal) String() string {
+       tmp := *d
+       err := tmp.Round(&tmp, int(tmp.resultFrac), ModeHalfEven)
+       Log(err)
+       return string(tmp.ToString())
+}
+
+func (d *MyDecimal) stringSize() int {
+       // sign, zero integer and dot.
+       return int(d.digitsInt + d.digitsFrac + 3)
+}
+
+func (d *MyDecimal) removeLeadingZeros() (wordIdx int, digitsInt int) {
+       digitsInt = int(d.digitsInt)
+       i := ((digitsInt - 1) % digitsPerWord) + 1
+       for digitsInt > 0 && d.wordBuf[wordIdx] == 0 {
+               digitsInt -= i
+               i = digitsPerWord
+               wordIdx++
+       }
+       if digitsInt > 0 {
+               digitsInt -= countLeadingZeroes((digitsInt-1)%digitsPerWord, d.wordBuf[wordIdx])
+       } else {
+               digitsInt = 0
+       }
+       return
+}
+
+func (d *MyDecimal) removeTrailingZeros() (lastWordIdx int, digitsFrac int) {
+       digitsFrac = int(d.digitsFrac)
+       i := ((digitsFrac - 1) % digitsPerWord) + 1
+       lastWordIdx = digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))
+       for digitsFrac > 0 && d.wordBuf[lastWordIdx-1] == 0 {
+               digitsFrac -= i
+               i = digitsPerWord
+               lastWordIdx--
+       }
+       if digitsFrac > 0 {
+               digitsFrac -= countTrailingZeroes(9-((digitsFrac-1)%digitsPerWord), d.wordBuf[lastWordIdx-1])
+       } else {
+               digitsFrac = 0
+       }
+       return
+}
+
+// ToString converts decimal to its printable string representation without rounding.
+//
+//  RETURN VALUE
+//
+//      str       - result string
+//      errCode   - eDecOK/eDecTruncate/eDecOverflow
+//
+func (d *MyDecimal) ToString() (str []byte) {
+       str = make([]byte, d.stringSize())
+       digitsFrac := int(d.digitsFrac)
+       wordStartIdx, digitsInt := d.removeLeadingZeros()
+       if digitsInt+digitsFrac == 0 {
+               digitsInt = 1
+               wordStartIdx = 0
+       }
+
+       digitsIntLen := digitsInt
+       if digitsIntLen == 0 {
+               digitsIntLen = 1
+       }
+       digitsFracLen := digitsFrac
+       length := digitsIntLen + digitsFracLen
+       if d.negative {
+               length++
+       }
+       if digitsFrac > 0 {
+               length++
+       }
+       str = str[:length]
+       strIdx := 0
+       if d.negative {
+               str[strIdx] = '-'
+               strIdx++
+       }
+       var fill int
+       if digitsFrac > 0 {
+               fracIdx := strIdx + digitsIntLen
+               fill = digitsFracLen - digitsFrac
+               wordIdx := wordStartIdx + digitsToWords(digitsInt)
+               str[fracIdx] = '.'
+               fracIdx++
+               for ; digitsFrac > 0; digitsFrac -= digitsPerWord {
+                       x := d.wordBuf[wordIdx]
+                       wordIdx++
+                       for i := myMin(digitsFrac, digitsPerWord); i > 0; i-- {
+                               y := x / digMask
+                               str[fracIdx] = byte(y) + '0'
+                               fracIdx++
+                               x -= y * digMask
+                               x *= 10
+                       }
+               }
+               for ; fill > 0; fill-- {
+                       str[fracIdx] = '0'
+                       fracIdx++
+               }
+       }
+       fill = digitsIntLen - digitsInt
+       if digitsInt == 0 {
+               fill-- /* symbol 0 before digital point */
+       }
+       for ; fill > 0; fill-- {
+               str[strIdx] = '0'
+               strIdx++
+       }
+       if digitsInt > 0 {
+               strIdx += digitsInt
+               wordIdx := wordStartIdx + digitsToWords(digitsInt)
+               for ; digitsInt > 0; digitsInt -= digitsPerWord {
+                       wordIdx--
+                       x := d.wordBuf[wordIdx]
+                       for i := myMin(digitsInt, digitsPerWord); i > 0; i-- {
+                               y := x / 10
+                               strIdx--
+                               str[strIdx] = '0' + byte(x-y*10)
+                               x = y
+                       }
+               }
+       } else {
+               str[strIdx] = '0'
+       }
+       return
+}
+
+// FromString parses decimal from string.
+func (d *MyDecimal) FromString(str []byte) error {
+       for i := 0; i < len(str); i++ {
+               if !isSpace(str[i]) {
+                       str = str[i:]
+                       break
+               }
+       }
+       if len(str) == 0 {
+               *d = zeroMyDecimal
+               return ErrBadNumber
+       }
+       switch str[0] {
+       case '-':
+               d.negative = true
+               fallthrough
+       case '+':
+               str = str[1:]
+       }
+       var strIdx int
+       for strIdx < len(str) && isDigit(str[strIdx]) {
+               strIdx++
+       }
+       digitsInt := strIdx
+       var digitsFrac int
+       var endIdx int
+       if strIdx < len(str) && str[strIdx] == '.' {
+               endIdx = strIdx + 1
+               for endIdx < len(str) && isDigit(str[endIdx]) {
+                       endIdx++
+               }
+               digitsFrac = endIdx - strIdx - 1
+       } else {
+               digitsFrac = 0
+               endIdx = strIdx
+       }
+       if digitsInt+digitsFrac == 0 {
+               *d = zeroMyDecimal
+               return ErrBadNumber
+       }
+       wordsInt := digitsToWords(digitsInt)
+       wordsFrac := digitsToWords(digitsFrac)
+       wordsInt, wordsFrac, err := fixWordCntError(wordsInt, wordsFrac)
+       if err != nil {
+               digitsFrac = wordsFrac * digitsPerWord
+               if err == ErrOverflow {
+                       digitsInt = wordsInt * digitsPerWord
+               }
+       }
+       d.digitsInt = int8(digitsInt)
+       d.digitsFrac = int8(digitsFrac)
+       wordIdx := wordsInt
+       strIdxTmp := strIdx
+       var word int32
+       var innerIdx int
+       for digitsInt > 0 {
+               digitsInt--
+               strIdx--
+               word += int32(str[strIdx]-'0') * powers10[innerIdx]
+               innerIdx++
+               if innerIdx == digitsPerWord {
+                       wordIdx--
+                       d.wordBuf[wordIdx] = word
+                       word = 0
+                       innerIdx = 0
+               }
+       }
+       if innerIdx != 0 {
+               wordIdx--
+               d.wordBuf[wordIdx] = word
+       }
+
+       wordIdx = wordsInt
+       strIdx = strIdxTmp
+       word = 0
+       innerIdx = 0
+       for digitsFrac > 0 {
+               digitsFrac--
+               strIdx++
+               word = int32(str[strIdx]-'0') + word*10
+               innerIdx++
+               if innerIdx == digitsPerWord {
+                       d.wordBuf[wordIdx] = word
+                       wordIdx++
+                       word = 0
+                       innerIdx = 0
+               }
+       }
+       if innerIdx != 0 {
+               d.wordBuf[wordIdx] = word * powers10[digitsPerWord-innerIdx]
+       }
+       if endIdx+1 <= len(str) && (str[endIdx] == 'e' || str[endIdx] == 'E') {
+               exponent, err1 := strToInt(string(str[endIdx+1:]))
+               if err1 != nil {
+                       err = err1
+                       if err != ErrTruncated {
+                               *d = zeroMyDecimal
+                       }
+               }
+               if exponent > math.MaxInt32/2 {
+                       negative := d.negative
+                       maxDecimal(wordBufLen*digitsPerWord, 0, d)
+                       d.negative = negative
+                       err = ErrOverflow
+               }
+               if exponent < math.MinInt32/2 && err != ErrOverflow {
+                       *d = zeroMyDecimal
+                       err = ErrTruncated
+               }
+               if err != ErrOverflow {
+                       shiftErr := d.Shift(int(exponent))
+                       if shiftErr != nil {
+                               if shiftErr == ErrOverflow {
+                                       negative := d.negative
+                                       maxDecimal(wordBufLen*digitsPerWord, 0, d)
+                                       d.negative = negative
+                               }
+                               err = shiftErr
+                       }
+               }
+       }
+       allZero := true
+       for i := 0; i < wordBufLen; i++ {
+               if d.wordBuf[i] != 0 {
+                       allZero = false
+                       break
+               }
+       }
+       if allZero {
+               d.negative = false
+       }
+       d.resultFrac = d.digitsFrac
+       return err
+}
+
+// Shift shifts decimal digits in given number (with rounding if it need), shift > 0 means shift to left shift,
+// shift < 0 means right shift. In fact it is multiplying on 10^shift.
+//
+// RETURN
+//   eDecOK          OK
+//   eDecOverflow    operation lead to overflow, number is untoched
+//   eDecTruncated   number was rounded to fit into buffer
+//
+func (d *MyDecimal) Shift(shift int) error {
+       var err error
+       if shift == 0 {
+               return nil
+       }
+       var (
+               // digitBegin is index of first non zero digit (all indexes from 0).
+               digitBegin int
+               // digitEnd is index of position after last decimal digit.
+               digitEnd int
+               // point is index of digit position just after point.
+               point = digitsToWords(int(d.digitsInt)) * digitsPerWord
+               // new point position.
+               newPoint = point + shift
+               // number of digits in result.
+               digitsInt, digitsFrac int
+               newFront              int
+       )
+       digitBegin, digitEnd = d.digitBounds()
+       if digitBegin == digitEnd {
+               *d = zeroMyDecimal
+               return nil
+       }
+
+       digitsInt = newPoint - digitBegin
+       if digitsInt < 0 {
+               digitsInt = 0
+       }
+       digitsFrac = digitEnd - newPoint
+       if digitsFrac < 0 {
+               digitsFrac = 0
+       }
+       wordsInt := digitsToWords(digitsInt)
+       wordsFrac := digitsToWords(digitsFrac)
+       newLen := wordsInt + wordsFrac
+       if newLen > wordBufLen {
+               lack := newLen - wordBufLen
+               if wordsFrac < lack {
+                       return ErrOverflow
+               }
+               /* cut off fraction part to allow new number to fit in our buffer */
+               err = ErrTruncated
+               wordsFrac -= lack
+               diff := digitsFrac - wordsFrac*digitsPerWord
+               err1 := d.Round(d, digitEnd-point-diff, ModeHalfEven)
+               if err1 != nil {
+                       return err1
+               }
+               digitEnd -= diff
+               digitsFrac = wordsFrac * digitsPerWord
+               if digitEnd <= digitBegin {
+                       /*
+                          We lost all digits (they will be shifted out of buffer), so we can
+                          just return 0.
+                       */
+                       *d = zeroMyDecimal
+                       return ErrTruncated
+               }
+       }
+
+       if shift%digitsPerWord != 0 {
+               var lMiniShift, rMiniShift, miniShift int
+               var doLeft bool
+               /*
+                  Calculate left/right shift to align decimal digits inside our bug
+                  digits correctly.
+               */
+               if shift > 0 {
+                       lMiniShift = shift % digitsPerWord
+                       rMiniShift = digitsPerWord - lMiniShift
+                       doLeft = lMiniShift <= digitBegin
+               } else {
+                       rMiniShift = (-shift) % digitsPerWord
+                       lMiniShift = digitsPerWord - rMiniShift
+                       doLeft = (digitsPerWord*wordBufLen - digitEnd) < rMiniShift
+               }
+               if doLeft {
+                       d.doMiniLeftShift(lMiniShift, digitBegin, digitEnd)
+                       miniShift = -lMiniShift
+               } else {
+                       d.doMiniRightShift(rMiniShift, digitBegin, digitEnd)
+                       miniShift = rMiniShift
+               }
+               newPoint += miniShift
+               /*
+                  If number is shifted and correctly aligned in buffer we can finish.
+               */
+               if shift+miniShift == 0 && (newPoint-digitsInt) < digitsPerWord {
+                       d.digitsInt = int8(digitsInt)
+                       d.digitsFrac = int8(digitsFrac)
+                       return err /* already shifted as it should be */
+               }
+               digitBegin += miniShift
+               digitEnd += miniShift
+       }
+
+       /* if new 'decimal front' is in first digit, we do not need move digits */
+       newFront = newPoint - digitsInt
+       if newFront >= digitsPerWord || newFront < 0 {
+               /* need to move digits */
+               var wordShift int
+               if newFront > 0 {
+                       /* move left */
+                       wordShift = newFront / digitsPerWord
+                       to := digitBegin/digitsPerWord - wordShift
+                       barier := (digitEnd-1)/digitsPerWord - wordShift
+                       for ; to <= barier; to++ {
+                               d.wordBuf[to] = d.wordBuf[to+wordShift]
+                       }
+                       for barier += wordShift; to <= barier; to++ {
+                               d.wordBuf[to] = 0
+                       }
+                       wordShift = -wordShift
+               } else {
+                       /* move right */
+                       wordShift = (1 - newFront) / digitsPerWord
+                       to := (digitEnd-1)/digitsPerWord + wordShift
+                       barier := digitBegin/digitsPerWord + wordShift
+                       for ; to >= barier; to-- {
+                               d.wordBuf[to] = d.wordBuf[to-wordShift]
+                       }
+                       for barier -= wordShift; to >= barier; to-- {
+                               d.wordBuf[to] = 0
+                       }
+               }
+               digitShift := wordShift * digitsPerWord
+               digitBegin += digitShift
+               digitEnd += digitShift
+               newPoint += digitShift
+       }
+       /*
+          If there are gaps then fill them with 0.
+
+          Only one of following 'for' loops will work because wordIdxBegin <= wordIdxEnd.
+       */
+       wordIdxBegin := digitBegin / digitsPerWord
+       wordIdxEnd := (digitEnd - 1) / digitsPerWord
+       wordIdxNewPoint := 0
+
+       /* We don't want negative new_point below */
+       if newPoint != 0 {
+               wordIdxNewPoint = (newPoint - 1) / digitsPerWord
+       }
+       if wordIdxNewPoint > wordIdxEnd {
+               for wordIdxNewPoint > wordIdxEnd {
+                       d.wordBuf[wordIdxNewPoint] = 0
+                       wordIdxNewPoint--
+               }
+       } else {
+               for ; wordIdxNewPoint < wordIdxBegin; wordIdxNewPoint++ {
+                       d.wordBuf[wordIdxNewPoint] = 0
+               }
+       }
+       d.digitsInt = int8(digitsInt)
+       d.digitsFrac = int8(digitsFrac)
+       return err
+}
+
+/*
+  digitBounds returns bounds of decimal digits in the number.
+
+      start - index (from 0 ) of first decimal digits.
+      end   - index of position just after last decimal digit.
+*/
+func (d *MyDecimal) digitBounds() (start, end int) {
+       var i int
+       bufBeg := 0
+       bufLen := digitsToWords(int(d.digitsInt)) + digitsToWords(int(d.digitsFrac))
+       bufEnd := bufLen - 1
+
+       /* find non-zero digit from number beginning */
+       for bufBeg < bufLen && d.wordBuf[bufBeg] == 0 {
+               bufBeg++
+       }
+       if bufBeg >= bufLen {
+               return 0, 0
+       }
+
+       /* find non-zero decimal digit from number beginning */
+       if bufBeg == 0 && d.digitsInt > 0 {
+               i = (int(d.digitsInt) - 1) % digitsPerWord
+               start = digitsPerWord - i - 1
+       } else {
+               i = digitsPerWord - 1
+               start = bufBeg * digitsPerWord
+       }
+       if bufBeg < bufLen {
+               start += countLeadingZeroes(i, d.wordBuf[bufBeg])
+       }
+
+       /* find non-zero digit at the end */
+       for bufEnd > bufBeg && d.wordBuf[bufEnd] == 0 {
+               bufEnd--
+       }
+       /* find non-zero decimal digit from the end */
+       if bufEnd == bufLen-1 && d.digitsFrac > 0 {
+               i = (int(d.digitsFrac)-1)%digitsPerWord + 1
+               end = bufEnd*digitsPerWord + i
+               i = digitsPerWord - i + 1
+       } else {
+               end = (bufEnd + 1) * digitsPerWord
+               i = 1
+       }
+       end -= countTrailingZeroes(i, d.wordBuf[bufEnd])
+       return start, end
+}
+
+/*
+  doMiniLeftShift does left shift for alignment of data in buffer.
+
+    shift   number of decimal digits on which it should be shifted
+    beg/end bounds of decimal digits (see digitsBounds())
+
+  NOTE
+    Result fitting in the buffer should be garanted.
+    'shift' have to be from 1 to digitsPerWord-1 (inclusive)
+*/
+func (d *MyDecimal) doMiniLeftShift(shift, beg, end int) {
+       bufFrom := beg / digitsPerWord
+       bufEnd := (end - 1) / digitsPerWord
+       cShift := digitsPerWord - shift
+       if beg%digitsPerWord < shift {
+               d.wordBuf[bufFrom-1] = d.wordBuf[bufFrom] / powers10[cShift]
+       }
+       for bufFrom < bufEnd {
+               d.wordBuf[bufFrom] = (d.wordBuf[bufFrom]%powers10[cShift])*powers10[shift] + d.wordBuf[bufFrom+1]/powers10[cShift]
+               bufFrom++
+       }
+       d.wordBuf[bufFrom] = (d.wordBuf[bufFrom] % powers10[cShift]) * powers10[shift]
+}
+
+/*
+  doMiniRightShift does right shift for alignment of data in buffer.
+
+    shift   number of decimal digits on which it should be shifted
+    beg/end bounds of decimal digits (see digitsBounds())
+
+  NOTE
+    Result fitting in the buffer should be garanted.
+    'shift' have to be from 1 to digitsPerWord-1 (inclusive)
+*/
+func (d *MyDecimal) doMiniRightShift(shift, beg, end int) {
+       bufFrom := (end - 1) / digitsPerWord
+       bufEnd := beg / digitsPerWord
+       cShift := digitsPerWord - shift
+       if digitsPerWord-((end-1)%digitsPerWord+1) < shift {
+               d.wordBuf[bufFrom+1] = (d.wordBuf[bufFrom] % powers10[shift]) * powers10[cShift]
+       }
+       for bufFrom > bufEnd {
+               d.wordBuf[bufFrom] = d.wordBuf[bufFrom]/powers10[shift] + (d.wordBuf[bufFrom-1]%powers10[shift])*powers10[cShift]
+               bufFrom--
+       }
+       d.wordBuf[bufFrom] = d.wordBuf[bufFrom] / powers10[shift]
+}
+
+// Round rounds the decimal to "frac" digits.
+//
+//    to                       - result buffer. d == to is allowed
+//    frac                     - to what position after fraction point to round. can be negative!
+//    roundMode                - round to nearest even or truncate
+//                     ModeHalfEven rounds normally.
+//                     Truncate just truncates the decimal.
+//
+// NOTES
+//  scale can be negative !
+//  one TRUNCATED error (line XXX below) isn't treated very logical :(
+//
+// RETURN VALUE
+//  eDecOK/eDecTruncated
+func (d *MyDecimal) Round(to *MyDecimal, frac int, roundMode RoundMode) (err error) {
+       // wordsFracTo is the number of fraction words in buffer.
+       wordsFracTo := (frac + 1) / digitsPerWord
+       if frac > 0 {
+               wordsFracTo = digitsToWords(frac)
+       }
+       wordsFrac := digitsToWords(int(d.digitsFrac))
+       wordsInt := digitsToWords(int(d.digitsInt))
+
+       roundDigit := int32(roundMode)
+       /* TODO - fix this code as it won't work for CEILING mode */
+
+       if wordsInt+wordsFracTo > wordBufLen {
+               wordsFracTo = wordBufLen - wordsInt
+               frac = wordsFracTo * digitsPerWord
+               err = ErrTruncated
+       }
+       if int(d.digitsInt)+frac < 0 {
+               *to = zeroMyDecimal
+               return nil
+       }
+       if to != d {
+               copy(to.wordBuf[:], d.wordBuf[:])
+               to.negative = d.negative
+               to.digitsInt = int8(myMin(wordsInt, wordBufLen) * digitsPerWord)
+       }
+       if wordsFracTo > wordsFrac {
+               idx := wordsInt + wordsFrac
+               for wordsFracTo > wordsFrac {
+                       wordsFracTo--
+                       to.wordBuf[idx] = 0
+                       idx++
+               }
+               to.digitsFrac = int8(frac)
+               to.resultFrac = to.digitsFrac
+               return
+       }
+       if frac >= int(d.digitsFrac) {
+               to.digitsFrac = int8(frac)
+               to.resultFrac = to.digitsFrac
+               return
+       }
+
+       // Do increment.
+       toIdx := wordsInt + wordsFracTo - 1
+       if frac == wordsFracTo*digitsPerWord {
+               doInc := false
+               switch roundMode {
+               // Notice: No support for ceiling mode now.
+               case modeCeiling:
+                       // If any word after scale is not zero, do increment.
+                       // e.g ceiling 3.0001 to scale 1, gets 3.1
+                       idx := toIdx + (wordsFrac - wordsFracTo)
+                       for idx > toIdx {
+                               if d.wordBuf[idx] != 0 {
+                                       doInc = true
+                                       break
+                               }
+                               idx--
+                       }
+               case ModeHalfEven:
+                       digAfterScale := d.wordBuf[toIdx+1] / digMask // the first digit after scale.
+                       // If first digit after scale is 5 and round even, do increment if digit at scale is odd.
+                       doInc = (digAfterScale > 5) || (digAfterScale == 5)
+               case ModeTruncate:
+                       // Never round, just truncate.
+                       doInc = false
+               }
+               if doInc {
+                       if toIdx >= 0 {
+                               to.wordBuf[toIdx]++
+                       } else {
+                               toIdx++
+                               to.wordBuf[toIdx] = wordBase
+                       }
+               } else if wordsInt+wordsFracTo == 0 {
+                       *to = zeroMyDecimal
+                       return nil
+               }
+       } else {
+               /* TODO - fix this code as it won't work for CEILING mode */
+               pos := wordsFracTo*digitsPerWord - frac - 1
+               shiftedNumber := to.wordBuf[toIdx] / powers10[pos]
+               digAfterScale := shiftedNumber % 10
+               if digAfterScale > roundDigit || (roundDigit == 5 && digAfterScale == 5) {
+                       shiftedNumber += 10
+               }
+               to.wordBuf[toIdx] = powers10[pos] * (shiftedNumber - digAfterScale)
+       }
+       /*
+          In case we're rounding e.g. 1.5e9 to 2.0e9, the decimal words inside
+          the buffer are as follows.
+
+          Before <1, 5e8>
+          After  <2, 5e8>
+
+          Hence we need to set the 2nd field to 0.
+          The same holds if we round 1.5e-9 to 2e-9.
+       */
+       if wordsFracTo < wordsFrac {
+               idx := wordsInt + wordsFracTo
+               if frac == 0 && wordsInt == 0 {
+                       idx = 1
+               }
+               for idx < wordBufLen {
+                       to.wordBuf[idx] = 0
+                       idx++
+               }
+       }
+
+       // Handle carry.
+       var carry int32
+       if to.wordBuf[toIdx] >= wordBase {
+               carry = 1
+               to.wordBuf[toIdx] -= wordBase
+               for carry == 1 && toIdx > 0 {
+                       toIdx--
+                       to.wordBuf[toIdx], carry = add(to.wordBuf[toIdx], 0, carry)
+               }
+               if carry > 0 {
+                       if wordsInt+wordsFracTo >= wordBufLen {
+                               wordsFracTo--
+                               frac = wordsFracTo * digitsPerWord
+                               err = ErrTruncated
+                       }
+                       for toIdx = wordsInt + myMax(wordsFracTo, 0); toIdx > 0; toIdx-- {
+                               if toIdx < wordBufLen {
+                                       to.wordBuf[toIdx] = to.wordBuf[toIdx-1]
+                               } else {
+                                       err = ErrOverflow
+                               }
+                       }
+                       to.wordBuf[toIdx] = 1
+                       /* We cannot have more than 9 * 9 = 81 digits. */
+                       if int(to.digitsInt) < digitsPerWord*wordBufLen {
+                               to.digitsInt++
+                       } else {
+                               err = ErrOverflow
+                       }
+               }
+       } else {
+               for {
+                       if to.wordBuf[toIdx] != 0 {
+                               break
+                       }
+                       if toIdx == 0 {
+                               /* making 'zero' with the proper scale */
+                               idx := wordsFracTo + 1
+                               to.digitsInt = 1
+                               to.digitsFrac = int8(myMax(frac, 0))
+                               to.negative = false
+                               for toIdx < idx {
+                                       to.wordBuf[toIdx] = 0
+                                       toIdx++
+                               }
+                               to.resultFrac = to.digitsFrac
+                               return nil
+                       }
+                       toIdx--
+               }
+       }
+       /* Here we check 999.9 -> 1000 case when we need to increase intDigCnt */
+       firstDig := mod9[to.digitsInt]
+       if firstDig > 0 && to.wordBuf[toIdx] >= powers10[firstDig] {
+               to.digitsInt++
+       }
+       if frac < 0 {
+               frac = 0
+       }
+       to.digitsFrac = int8(frac)
+       to.resultFrac = to.digitsFrac
+       return
+}
+
+// FromInt sets the decimal value from int64.
+func (d *MyDecimal) FromInt(val int64) *MyDecimal {
+       var uVal uint64
+       if val < 0 {
+               d.negative = true
+               uVal = uint64(-val)
+       } else {
+               uVal = uint64(val)
+       }
+       return d.FromUint(uVal)
+}
+
+// FromUint sets the decimal value from uint64.
+func (d *MyDecimal) FromUint(val uint64) *MyDecimal {
+       x := val
+       wordIdx := 1
+       for x >= wordBase {
+               wordIdx++
+               x /= wordBase
+       }
+       d.digitsFrac = 0
+       d.digitsInt = int8(wordIdx * digitsPerWord)
+       x = val
+       for wordIdx > 0 {
+               wordIdx--
+               y := x / wordBase
+               d.wordBuf[wordIdx] = int32(x - y*wordBase)
+               x = y
+       }
+       return d
+}
+
+// ToInt returns int part of the decimal, returns the result and errcode.
+func (d *MyDecimal) ToInt() (int64, error) {
+       var x int64
+       wordIdx := 0
+       for i := d.digitsInt; i > 0; i -= digitsPerWord {
+               y := x
+               /*
+                  Attention: trick!
+                  we're calculating -|from| instead of |from| here
+                  because |LONGLONG_MIN| > LONGLONG_MAX
+                  so we can convert -9223372036854775808 correctly
+               */
+               x = x*wordBase - int64(d.wordBuf[wordIdx])
+               wordIdx++
+               if y < math.MinInt64/wordBase || x > y {
+                       /*
+                          the decimal is bigger than any possible integer
+                          return border integer depending on the sign
+                       */
+                       if d.negative {
+                               return math.MinInt64, ErrOverflow
+                       }
+                       return math.MaxInt64, ErrOverflow
+               }
+       }
+       /* boundary case: 9223372036854775808 */
+       if !d.negative && x == math.MinInt64 {
+               return math.MaxInt64, ErrOverflow
+       }
+       if !d.negative {
+               x = -x
+       }
+       for i := d.digitsFrac; i > 0; i -= digitsPerWord {
+               if d.wordBuf[wordIdx] != 0 {
+                       return x, ErrTruncated
+               }
+               wordIdx++
+       }
+       return x, nil
+}
+
+// ToUint returns int part of the decimal, returns the result and errcode.
+func (d *MyDecimal) ToUint() (uint64, error) {
+       if d.negative {
+               return 0, ErrOverflow
+       }
+       var x uint64
+       wordIdx := 0
+       for i := d.digitsInt; i > 0; i -= digitsPerWord {
+               y := x
+               x = x*wordBase + uint64(d.wordBuf[wordIdx])
+               wordIdx++
+               if y > math.MaxUint64/wordBase || x < y {
+                       return math.MaxUint64, ErrOverflow
+               }
+       }
+       for i := d.digitsFrac; i > 0; i -= digitsPerWord {
+               if d.wordBuf[wordIdx] != 0 {
+                       return x, ErrTruncated
+               }
+               wordIdx++
+       }
+       return x, nil
+}
+
+// FromFloat64 creates a decimal from float64 value.
+func (d *MyDecimal) FromFloat64(f float64) error {
+       s := strconv.FormatFloat(f, 'g', -1, 64)
+       return d.FromString([]byte(s))
+}
+
+// ToFloat64 converts decimal to float64 value.
+func (d *MyDecimal) ToFloat64() (float64, error) {
+       f, err := strconv.ParseFloat(d.String(), 64)
+       if err != nil {
+               err = ErrOverflow
+       }
+       return f, err
+}
+
+/*
+ToBin converts decimal to its binary fixed-length representation
+two representations of the same length can be compared with memcmp
+with the correct -1/0/+1 result
+
+  PARAMS
+               precision/frac - if precision is 0, internal value of the decimal will be used,
+               then the encoded value is not memory comparable.
+
+  NOTE
+    the buffer is assumed to be of the size DecimalBinSize(precision, frac)
+
+  RETURN VALUE
+       bin     - binary value
+    errCode - eDecOK/eDecTruncate/eDecOverflow
+
+  DESCRIPTION
+    for storage decimal numbers are converted to the "binary" format.
+
+    This format has the following properties:
+      1. length of the binary representation depends on the {precision, frac}
+      as provided by the caller and NOT on the digitsInt/digitsFrac of the decimal to
+      convert.
+      2. binary representations of the same {precision, frac} can be compared
+      with memcmp - with the same result as DecimalCompare() of the original
+      decimals (not taking into account possible precision loss during
+      conversion).
+
+    This binary format is as follows:
+      1. First the number is converted to have a requested precision and frac.
+      2. Every full digitsPerWord digits of digitsInt part are stored in 4 bytes
+         as is
+      3. The first digitsInt % digitesPerWord digits are stored in the reduced
+         number of bytes (enough bytes to store this number of digits -
+         see dig2bytes)
+      4. same for frac - full word are stored as is,
+         the last frac % digitsPerWord digits - in the reduced number of bytes.
+      5. If the number is negative - every byte is inversed.
+      5. The very first bit of the resulting byte array is inverted (because
+         memcmp compares unsigned bytes, see property 2 above)
+
+    Example:
+
+      1234567890.1234
+
+    internally is represented as 3 words
+
+      1 234567890 123400000
+
+    (assuming we want a binary representation with precision=14, frac=4)
+    in hex it's
+
+      00-00-00-01  0D-FB-38-D2  07-5A-EF-40
+
+    now, middle word is full - it stores 9 decimal digits. It goes
+    into binary representation as is:
+
+
+      ...........  0D-FB-38-D2 ............
+
+    First word has only one decimal digit. We can store one digit in
+    one byte, no need to waste four:
+
+                01 0D-FB-38-D2 ............
+
+    now, last word. It's 123400000. We can store 1234 in two bytes:
+
+                01 0D-FB-38-D2 04-D2
+
+    So, we've packed 12 bytes number in 7 bytes.
+    And now we invert the highest bit to get the final result:
+
+                81 0D FB 38 D2 04 D2
+
+    And for -1234567890.1234 it would be
+
+                7E F2 04 C7 2D FB 2D
+*/
+func (d *MyDecimal) ToBin(precision, frac int) ([]byte, error) {
+       if precision > digitsPerWord*maxWordBufLen || precision < 0 || frac > MaxDecimalScale || frac < 0 {
+               return nil, ErrBadNumber
+       }
+       var err error
+       var mask int32
+       if d.negative {
+               mask = -1
+       }
+       digitsInt := precision - frac
+       wordsInt := digitsInt / digitsPerWord
+       leadingDigits := digitsInt - wordsInt*digitsPerWord
+       wordsFrac := frac / digitsPerWord
+       trailingDigits := frac - wordsFrac*digitsPerWord
+
+       wordsFracFrom := int(d.digitsFrac) / digitsPerWord
+       trailingDigitsFrom := int(d.digitsFrac) - wordsFracFrom*digitsPerWord
+       intSize := wordsInt*wordSize + dig2bytes[leadingDigits]
+       fracSize := wordsFrac*wordSize + dig2bytes[trailingDigits]
+       fracSizeFrom := wordsFracFrom*wordSize + dig2bytes[trailingDigitsFrom]
+       originIntSize := intSize
+       originFracSize := fracSize
+       bin := make([]byte, intSize+fracSize)
+       binIdx := 0
+       wordIdxFrom, digitsIntFrom := d.removeLeadingZeros()
+       if digitsIntFrom+fracSizeFrom == 0 {
+               mask = 0
+               digitsInt = 1
+       }
+
+       wordsIntFrom := digitsIntFrom / digitsPerWord
+       leadingDigitsFrom := digitsIntFrom - wordsIntFrom*digitsPerWord
+       iSizeFrom := wordsIntFrom*wordSize + dig2bytes[leadingDigitsFrom]
+
+       if digitsInt < digitsIntFrom {
+               wordIdxFrom += wordsIntFrom - wordsInt
+               if leadingDigitsFrom > 0 {
+                       wordIdxFrom++
+               }
+               if leadingDigits > 0 {
+                       wordIdxFrom--
+               }
+               wordsIntFrom = wordsInt
+               leadingDigitsFrom = leadingDigits
+               err = ErrOverflow
+       } else if intSize > iSizeFrom {
+               for intSize > iSizeFrom {
+                       intSize--
+                       bin[binIdx] = byte(mask)
+                       binIdx++
+               }
+       }
+
+       if fracSize < fracSizeFrom {
+               wordsFracFrom = wordsFrac
+               trailingDigitsFrom = trailingDigits
+               err = ErrTruncated
+       } else if fracSize > fracSizeFrom && trailingDigitsFrom > 0 {
+               if wordsFrac == wordsFracFrom {
+                       trailingDigitsFrom = trailingDigits
+                       fracSize = fracSizeFrom
+               } else {
+                       wordsFracFrom++
+                       trailingDigitsFrom = 0
+               }
+       }
+       // xIntFrom part
+       if leadingDigitsFrom > 0 {
+               i := dig2bytes[leadingDigitsFrom]
+               x := (d.wordBuf[wordIdxFrom] % powers10[leadingDigitsFrom]) ^ mask
+               wordIdxFrom++
+               writeWord(bin[binIdx:], x, i)
+               binIdx += i
+       }
+
+       // wordsInt + wordsFrac part.
+       for stop := wordIdxFrom + wordsIntFrom + wordsFracFrom; wordIdxFrom < stop; binIdx += wordSize {
+               x := d.wordBuf[wordIdxFrom] ^ mask
+               wordIdxFrom++
+               writeWord(bin[binIdx:], x, 4)
+       }
+
+       // xFracFrom part
+       if trailingDigitsFrom > 0 {
+               var x int32
+               i := dig2bytes[trailingDigitsFrom]
+               lim := trailingDigits
+               if wordsFracFrom < wordsFrac {
+                       lim = digitsPerWord
+               }
+
+               for trailingDigitsFrom < lim && dig2bytes[trailingDigitsFrom] == i {
+                       trailingDigitsFrom++
+               }
+               x = (d.wordBuf[wordIdxFrom] / powers10[digitsPerWord-trailingDigitsFrom]) ^ mask
+               writeWord(bin[binIdx:], x, i)
+               binIdx += i
+       }
+       if fracSize > fracSizeFrom {
+               binIdxEnd := originIntSize + originFracSize
+               for fracSize > fracSizeFrom && binIdx < binIdxEnd {
+                       fracSize--
+                       bin[binIdx] = byte(mask)
+                       binIdx++
+               }
+       }
+       bin[0] ^= 0x80
+       return bin, err
+}
+
+// ToHashKey removes the leading and trailing zeros and generates a hash key.
+// Two Decimals dec0 and dec1 with different fraction will generate the same hash keys if dec0.Compare(dec1) == 0.
+func (d *MyDecimal) ToHashKey() ([]byte, error) {
+       _, digitsInt := d.removeLeadingZeros()
+       _, digitsFrac := d.removeTrailingZeros()
+       prec := digitsInt + digitsFrac
+       if prec == 0 { // zeroDecimal
+               prec = 1
+       }
+       buf, err := d.ToBin(prec, digitsFrac)
+       if err == ErrTruncated {
+               // This err is caused by shorter digitsFrac;
+               // After removing the trailing zeros from a Decimal,
+               // so digitsFrac may be less than the real digitsFrac of the Decimal,
+               // thus ErrTruncated may be raised, we can ignore it here.
+               err = nil
+       }
+       return buf, err
+}
+
+// PrecisionAndFrac returns the internal precision and frac number.
+func (d *MyDecimal) PrecisionAndFrac() (precision, frac int) {
+       frac = int(d.digitsFrac)
+       _, digitsInt := d.removeLeadingZeros()
+       precision = digitsInt + frac
+       if precision == 0 {
+               precision = 1
+       }
+       return
+}
+
+// IsZero checks whether it's a zero decimal.
+func (d *MyDecimal) IsZero() bool {
+       isZero := true
+       for _, val := range d.wordBuf {
+               if val != 0 {
+                       isZero = false
+                       break
+               }
+       }
+       return isZero
+}
+
+// FromBin Restores decimal from its binary fixed-length representation.
+func (d *MyDecimal) FromBin(bin []byte, precision, frac int) (binSize int, err error) {
+       if len(bin) == 0 {
+               *d = zeroMyDecimal
+               return 0, ErrBadNumber
+       }
+       digitsInt := precision - frac
+       wordsInt := digitsInt / digitsPerWord
+       leadingDigits := digitsInt - wordsInt*digitsPerWord
+       wordsFrac := frac / digitsPerWord
+       trailingDigits := frac - wordsFrac*digitsPerWord
+       wordsIntTo := wordsInt
+       if leadingDigits > 0 {
+               wordsIntTo++
+       }
+       wordsFracTo := wordsFrac
+       if trailingDigits > 0 {
+               wordsFracTo++
+       }
+
+       binIdx := 0
+       mask := int32(-1)
+       if bin[binIdx]&0x80 > 0 {
+               mask = 0
+       }
+       binSize = DecimalBinSize(precision, frac)
+       dCopy := make([]byte, 40)
+       dCopy = dCopy[:binSize]
+       copy(dCopy, bin)
+       dCopy[0] ^= 0x80
+       bin = dCopy
+       oldWordsIntTo := wordsIntTo
+       wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
+       if err != nil {
+               if wordsIntTo < oldWordsIntTo {
+                       binIdx += dig2bytes[leadingDigits] + (wordsInt-wordsIntTo)*wordSize
+               } else {
+                       trailingDigits = 0
+                       wordsFrac = wordsFracTo
+               }
+       }
+       d.negative = mask != 0
+       d.digitsInt = int8(wordsInt*digitsPerWord + leadingDigits)
+       d.digitsFrac = int8(wordsFrac*digitsPerWord + trailingDigits)
+
+       wordIdx := 0
+       if leadingDigits > 0 {
+               i := dig2bytes[leadingDigits]
+               x := readWord(bin[binIdx:], i)
+               binIdx += i
+               d.wordBuf[wordIdx] = x ^ mask
+               if uint64(d.wordBuf[wordIdx]) >= uint64(powers10[leadingDigits+1]) {
+                       *d = zeroMyDecimal
+                       return binSize, ErrBadNumber
+               }
+               if wordIdx > 0 || d.wordBuf[wordIdx] != 0 {
+                       wordIdx++
+               } else {
+                       d.digitsInt -= int8(leadingDigits)
+               }
+       }
+       for stop := binIdx + wordsInt*wordSize; binIdx < stop; binIdx += wordSize {
+               d.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask
+               if uint32(d.wordBuf[wordIdx]) > wordMax {
+                       *d = zeroMyDecimal
+                       return binSize, ErrBadNumber
+               }
+               if wordIdx > 0 || d.wordBuf[wordIdx] != 0 {
+                       wordIdx++
+               } else {
+                       d.digitsInt -= digitsPerWord
+               }
+       }
+
+       for stop := binIdx + wordsFrac*wordSize; binIdx < stop; binIdx += wordSize {
+               d.wordBuf[wordIdx] = readWord(bin[binIdx:], 4) ^ mask
+               if uint32(d.wordBuf[wordIdx]) > wordMax {
+                       *d = zeroMyDecimal
+                       return binSize, ErrBadNumber
+               }
+               wordIdx++
+       }
+
+       if trailingDigits > 0 {
+               i := dig2bytes[trailingDigits]
+               x := readWord(bin[binIdx:], i)
+               d.wordBuf[wordIdx] = (x ^ mask) * powers10[digitsPerWord-trailingDigits]
+               if uint32(d.wordBuf[wordIdx]) > wordMax {
+                       *d = zeroMyDecimal
+                       return binSize, ErrBadNumber
+               }
+       }
+
+       if d.digitsInt == 0 && d.digitsFrac == 0 {
+               *d = zeroMyDecimal
+       }
+       d.resultFrac = int8(frac)
+       return binSize, err
+}
+
+// DecimalBinSize returns the size of array to hold a binary representation of a decimal.
+func DecimalBinSize(precision, frac int) int {
+       digitsInt := precision - frac
+       wordsInt := digitsInt / digitsPerWord
+       wordsFrac := frac / digitsPerWord
+       xInt := digitsInt - wordsInt*digitsPerWord
+       xFrac := frac - wordsFrac*digitsPerWord
+       return wordsInt*wordSize + dig2bytes[xInt] + wordsFrac*wordSize + dig2bytes[xFrac]
+}
+
+func readWord(b []byte, size int) int32 {
+       var x int32
+       switch size {
+       case 1:
+               x = int32(int8(b[0]))
+       case 2:
+               x = int32(int8(b[0]))<<8 + int32(b[1])
+       case 3:
+               if b[0]&128 > 0 {
+                       x = int32(uint32(255)<<24 | uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
+               } else {
+                       x = int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
+               }
+       case 4:
+               x = int32(b[3]) + int32(b[2])<<8 + int32(b[1])<<16 + int32(int8(b[0]))<<24
+       }
+       return x
+}
+
+func writeWord(b []byte, word int32, size int) {
+       v := uint32(word)
+       switch size {
+       case 1:
+               b[0] = byte(word)
+       case 2:
+               b[0] = byte(v >> 8)
+               b[1] = byte(v)
+       case 3:
+               b[0] = byte(v >> 16)
+               b[1] = byte(v >> 8)
+               b[2] = byte(v)
+       case 4:
+               b[0] = byte(v >> 24)
+               b[1] = byte(v >> 16)
+               b[2] = byte(v >> 8)
+               b[3] = byte(v)
+       }
+}
+
+// Compare compares one decimal to another, returns -1/0/1.
+func (d *MyDecimal) Compare(to *MyDecimal) int {
+       if d.negative == to.negative {
+               cmp, err := doSub(d, to, nil)
+               Log(err)
+               return cmp
+       }
+       if d.negative {
+               return -1
+       }
+       return 1
+}
+
+// DecimalNeg reverses decimal's sign.
+func DecimalNeg(from *MyDecimal) *MyDecimal {
+       to := *from
+       if from.IsZero() {
+               return &to
+       }
+       to.negative = !from.negative
+       return &to
+}
+
+// DecimalAdd adds two decimals, sets the result to 'to'.
+// Note: DO NOT use `from1` or `from2` as `to` since the metadata
+// of `to` may be changed during evaluating.
+func DecimalAdd(from1, from2, to *MyDecimal) error {
+       from1, from2, to = validateArgs(from1, from2, to)
+       to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
+       if from1.negative == from2.negative {
+               return doAdd(from1, from2, to)
+       }
+       _, err := doSub(from1, from2, to)
+       return err
+}
+
+// DecimalSub subs one decimal from another, sets the result to 'to'.
+func DecimalSub(from1, from2, to *MyDecimal) error {
+       from1, from2, to = validateArgs(from1, from2, to)
+       to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
+       if from1.negative == from2.negative {
+               _, err := doSub(from1, from2, to)
+               return err
+       }
+       return doAdd(from1, from2, to)
+}
+
+func validateArgs(f1, f2, to *MyDecimal) (*MyDecimal, *MyDecimal, *MyDecimal) {
+       if to == nil {
+               return f1, f2, to
+       }
+       if f1 == to {
+               tmp := *f1
+               f1 = &tmp
+       }
+       if f2 == to {
+               tmp := *f2
+               f2 = &tmp
+       }
+       to.digitsFrac = 0
+       to.digitsInt = 0
+       to.resultFrac = 0
+       to.negative = false
+       for i := range to.wordBuf {
+               to.wordBuf[i] = 0
+       }
+       return f1, f2, to
+}
+
+func doSub(from1, from2, to *MyDecimal) (cmp int, err error) {
+       var (
+               wordsInt1   = digitsToWords(int(from1.digitsInt))
+               wordsFrac1  = digitsToWords(int(from1.digitsFrac))
+               wordsInt2   = digitsToWords(int(from2.digitsInt))
+               wordsFrac2  = digitsToWords(int(from2.digitsFrac))
+               wordsFracTo = myMax(wordsFrac1, wordsFrac2)
+
+               start1 = 0
+               stop1  = wordsInt1
+               idx1   = 0
+               start2 = 0
+               stop2  = wordsInt2
+               idx2   = 0
+       )
+       if from1.wordBuf[idx1] == 0 {
+               for idx1 < stop1 && from1.wordBuf[idx1] == 0 {
+                       idx1++
+               }
+               start1 = idx1
+               wordsInt1 = stop1 - idx1
+       }
+       if from2.wordBuf[idx2] == 0 {
+               for idx2 < stop2 && from2.wordBuf[idx2] == 0 {
+                       idx2++
+               }
+               start2 = idx2
+               wordsInt2 = stop2 - idx2
+       }
+
+       var carry int32
+       if wordsInt2 > wordsInt1 {
+               carry = 1
+       } else if wordsInt2 == wordsInt1 {
+               end1 := stop1 + wordsFrac1 - 1
+               end2 := stop2 + wordsFrac2 - 1
+               for idx1 <= end1 && from1.wordBuf[end1] == 0 {
+                       end1--
+               }
+               for idx2 <= end2 && from2.wordBuf[end2] == 0 {
+                       end2--
+               }
+               wordsFrac1 = end1 - stop1 + 1
+               wordsFrac2 = end2 - stop2 + 1
+               for idx1 <= end1 && idx2 <= end2 && from1.wordBuf[idx1] == from2.wordBuf[idx2] {
+                       idx1++
+                       idx2++
+               }
+               if idx1 <= end1 {
+                       if idx2 <= end2 && from2.wordBuf[idx2] > from1.wordBuf[idx1] {
+                               carry = 1
+                       } else {
+                               carry = 0
+                       }
+               } else {
+                       if idx2 <= end2 {
+                               carry = 1
+                       } else {
+                               if to == nil {
+                                       return 0, nil
+                               }
+                               *to = zeroMyDecimalWithFrac(to.resultFrac)
+                               return 0, nil
+                       }
+               }
+       }
+
+       if to == nil {
+               if carry > 0 == from1.negative { // from2 is negative too.
+                       return 1, nil
+               }
+               return -1, nil
+       }
+
+       to.negative = from1.negative
+
+       /* ensure that always idx1 > idx2 (and wordsInt1 >= wordsInt2) */
+       if carry > 0 {
+               from1, from2 = from2, from1
+               start1, start2 = start2, start1
+               wordsInt1, wordsInt2 = wordsInt2, wordsInt1
+               wordsFrac1, wordsFrac2 = wordsFrac2, wordsFrac1
+               to.negative = !to.negative
+       }
+
+       wordsInt1, wordsFracTo, err = fixWordCntError(wordsInt1, wordsFracTo)
+       idxTo := wordsInt1 + wordsFracTo
+       to.digitsFrac = from1.digitsFrac
+       if to.digitsFrac < from2.digitsFrac {
+               to.digitsFrac = from2.digitsFrac
+       }
+       to.digitsInt = int8(wordsInt1 * digitsPerWord)
+       if err != nil {
+               if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
+                       to.digitsFrac = int8(wordsFracTo * digitsPerWord)
+               }
+               if wordsFrac1 > wordsFracTo {
+                       wordsFrac1 = wordsFracTo
+               }
+               if wordsFrac2 > wordsFracTo {
+                       wordsFrac2 = wordsFracTo
+               }
+               if wordsInt2 > wordsInt1 {
+                       wordsInt2 = wordsInt1
+               }
+       }
+       carry = 0
+
+       /* part 1 - max(frac) ... min (frac) */
+       if wordsFrac1 > wordsFrac2 {
+               idx1 = start1 + wordsInt1 + wordsFrac1
+               stop1 = start1 + wordsInt1 + wordsFrac2
+               idx2 = start2 + wordsInt2 + wordsFrac2
+               for wordsFracTo > wordsFrac1 {
+                       wordsFracTo--
+                       idxTo--
+                       to.wordBuf[idxTo] = 0
+               }
+               for idx1 > stop1 {
+                       idxTo--
+                       idx1--
+                       to.wordBuf[idxTo] = from1.wordBuf[idx1]
+               }
+       } else {
+               idx1 = start1 + wordsInt1 + wordsFrac1
+               idx2 = start2 + wordsInt2 + wordsFrac2
+               stop2 = start2 + wordsInt2 + wordsFrac1
+               for wordsFracTo > wordsFrac2 {
+                       wordsFracTo--
+                       idxTo--
+                       to.wordBuf[idxTo] = 0
+               }
+               for idx2 > stop2 {
+                       idxTo--
+                       idx2--
+                       to.wordBuf[idxTo], carry = sub(0, from2.wordBuf[idx2], carry)
+               }
+       }
+
+       /* part 2 - min(frac) ... wordsInt2 */
+       for idx2 > start2 {
+               idxTo--
+               idx1--
+               idx2--
+               to.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], from2.wordBuf[idx2], carry)
+       }
+
+       /* part 3 - wordsInt2 ... wordsInt1 */
+       for carry > 0 && idx1 > start1 {
+               idxTo--
+               idx1--
+               to.wordBuf[idxTo], carry = sub(from1.wordBuf[idx1], 0, carry)
+       }
+       for idx1 > start1 {
+               idxTo--
+               idx1--
+               to.wordBuf[idxTo] = from1.wordBuf[idx1]
+       }
+       for idxTo > 0 {
+               idxTo--
+               to.wordBuf[idxTo] = 0
+       }
+       return 0, err
+}
+
+func doAdd(from1, from2, to *MyDecimal) error {
+       var (
+               err         error
+               wordsInt1   = digitsToWords(int(from1.digitsInt))
+               wordsFrac1  = digitsToWords(int(from1.digitsFrac))
+               wordsInt2   = digitsToWords(int(from2.digitsInt))
+               wordsFrac2  = digitsToWords(int(from2.digitsFrac))
+               wordsIntTo  = myMax(wordsInt1, wordsInt2)
+               wordsFracTo = myMax(wordsFrac1, wordsFrac2)
+       )
+
+       var x int32
+       if wordsInt1 > wordsInt2 {
+               x = from1.wordBuf[0]
+       } else if wordsInt2 > wordsInt1 {
+               x = from2.wordBuf[0]
+       } else {
+               x = from1.wordBuf[0] + from2.wordBuf[0]
+       }
+       if x > wordMax-1 { /* yes, there is */
+               wordsIntTo++
+               to.wordBuf[0] = 0 /* safety */
+       }
+
+       wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
+       if err == ErrOverflow {
+               maxDecimal(wordBufLen*digitsPerWord, 0, to)
+               return err
+       }
+       idxTo := wordsIntTo + wordsFracTo
+       to.negative = from1.negative
+       to.digitsInt = int8(wordsIntTo * digitsPerWord)
+       to.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)
+
+       if err != nil {
+               if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
+                       to.digitsFrac = int8(wordsFracTo * digitsPerWord)
+               }
+               if wordsFrac1 > wordsFracTo {
+                       wordsFrac1 = wordsFracTo
+               }
+               if wordsFrac2 > wordsFracTo {
+                       wordsFrac2 = wordsFracTo
+               }
+               if wordsInt1 > wordsIntTo {
+                       wordsInt1 = wordsIntTo
+               }
+               if wordsInt2 > wordsIntTo {
+                       wordsInt2 = wordsIntTo
+               }
+       }
+       var dec1, dec2 = from1, from2
+       var idx1, idx2, stop, stop2 int
+       /* part 1 - max(frac) ... min (frac) */
+       if wordsFrac1 > wordsFrac2 {
+               idx1 = wordsInt1 + wordsFrac1
+               stop = wordsInt1 + wordsFrac2
+               idx2 = wordsInt2 + wordsFrac2
+               if wordsInt1 > wordsInt2 {
+                       stop2 = wordsInt1 - wordsInt2
+               }
+       } else {
+               idx1 = wordsInt2 + wordsFrac2
+               stop = wordsInt2 + wordsFrac1
+               idx2 = wordsInt1 + wordsFrac1
+               if wordsInt2 > wordsInt1 {
+                       stop2 = wordsInt2 - wordsInt1
+               }
+               dec1, dec2 = from2, from1
+       }
+       for idx1 > stop {
+               idxTo--
+               idx1--
+               to.wordBuf[idxTo] = dec1.wordBuf[idx1]
+       }
+
+       /* part 2 - min(frac) ... min(digitsInt) */
+       carry := int32(0)
+       for idx1 > stop2 {
+               idx1--
+               idx2--
+               idxTo--
+               to.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], dec2.wordBuf[idx2], carry)
+       }
+
+       /* part 3 - min(digitsInt) ... max(digitsInt) */
+       stop = 0
+       if wordsInt1 > wordsInt2 {
+               idx1 = wordsInt1 - wordsInt2
+               dec1 = from1
+       } else {
+               idx1 = wordsInt2 - wordsInt1
+               dec1 = from2
+       }
+       for idx1 > stop {
+               idxTo--
+               idx1--
+               to.wordBuf[idxTo], carry = add(dec1.wordBuf[idx1], 0, carry)
+       }
+       if carry > 0 {
+               idxTo--
+               to.wordBuf[idxTo] = 1
+       }
+       return err
+}
+
+func maxDecimal(precision, frac int, to *MyDecimal) {
+       digitsInt := precision - frac
+       to.negative = false
+       to.digitsInt = int8(digitsInt)
+       idx := 0
+       if digitsInt > 0 {
+               firstWordDigits := digitsInt % digitsPerWord
+               if firstWordDigits > 0 {
+                       to.wordBuf[idx] = powers10[firstWordDigits] - 1 /* get 9 99 999 ... */
+                       idx++
+               }
+               for digitsInt /= digitsPerWord; digitsInt > 0; digitsInt-- {
+                       to.wordBuf[idx] = wordMax
+                       idx++
+               }
+       }
+       to.digitsFrac = int8(frac)
+       if frac > 0 {
+               lastDigits := frac % digitsPerWord
+               for frac /= digitsPerWord; frac > 0; frac-- {
+                       to.wordBuf[idx] = wordMax
+                       idx++
+               }
+               if lastDigits > 0 {
+                       to.wordBuf[idx] = fracMax[lastDigits-1]
+               }
+       }
+}
+
+/*
+DecimalMul multiplies two decimals.
+
+      from1, from2 - factors
+      to      - product
+
+  RETURN VALUE
+    E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW;
+
+  NOTES
+    in this implementation, with wordSize=4 we have digitsPerWord=9,
+    and 63-digit number will take only 7 words (basically a 7-digit
+    "base 999999999" number).  Thus there's no need in fast multiplication
+    algorithms, 7-digit numbers can be multiplied with a naive O(n*n)
+    method.
+
+    XXX if this library is to be used with huge numbers of thousands of
+    digits, fast multiplication must be implemented.
+*/
+func DecimalMul(from1, from2, to *MyDecimal) error {
+       from1, from2, to = validateArgs(from1, from2, to)
+       var (
+               err         error
+               wordsInt1   = digitsToWords(int(from1.digitsInt))
+               wordsFrac1  = digitsToWords(int(from1.digitsFrac))
+               wordsInt2   = digitsToWords(int(from2.digitsInt))
+               wordsFrac2  = digitsToWords(int(from2.digitsFrac))
+               wordsIntTo  = digitsToWords(int(from1.digitsInt) + int(from2.digitsInt))
+               wordsFracTo = wordsFrac1 + wordsFrac2
+               idx1        = wordsInt1
+               idx2        = wordsInt2
+               idxTo       int
+               tmp1        = wordsIntTo
+               tmp2        = wordsFracTo
+       )
+       to.resultFrac = myMinInt8(from1.resultFrac+from2.resultFrac, MaxDecimalScale)
+       wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
+       to.negative = from1.negative != from2.negative
+       to.digitsFrac = from1.digitsFrac + from2.digitsFrac
+       if to.digitsFrac > notFixedDec {
+               to.digitsFrac = notFixedDec
+       }
+       to.digitsInt = int8(wordsIntTo * digitsPerWord)
+       if err == ErrOverflow {
+               return err
+       }
+       if err != nil {
+               if to.digitsFrac > int8(wordsFracTo*digitsPerWord) {
+                       to.digitsFrac = int8(wordsFracTo * digitsPerWord)
+               }
+               if to.digitsInt > int8(wordsIntTo*digitsPerWord) {
+                       to.digitsInt = int8(wordsIntTo * digitsPerWord)
+               }
+               if tmp1 > wordsIntTo {
+                       tmp1 -= wordsIntTo
+                       tmp2 = tmp1 >> 1
+                       wordsInt2 -= tmp1 - tmp2
+                       wordsFrac1 = 0
+                       wordsFrac2 = 0
+               } else {
+                       tmp2 -= wordsFracTo
+                       tmp1 = tmp2 >> 1
+                       if wordsFrac1 <= wordsFrac2 {
+                               wordsFrac1 -= tmp1
+                               wordsFrac2 -= tmp2 - tmp1
+                       } else {
+                               wordsFrac2 -= tmp1
+                               wordsFrac1 -= tmp2 - tmp1
+                       }
+               }
+       }
+       startTo := wordsIntTo + wordsFracTo - 1
+       start2 := idx2 + wordsFrac2 - 1
+       stop1 := idx1 - wordsInt1
+       stop2 := idx2 - wordsInt2
+       to.wordBuf = zeroMyDecimal.wordBuf
+
+       for idx1 += wordsFrac1 - 1; idx1 >= stop1; idx1-- {
+               carry := int32(0)
+               idxTo = startTo
+               idx2 = start2
+               for idx2 >= stop2 {
+                       var hi, lo int32
+                       p := int64(from1.wordBuf[idx1]) * int64(from2.wordBuf[idx2])
+                       hi = int32(p / wordBase)
+                       lo = int32(p - int64(hi)*wordBase)
+                       to.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], lo, carry)
+                       carry += hi
+                       idx2--
+                       idxTo--
+               }
+               if carry > 0 {
+                       if idxTo < 0 {
+                               return ErrOverflow
+                       }
+                       to.wordBuf[idxTo], carry = add2(to.wordBuf[idxTo], 0, carry)
+               }
+               for idxTo--; carry > 0; idxTo-- {
+                       if idxTo < 0 {
+                               return ErrOverflow
+                       }
+                       to.wordBuf[idxTo], carry = add(to.wordBuf[idxTo], 0, carry)
+               }
+               startTo--
+       }
+
+       /* Now we have to check for -0.000 case */
+       if to.negative {
+               idx := 0
+               end := wordsIntTo + wordsFracTo
+               for {
+                       if to.wordBuf[idx] != 0 {
+                               break
+                       }
+                       idx++
+                       /* We got decimal zero */
+                       if idx == end {
+                               *to = zeroMyDecimalWithFrac(to.resultFrac)
+                               break
+                       }
+               }
+       }
+
+       idxTo = 0
+       dToMove := wordsIntTo + digitsToWords(int(to.digitsFrac))
+       for to.wordBuf[idxTo] == 0 && to.digitsInt > digitsPerWord {
+               idxTo++
+               to.digitsInt -= digitsPerWord
+               dToMove--
+       }
+       if idxTo > 0 {
+               curIdx := 0
+               for dToMove > 0 {
+                       to.wordBuf[curIdx] = to.wordBuf[idxTo]
+                       curIdx++
+                       idxTo++
+                       dToMove--
+               }
+       }
+       return err
+}
+
+// DecimalDiv does division of two decimals.
+//
+// from1    - dividend
+// from2    - divisor
+// to       - quotient
+// fracIncr - increment of fraction
+func DecimalDiv(from1, from2, to *MyDecimal, fracIncr int) error {
+       from1, from2, to = validateArgs(from1, from2, to)
+       to.resultFrac = myMinInt8(from1.resultFrac+int8(fracIncr), MaxDecimalScale)
+       return doDivMod(from1, from2, to, nil, fracIncr)
+}
+
+/*
+DecimalMod does modulus of two decimals.
+
+      from1   - dividend
+      from2   - divisor
+      to      - modulus
+
+  RETURN VALUE
+    E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW/E_DEC_DIV_ZERO;
+
+  NOTES
+    see do_div_mod()
+
+  DESCRIPTION
+    the modulus R in    R = M mod N
+
+   is defined as
+
+     0 <= |R| < |M|
+     sign R == sign M
+     R = M - k*N, where k is integer
+
+   thus, there's no requirement for M or N to be integers
+*/
+func DecimalMod(from1, from2, to *MyDecimal) error {
+       from1, from2, to = validateArgs(from1, from2, to)
+       to.resultFrac = myMaxInt8(from1.resultFrac, from2.resultFrac)
+       return doDivMod(from1, from2, nil, to, 0)
+}
+
+func doDivMod(from1, from2, to, mod *MyDecimal, fracIncr int) error {
+       var (
+               frac1 = digitsToWords(int(from1.digitsFrac)) * digitsPerWord
+               prec1 = int(from1.digitsInt) + frac1
+               frac2 = digitsToWords(int(from2.digitsFrac)) * digitsPerWord
+               prec2 = int(from2.digitsInt) + frac2
+       )
+       if mod != nil {
+               to = mod
+       }
+
+       /* removing all the leading zeros */
+       i := ((prec2 - 1) % digitsPerWord) + 1
+       idx2 := 0
+       for prec2 > 0 && from2.wordBuf[idx2] == 0 {
+               prec2 -= i
+               i = digitsPerWord
+               idx2++
+       }
+       if prec2 <= 0 {
+               /* short-circuit everything: from2 == 0 */
+               return ErrDivByZero
+       }
+
+       prec2 -= countLeadingZeroes((prec2-1)%digitsPerWord, from2.wordBuf[idx2])
+       i = ((prec1 - 1) % digitsPerWord) + 1
+       idx1 := 0
+       for prec1 > 0 && from1.wordBuf[idx1] == 0 {
+               prec1 -= i
+               i = digitsPerWord
+               idx1++
+       }
+       if prec1 <= 0 {
+               /* short-circuit everything: from1 == 0 */
+               *to = zeroMyDecimalWithFrac(to.resultFrac)
+               return nil
+       }
+       prec1 -= countLeadingZeroes((prec1-1)%digitsPerWord, from1.wordBuf[idx1])
+
+       /* let's fix fracIncr, taking into account frac1,frac2 increase */
+       fracIncr -= frac1 - int(from1.digitsFrac) + frac2 - int(from2.digitsFrac)
+       if fracIncr < 0 {
+               fracIncr = 0
+       }
+
+       digitsIntTo := (prec1 - frac1) - (prec2 - frac2)
+       if from1.wordBuf[idx1] >= from2.wordBuf[idx2] {
+               digitsIntTo++
+       }
+       var wordsIntTo int
+       if digitsIntTo < 0 {
+               digitsIntTo /= digitsPerWord
+               wordsIntTo = 0
+       } else {
+               wordsIntTo = digitsToWords(digitsIntTo)
+       }
+       var wordsFracTo int
+       var err error
+       if mod != nil {
+               // we're calculating N1 % N2.
+               // The result will have
+               // digitsFrac=max(frac1, frac2), as for subtraction
+               // digitsInt=from2.digitsInt
+               to.negative = from1.negative
+               to.digitsFrac = myMaxInt8(from1.digitsFrac, from2.digitsFrac)
+       } else {
+               wordsFracTo = digitsToWords(frac1 + frac2 + fracIncr)
+               wordsIntTo, wordsFracTo, err = fixWordCntError(wordsIntTo, wordsFracTo)
+               to.negative = from1.negative != from2.negative
+               to.digitsInt = int8(wordsIntTo * digitsPerWord)
+               to.digitsFrac = int8(wordsFracTo * digitsPerWord)
+       }
+       idxTo := 0
+       stopTo := wordsIntTo + wordsFracTo
+       if mod == nil {
+               for digitsIntTo < 0 && idxTo < wordBufLen {
+                       to.wordBuf[idxTo] = 0
+                       idxTo++
+                       digitsIntTo++
+               }
+       }
+       i = digitsToWords(prec1)
+       len1 := i + digitsToWords(2*frac2+fracIncr+1) + 1
+       if len1 < 3 {
+               len1 = 3
+       }
+
+       tmp1 := make([]int32, len1)
+       copy(tmp1, from1.wordBuf[idx1:idx1+i])
+
+       start1 := 0
+       var stop1 int
+       start2 := idx2
+       stop2 := idx2 + digitsToWords(prec2) - 1
+
+       /* removing end zeroes */
+       for from2.wordBuf[stop2] == 0 && stop2 >= start2 {
+               stop2--
+       }
+       len2 := stop2 - start2
+       stop2++
+
+       /*
+          calculating norm2 (normalized from2.wordBuf[start2]) - we need from2.wordBuf[start2] to be large
+          (at least > DIG_BASE/2), but unlike Knuth's Alg. D we don't want to
+          normalize input numbers (as we don't make a copy of the divisor).
+          Thus we normalize first dec1 of buf2 only, and we'll normalize tmp1[start1]
+          on the fly for the purpose of guesstimation only.
+          It's also faster, as we're saving on normalization of from2.
+       */
+       normFactor := wordBase / int64(from2.wordBuf[start2]+1)
+       norm2 := int32(normFactor * int64(from2.wordBuf[start2]))
+       if len2 > 0 {
+               norm2 += int32(normFactor * int64(from2.wordBuf[start2+1]) / wordBase)
+       }
+       dcarry := int32(0)
+       if tmp1[start1] < from2.wordBuf[start2] {
+               dcarry = tmp1[start1]
+               start1++
+       }
+
+       // main loop
+       var guess int64
+       for ; idxTo < stopTo; idxTo++ {
+               /* short-circuit, if possible */
+               if dcarry == 0 && tmp1[start1] < from2.wordBuf[start2] {
+                       guess = 0
+               } else {
+                       /* D3: make a guess */
+                       x := int64(tmp1[start1]) + int64(dcarry)*wordBase
+                       y := int64(tmp1[start1+1])
+                       guess = (normFactor*x + normFactor*y/wordBase) / int64(norm2)
+                       if guess >= wordBase {
+                               guess = wordBase - 1
+                       }
+
+                       if len2 > 0 {
+                               /* remove normalization */
+                               if int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {
+                                       guess--
+                               }
+                               if int64(from2.wordBuf[start2+1])*guess > (x-guess*int64(from2.wordBuf[start2]))*wordBase+y {
+                                       guess--
+                               }
+                       }
+
+                       /* D4: multiply and subtract */
+                       idx2 = stop2
+                       idx1 = start1 + len2
+                       var carry int32
+                       for carry = 0; idx2 > start2; idx1-- {
+                               var hi, lo int32
+                               idx2--
+                               x = guess * int64(from2.wordBuf[idx2])
+                               hi = int32(x / wordBase)
+                               lo = int32(x - int64(hi)*wordBase)
+                               tmp1[idx1], carry = sub2(tmp1[idx1], lo, carry)
+                               carry += hi
+                       }
+                       if dcarry < carry {
+                               carry = 1
+                       } else {
+                               carry = 0
+                       }
+
+                       /* D5: check the remainder */
+                       if carry > 0 {
+                               /* D6: correct the guess */
+                               guess--
+                               idx2 = stop2
+                               idx1 = start1 + len2
+                               for carry = 0; idx2 > start2; idx1-- {
+                                       idx2--
+                                       tmp1[idx1], carry = add(tmp1[idx1], from2.wordBuf[idx2], carry)
+                               }
+                       }
+               }
+               if mod == nil {
+                       to.wordBuf[idxTo] = int32(guess)
+               }
+               dcarry = tmp1[start1]
+               start1++
+       }
+       if mod != nil {
+               /*
+                  now the result is in tmp1, it has
+                  digitsInt=prec1-frac1
+                  digitsFrac=max(frac1, frac2)
+               */
+               if dcarry != 0 {
+                       start1--
+                       tmp1[start1] = dcarry
+               }
+               idxTo = 0
+
+               digitsIntTo = prec1 - frac1 - start1*digitsPerWord
+               if digitsIntTo < 0 {
+                       /* If leading zeroes in the fractional part were earlier stripped */
+                       wordsIntTo = digitsIntTo / digitsPerWord
+               } else {
+                       wordsIntTo = digitsToWords(digitsIntTo)
+               }
+
+               wordsFracTo = digitsToWords(int(to.digitsFrac))
+               err = nil
+               if wordsIntTo == 0 && wordsFracTo == 0 {
+                       *to = zeroMyDecimal
+                       return err
+               }
+               if wordsIntTo <= 0 {
+                       if -wordsIntTo >= wordBufLen {
+                               *to = zeroMyDecimal
+                               return ErrTruncated
+                       }
+                       stop1 = start1 + wordsIntTo + wordsFracTo
+                       wordsFracTo += wordsIntTo
+                       to.digitsInt = 0
+                       for wordsIntTo < 0 {
+                               to.wordBuf[idxTo] = 0
+                               idxTo++
+                               wordsIntTo++
+                       }
+               } else {
+                       if wordsIntTo > wordBufLen {
+                               to.digitsInt = int8(digitsPerWord * wordBufLen)
+                               to.digitsFrac = 0
+                               return ErrOverflow
+                       }
+                       stop1 = start1 + wordsIntTo + wordsFracTo
+                       to.digitsInt = int8(myMin(wordsIntTo*digitsPerWord, int(from2.digitsInt)))
+               }
+               if wordsIntTo+wordsFracTo > wordBufLen {
+                       stop1 -= wordsIntTo + wordsFracTo - wordBufLen
+                       wordsFracTo = wordBufLen - wordsIntTo
+                       to.digitsFrac = int8(wordsFracTo * digitsPerWord)
+                       err = ErrTruncated
+               }
+               for start1 < stop1 {
+                       to.wordBuf[idxTo] = tmp1[start1]
+                       idxTo++
+                       start1++
+               }
+       }
+       idxTo, digitsIntTo = to.removeLeadingZeros()
+       to.digitsInt = int8(digitsIntTo)
+       if idxTo != 0 {
+               copy(to.wordBuf[:], to.wordBuf[idxTo:])
+       }
+       return err
+}
+
+// DecimalPeak returns the length of the encoded decimal.
+func DecimalPeak(b []byte) (int, error) {
+       if len(b) < 3 {
+               return 0, ErrBadNumber
+       }
+       precision := int(b[0])
+       frac := int(b[1])
+       return DecimalBinSize(precision, frac) + 2, nil
+}
+
+// NewDecFromInt creates a MyDecimal from int.
+func NewDecFromInt(i int64) *MyDecimal {
+       return new(MyDecimal).FromInt(i)
+}
+
+// NewDecFromUint creates a MyDecimal from uint.
+func NewDecFromUint(i uint64) *MyDecimal {
+       return new(MyDecimal).FromUint(i)
+}
+
+// NewDecFromFloatForTest creates a MyDecimal from float, as it returns no error, it should only be used in test.
+func NewDecFromFloatForTest(f float64) *MyDecimal {
+       dec := new(MyDecimal)
+       err := dec.FromFloat64(f)
+       Log(err)
+       return dec
+}
+
+// NewDecFromStringForTest creates a MyDecimal from string, as it returns no error, it should only be used in test.
+func NewDecFromStringForTest(s string) *MyDecimal {
+       dec := new(MyDecimal)
+       err := dec.FromString([]byte(s))
+       Log(err)
+       return dec
+}
+
+// NewMaxOrMinDec returns the max or min value decimal for given precision and fraction.
+func NewMaxOrMinDec(negative bool, prec, frac int) *MyDecimal {
+       str := make([]byte, prec+2)
+       for i := 0; i < len(str); i++ {
+               str[i] = '9'
+       }
+       if negative {
+               str[0] = '-'
+       } else {
+               str[0] = '+'
+       }
+       str[1+prec-frac] = '.'
+       dec := new(MyDecimal)
+       err := dec.FromString(str)
+       Log(err)
+       return dec
+}