mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-04 13:28:25 +00:00 
			
		
		
		
	* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
		
			
				
	
	
		
			756 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			756 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// The MIT License (MIT)
 | 
						|
 | 
						|
// Copyright (c) 2015 Spring, Inc.
 | 
						|
 | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
// of this software and associated documentation files (the "Software"), to deal
 | 
						|
// in the Software without restriction, including without limitation the rights
 | 
						|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
// copies of the Software, and to permit persons to whom the Software is
 | 
						|
// furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
// The above copyright notice and this permission notice shall be included in
 | 
						|
// all copies or substantial portions of the Software.
 | 
						|
 | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						|
// THE SOFTWARE.
 | 
						|
 | 
						|
// - Based on https://github.com/oguzbilgic/fpd, which has the following license:
 | 
						|
// """
 | 
						|
// The MIT License (MIT)
 | 
						|
 | 
						|
// Copyright (c) 2013 Oguz Bilgic
 | 
						|
 | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
						|
// this software and associated documentation files (the "Software"), to deal in
 | 
						|
// the Software without restriction, including without limitation the rights to
 | 
						|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
						|
// the Software, and to permit persons to whom the Software is furnished to do so,
 | 
						|
// subject to the following conditions:
 | 
						|
 | 
						|
// The above copyright notice and this permission notice shall be included in all
 | 
						|
// copies or substantial portions of the Software.
 | 
						|
 | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
						|
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
						|
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
						|
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
						|
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
// """
 | 
						|
 | 
						|
// 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.
 | 
						|
 | 
						|
package mysql
 | 
						|
 | 
						|
// Decimal implements an arbitrary precision fixed-point decimal.
 | 
						|
//
 | 
						|
// To use as part of a struct:
 | 
						|
//
 | 
						|
//     type Struct struct {
 | 
						|
//         Number Decimal
 | 
						|
//     }
 | 
						|
//
 | 
						|
// The zero-value of a Decimal is 0, as you would expect.
 | 
						|
//
 | 
						|
// The best way to create a new Decimal is to use decimal.NewFromString, ex:
 | 
						|
//
 | 
						|
//     n, err := decimal.NewFromString("-123.4567")
 | 
						|
//     n.String() // output: "-123.4567"
 | 
						|
//
 | 
						|
// NOTE: this can "only" represent numbers with a maximum of 2^31 digits
 | 
						|
// after the decimal point.
 | 
						|
 | 
						|
import (
 | 
						|
	"database/sql/driver"
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"math/big"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
// DivisionPrecision is the number of decimal places in the result when it
 | 
						|
// doesn't divide exactly.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)
 | 
						|
//     d1.String() // output: "0.6667"
 | 
						|
//     d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)
 | 
						|
//     d2.String() // output: "0.0001"
 | 
						|
//     d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)
 | 
						|
//     d3.String() // output: "6666.6666666666666667"
 | 
						|
//     decimal.DivisionPrecision = 3
 | 
						|
//     d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)
 | 
						|
//     d4.String() // output: "0.6667"
 | 
						|
//
 | 
						|
const (
 | 
						|
	MaxFractionDigits    = 30
 | 
						|
	DivIncreasePrecision = 4
 | 
						|
)
 | 
						|
 | 
						|
// ZeroDecimal is zero constant, to make computations faster.
 | 
						|
var ZeroDecimal = NewDecimalFromInt(0, 1)
 | 
						|
 | 
						|
var zeroInt = big.NewInt(0)
 | 
						|
var oneInt = big.NewInt(1)
 | 
						|
var fiveInt = big.NewInt(5)
 | 
						|
var tenInt = big.NewInt(10)
 | 
						|
 | 
						|
// Decimal represents a fixed-point decimal. It is immutable.
 | 
						|
// number = value * 10 ^ exp
 | 
						|
type Decimal struct {
 | 
						|
	value *big.Int
 | 
						|
 | 
						|
	// this must be an int32, because we cast it to float64 during
 | 
						|
	// calculations. If exp is 64 bit, we might lose precision.
 | 
						|
	// If we cared about being able to represent every possible decimal, we
 | 
						|
	// could make exp a *big.Int but it would hurt performance and numbers
 | 
						|
	// like that are unrealistic.
 | 
						|
	exp        int32
 | 
						|
	fracDigits int32 // Number of fractional digits for string result.
 | 
						|
}
 | 
						|
 | 
						|
// ConvertToDecimal converts interface to decimal.
 | 
						|
func ConvertToDecimal(value interface{}) (Decimal, error) {
 | 
						|
	switch v := value.(type) {
 | 
						|
	case int8:
 | 
						|
		return NewDecimalFromInt(int64(v), 0), nil
 | 
						|
	case int16:
 | 
						|
		return NewDecimalFromInt(int64(v), 0), nil
 | 
						|
	case int32:
 | 
						|
		return NewDecimalFromInt(int64(v), 0), nil
 | 
						|
	case int64:
 | 
						|
		return NewDecimalFromInt(int64(v), 0), nil
 | 
						|
	case int:
 | 
						|
		return NewDecimalFromInt(int64(v), 0), nil
 | 
						|
	case uint8:
 | 
						|
		return NewDecimalFromUint(uint64(v), 0), nil
 | 
						|
	case uint16:
 | 
						|
		return NewDecimalFromUint(uint64(v), 0), nil
 | 
						|
	case uint32:
 | 
						|
		return NewDecimalFromUint(uint64(v), 0), nil
 | 
						|
	case uint64:
 | 
						|
		return NewDecimalFromUint(uint64(v), 0), nil
 | 
						|
	case uint:
 | 
						|
		return NewDecimalFromUint(uint64(v), 0), nil
 | 
						|
	case float32:
 | 
						|
		return NewDecimalFromFloat(float64(v)), nil
 | 
						|
	case float64:
 | 
						|
		return NewDecimalFromFloat(float64(v)), nil
 | 
						|
	case string:
 | 
						|
		return ParseDecimal(v)
 | 
						|
	case Decimal:
 | 
						|
		return v, nil
 | 
						|
	case Hex:
 | 
						|
		return NewDecimalFromInt(int64(v.Value), 0), nil
 | 
						|
	case Bit:
 | 
						|
		return NewDecimalFromUint(uint64(v.Value), 0), nil
 | 
						|
	case Enum:
 | 
						|
		return NewDecimalFromUint(uint64(v.Value), 0), nil
 | 
						|
	case Set:
 | 
						|
		return NewDecimalFromUint(uint64(v.Value), 0), nil
 | 
						|
	default:
 | 
						|
		return Decimal{}, fmt.Errorf("can't convert %v to decimal", value)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewDecimalFromInt returns a new fixed-point decimal, value * 10 ^ exp.
 | 
						|
func NewDecimalFromInt(value int64, exp int32) Decimal {
 | 
						|
	return Decimal{
 | 
						|
		value:      big.NewInt(value),
 | 
						|
		exp:        exp,
 | 
						|
		fracDigits: fracDigitsDefault(exp),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// NewDecimalFromUint returns a new fixed-point decimal, value * 10 ^ exp.
 | 
						|
func NewDecimalFromUint(value uint64, exp int32) Decimal {
 | 
						|
	return Decimal{
 | 
						|
		value:      big.NewInt(0).SetUint64(value),
 | 
						|
		exp:        exp,
 | 
						|
		fracDigits: fracDigitsDefault(exp),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ParseDecimal returns a new Decimal from a string representation.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     d, err := ParseDecimal("-123.45")
 | 
						|
//     d2, err := ParseDecimal(".0001")
 | 
						|
//
 | 
						|
func ParseDecimal(value string) (Decimal, error) {
 | 
						|
	var intString string
 | 
						|
	var exp = int32(0)
 | 
						|
 | 
						|
	n := strings.IndexAny(value, "eE")
 | 
						|
	if n > 0 {
 | 
						|
		// It is scientific notation, like 3.14e10
 | 
						|
		expInt, err := strconv.Atoi(value[n+1:])
 | 
						|
		if err != nil {
 | 
						|
			return Decimal{}, fmt.Errorf("can't convert %s to decimal, incorrect exponent", value)
 | 
						|
		}
 | 
						|
		value = value[0:n]
 | 
						|
		exp = int32(expInt)
 | 
						|
	}
 | 
						|
 | 
						|
	parts := strings.Split(value, ".")
 | 
						|
	if len(parts) == 1 {
 | 
						|
		// There is no decimal point, we can just parse the original string as
 | 
						|
		// an int.
 | 
						|
		intString = value
 | 
						|
	} else if len(parts) == 2 {
 | 
						|
		intString = parts[0] + parts[1]
 | 
						|
		expInt := -len(parts[1])
 | 
						|
		exp += int32(expInt)
 | 
						|
	} else {
 | 
						|
		return Decimal{}, fmt.Errorf("can't convert %s to decimal: too many .s", value)
 | 
						|
	}
 | 
						|
 | 
						|
	dValue := new(big.Int)
 | 
						|
	_, ok := dValue.SetString(intString, 10)
 | 
						|
	if !ok {
 | 
						|
		return Decimal{}, fmt.Errorf("can't convert %s to decimal", value)
 | 
						|
	}
 | 
						|
 | 
						|
	val := Decimal{
 | 
						|
		value:      dValue,
 | 
						|
		exp:        exp,
 | 
						|
		fracDigits: fracDigitsDefault(exp),
 | 
						|
	}
 | 
						|
	if exp < -MaxFractionDigits {
 | 
						|
		val = val.rescale(-MaxFractionDigits)
 | 
						|
	}
 | 
						|
	return val, nil
 | 
						|
}
 | 
						|
 | 
						|
// NewDecimalFromFloat converts a float64 to Decimal.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     NewDecimalFromFloat(123.45678901234567).String() // output: "123.4567890123456"
 | 
						|
//     NewDecimalFromFloat(.00000000000000001).String() // output: "0.00000000000000001"
 | 
						|
//
 | 
						|
// NOTE: this will panic on NaN, +/-inf.
 | 
						|
func NewDecimalFromFloat(value float64) Decimal {
 | 
						|
	floor := math.Floor(value)
 | 
						|
 | 
						|
	// fast path, where float is an int.
 | 
						|
	if floor == value && !math.IsInf(value, 0) {
 | 
						|
		return NewDecimalFromInt(int64(value), 0)
 | 
						|
	}
 | 
						|
 | 
						|
	str := strconv.FormatFloat(value, 'f', -1, 64)
 | 
						|
	dec, err := ParseDecimal(str)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
	return dec
 | 
						|
}
 | 
						|
 | 
						|
// NewDecimalFromFloatWithExponent converts a float64 to Decimal, with an arbitrary
 | 
						|
// number of fractional digits.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     NewDecimalFromFloatWithExponent(123.456, -2).String() // output: "123.46"
 | 
						|
//
 | 
						|
func NewDecimalFromFloatWithExponent(value float64, exp int32) Decimal {
 | 
						|
	mul := math.Pow(10, -float64(exp))
 | 
						|
	floatValue := value * mul
 | 
						|
	if math.IsNaN(floatValue) || math.IsInf(floatValue, 0) {
 | 
						|
		panic(fmt.Sprintf("Cannot create a Decimal from %v", floatValue))
 | 
						|
	}
 | 
						|
	dValue := big.NewInt(round(floatValue))
 | 
						|
 | 
						|
	return Decimal{
 | 
						|
		value:      dValue,
 | 
						|
		exp:        exp,
 | 
						|
		fracDigits: fracDigitsDefault(exp),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// rescale returns a rescaled version of the decimal. Returned
 | 
						|
// decimal may be less precise if the given exponent is bigger
 | 
						|
// than the initial exponent of the Decimal.
 | 
						|
// NOTE: this will truncate, NOT round
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
// 	d := New(12345, -4)
 | 
						|
//	d2 := d.rescale(-1)
 | 
						|
//	d3 := d2.rescale(-4)
 | 
						|
//	println(d1)
 | 
						|
//	println(d2)
 | 
						|
//	println(d3)
 | 
						|
//
 | 
						|
// Output:
 | 
						|
//
 | 
						|
//	1.2345
 | 
						|
//	1.2
 | 
						|
//	1.2000
 | 
						|
//
 | 
						|
func (d Decimal) rescale(exp int32) Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
	if exp < -MaxFractionDigits-1 {
 | 
						|
		// Limit the number of digits but we can not call Round here because it is called by Round.
 | 
						|
		// Limit it to MaxFractionDigits + 1 to make sure the final result is correct.
 | 
						|
		exp = -MaxFractionDigits - 1
 | 
						|
	}
 | 
						|
	// Must convert exps to float64 before - to prevent overflow.
 | 
						|
	diff := math.Abs(float64(exp) - float64(d.exp))
 | 
						|
	value := new(big.Int).Set(d.value)
 | 
						|
 | 
						|
	expScale := new(big.Int).Exp(tenInt, big.NewInt(int64(diff)), nil)
 | 
						|
	if exp > d.exp {
 | 
						|
		value = value.Quo(value, expScale)
 | 
						|
	} else if exp < d.exp {
 | 
						|
		value = value.Mul(value, expScale)
 | 
						|
	}
 | 
						|
	return Decimal{
 | 
						|
		value:      value,
 | 
						|
		exp:        exp,
 | 
						|
		fracDigits: d.fracDigits,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Abs returns the absolute value of the decimal.
 | 
						|
func (d Decimal) Abs() Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
	d2Value := new(big.Int).Abs(d.value)
 | 
						|
	return Decimal{
 | 
						|
		value:      d2Value,
 | 
						|
		exp:        d.exp,
 | 
						|
		fracDigits: d.fracDigits,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Add returns d + d2.
 | 
						|
func (d Decimal) Add(d2 Decimal) Decimal {
 | 
						|
	baseExp := min(d.exp, d2.exp)
 | 
						|
	rd := d.rescale(baseExp)
 | 
						|
	rd2 := d2.rescale(baseExp)
 | 
						|
 | 
						|
	d3Value := new(big.Int).Add(rd.value, rd2.value)
 | 
						|
	return Decimal{
 | 
						|
		value:      d3Value,
 | 
						|
		exp:        baseExp,
 | 
						|
		fracDigits: fracDigitsPlus(d.fracDigits, d2.fracDigits),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Sub returns d - d2.
 | 
						|
func (d Decimal) Sub(d2 Decimal) Decimal {
 | 
						|
	baseExp := min(d.exp, d2.exp)
 | 
						|
	rd := d.rescale(baseExp)
 | 
						|
	rd2 := d2.rescale(baseExp)
 | 
						|
 | 
						|
	d3Value := new(big.Int).Sub(rd.value, rd2.value)
 | 
						|
	return Decimal{
 | 
						|
		value:      d3Value,
 | 
						|
		exp:        baseExp,
 | 
						|
		fracDigits: fracDigitsPlus(d.fracDigits, d2.fracDigits),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Mul returns d * d2.
 | 
						|
func (d Decimal) Mul(d2 Decimal) Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
	d2.ensureInitialized()
 | 
						|
 | 
						|
	expInt64 := int64(d.exp) + int64(d2.exp)
 | 
						|
	if expInt64 > math.MaxInt32 || expInt64 < math.MinInt32 {
 | 
						|
		// It is better to panic than to give incorrect results, as
 | 
						|
		// decimals are usually used for money.
 | 
						|
		panic(fmt.Sprintf("exponent %v overflows an int32!", expInt64))
 | 
						|
	}
 | 
						|
 | 
						|
	d3Value := new(big.Int).Mul(d.value, d2.value)
 | 
						|
	val := Decimal{
 | 
						|
		value:      d3Value,
 | 
						|
		exp:        int32(expInt64),
 | 
						|
		fracDigits: fracDigitsMul(d.fracDigits, d2.fracDigits),
 | 
						|
	}
 | 
						|
	if val.exp < -(MaxFractionDigits) {
 | 
						|
		val = val.Round(MaxFractionDigits)
 | 
						|
	}
 | 
						|
	return val
 | 
						|
}
 | 
						|
 | 
						|
// Div returns d / d2. If it doesn't divide exactly, the result will have
 | 
						|
// DivisionPrecision digits after the decimal point.
 | 
						|
func (d Decimal) Div(d2 Decimal) Decimal {
 | 
						|
	// Division is hard, use Rat to do it.
 | 
						|
	ratNum := d.Rat()
 | 
						|
	ratDenom := d2.Rat()
 | 
						|
 | 
						|
	quoRat := big.NewRat(0, 1).Quo(ratNum, ratDenom)
 | 
						|
 | 
						|
	// Converting from Rat to Decimal inefficiently for now.
 | 
						|
	ret, err := ParseDecimal(quoRat.FloatString(MaxFractionDigits + 1))
 | 
						|
	if err != nil {
 | 
						|
		panic(err) // This should never happen.
 | 
						|
	}
 | 
						|
	// To pass test "2 / 3 * 3 < 2" -> "1".
 | 
						|
	ret = ret.Truncate(MaxFractionDigits)
 | 
						|
	ret.fracDigits = fracDigitsDiv(d.fracDigits)
 | 
						|
	return ret
 | 
						|
}
 | 
						|
 | 
						|
// Cmp compares the numbers represented by d and d2, and returns:
 | 
						|
//
 | 
						|
//     -1 if d <  d2
 | 
						|
//      0 if d == d2
 | 
						|
//     +1 if d >  d2
 | 
						|
//
 | 
						|
func (d Decimal) Cmp(d2 Decimal) int {
 | 
						|
	baseExp := min(d.exp, d2.exp)
 | 
						|
	rd := d.rescale(baseExp)
 | 
						|
	rd2 := d2.rescale(baseExp)
 | 
						|
 | 
						|
	return rd.value.Cmp(rd2.value)
 | 
						|
}
 | 
						|
 | 
						|
// Equals returns whether the numbers represented by d and d2 are equal.
 | 
						|
func (d Decimal) Equals(d2 Decimal) bool {
 | 
						|
	return d.Cmp(d2) == 0
 | 
						|
}
 | 
						|
 | 
						|
// Exponent returns the exponent, or scale component of the decimal.
 | 
						|
func (d Decimal) Exponent() int32 {
 | 
						|
	return d.exp
 | 
						|
}
 | 
						|
 | 
						|
// FracDigits returns the number of fractional digits of the decimal.
 | 
						|
func (d Decimal) FracDigits() int32 {
 | 
						|
	return d.fracDigits
 | 
						|
}
 | 
						|
 | 
						|
// IntPart returns the integer component of the decimal.
 | 
						|
func (d Decimal) IntPart() int64 {
 | 
						|
	scaledD := d.rescale(0)
 | 
						|
	return scaledD.value.Int64()
 | 
						|
}
 | 
						|
 | 
						|
// Rat returns a rational number representation of the decimal.
 | 
						|
func (d Decimal) Rat() *big.Rat {
 | 
						|
	d.ensureInitialized()
 | 
						|
	if d.exp <= 0 {
 | 
						|
		// It must negate after casting to prevent int32 overflow.
 | 
						|
		denom := new(big.Int).Exp(tenInt, big.NewInt(-int64(d.exp)), nil)
 | 
						|
		return new(big.Rat).SetFrac(d.value, denom)
 | 
						|
	}
 | 
						|
 | 
						|
	mul := new(big.Int).Exp(tenInt, big.NewInt(int64(d.exp)), nil)
 | 
						|
	num := new(big.Int).Mul(d.value, mul)
 | 
						|
	return new(big.Rat).SetFrac(num, oneInt)
 | 
						|
}
 | 
						|
 | 
						|
// Float64 returns the nearest float64 value for d and a bool indicating
 | 
						|
// whether f represents d exactly.
 | 
						|
// For more details, see the documentation for big.Rat.Float64.
 | 
						|
func (d Decimal) Float64() (f float64, exact bool) {
 | 
						|
	return d.Rat().Float64()
 | 
						|
}
 | 
						|
 | 
						|
// String returns the string representation of the decimal
 | 
						|
// with the fixed point.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     d := New(-12345, -3)
 | 
						|
//     println(d.String())
 | 
						|
//
 | 
						|
// Output:
 | 
						|
//
 | 
						|
//     -12.345
 | 
						|
//
 | 
						|
func (d Decimal) String() string {
 | 
						|
	return d.StringFixed(d.fracDigits)
 | 
						|
}
 | 
						|
 | 
						|
// StringFixed returns a rounded fixed-point string with places digits after
 | 
						|
// the decimal point.
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
// 	   NewFromFloat(0).StringFixed(2) // output: "0.00"
 | 
						|
// 	   NewFromFloat(0).StringFixed(0) // output: "0"
 | 
						|
// 	   NewFromFloat(5.45).StringFixed(0) // output: "5"
 | 
						|
// 	   NewFromFloat(5.45).StringFixed(1) // output: "5.5"
 | 
						|
// 	   NewFromFloat(5.45).StringFixed(2) // output: "5.45"
 | 
						|
// 	   NewFromFloat(5.45).StringFixed(3) // output: "5.450"
 | 
						|
// 	   NewFromFloat(545).StringFixed(-1) // output: "550"
 | 
						|
//
 | 
						|
func (d Decimal) StringFixed(places int32) string {
 | 
						|
	rounded := d.Round(places)
 | 
						|
	return rounded.string(false)
 | 
						|
}
 | 
						|
 | 
						|
// Round rounds the decimal to places decimal places.
 | 
						|
// If places < 0, it will round the integer part to the nearest 10^(-places).
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
// 	   NewFromFloat(5.45).Round(1).String() // output: "5.5"
 | 
						|
// 	   NewFromFloat(545).Round(-1).String() // output: "550"
 | 
						|
//
 | 
						|
func (d Decimal) Round(places int32) Decimal {
 | 
						|
	// Truncate to places + 1.
 | 
						|
	ret := d.rescale(-places - 1)
 | 
						|
 | 
						|
	// Add sign(d) * 0.5.
 | 
						|
	if ret.value.Sign() < 0 {
 | 
						|
		ret.value.Sub(ret.value, fiveInt)
 | 
						|
	} else {
 | 
						|
		ret.value.Add(ret.value, fiveInt)
 | 
						|
	}
 | 
						|
 | 
						|
	// Floor for positive numbers, Ceil for negative numbers.
 | 
						|
	_, m := ret.value.DivMod(ret.value, tenInt, new(big.Int))
 | 
						|
	ret.exp++
 | 
						|
	if ret.value.Sign() < 0 && m.Cmp(zeroInt) != 0 {
 | 
						|
		ret.value.Add(ret.value, oneInt)
 | 
						|
	}
 | 
						|
	ret.fracDigits = places
 | 
						|
	return ret
 | 
						|
}
 | 
						|
 | 
						|
// Floor returns the nearest integer value less than or equal to d.
 | 
						|
func (d Decimal) Floor() Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
 | 
						|
	exp := big.NewInt(10)
 | 
						|
 | 
						|
	// It must negate after casting to prevent int32 overflow.
 | 
						|
	exp.Exp(exp, big.NewInt(-int64(d.exp)), nil)
 | 
						|
 | 
						|
	z := new(big.Int).Div(d.value, exp)
 | 
						|
	return Decimal{value: z, exp: 0}
 | 
						|
}
 | 
						|
 | 
						|
// Ceil returns the nearest integer value greater than or equal to d.
 | 
						|
func (d Decimal) Ceil() Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
 | 
						|
	exp := big.NewInt(10)
 | 
						|
 | 
						|
	// It must negate after casting to prevent int32 overflow.
 | 
						|
	exp.Exp(exp, big.NewInt(-int64(d.exp)), nil)
 | 
						|
 | 
						|
	z, m := new(big.Int).DivMod(d.value, exp, new(big.Int))
 | 
						|
	if m.Cmp(zeroInt) != 0 {
 | 
						|
		z.Add(z, oneInt)
 | 
						|
	}
 | 
						|
	return Decimal{value: z, exp: 0}
 | 
						|
}
 | 
						|
 | 
						|
// Truncate truncates off digits from the number, without rounding.
 | 
						|
//
 | 
						|
// NOTE: precision is the last digit that will not be truncated (must be >= 0).
 | 
						|
//
 | 
						|
// Example:
 | 
						|
//
 | 
						|
//     decimal.NewFromString("123.456").Truncate(2).String() // "123.45"
 | 
						|
//
 | 
						|
func (d Decimal) Truncate(precision int32) Decimal {
 | 
						|
	d.ensureInitialized()
 | 
						|
	if precision >= 0 && -precision > d.exp {
 | 
						|
		d = d.rescale(-precision)
 | 
						|
	}
 | 
						|
	d.fracDigits = precision
 | 
						|
	return d
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalJSON implements the json.Unmarshaler interface.
 | 
						|
func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error {
 | 
						|
	str, err := unquoteIfQuoted(decimalBytes)
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("Error decoding string '%s': %s", decimalBytes, err)
 | 
						|
	}
 | 
						|
 | 
						|
	decimal, err := ParseDecimal(str)
 | 
						|
	*d = decimal
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("Error decoding string '%s': %s", str, err)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalJSON implements the json.Marshaler interface.
 | 
						|
func (d Decimal) MarshalJSON() ([]byte, error) {
 | 
						|
	str := "\"" + d.String() + "\""
 | 
						|
	return []byte(str), nil
 | 
						|
}
 | 
						|
 | 
						|
// Scan implements the sql.Scanner interface for database deserialization.
 | 
						|
func (d *Decimal) Scan(value interface{}) error {
 | 
						|
	str, err := unquoteIfQuoted(value)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	*d, err = ParseDecimal(str)
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// Value implements the driver.Valuer interface for database serialization.
 | 
						|
func (d Decimal) Value() (driver.Value, error) {
 | 
						|
	return d.String(), nil
 | 
						|
}
 | 
						|
 | 
						|
// BigIntValue returns the *bit.Int value member of decimal.
 | 
						|
func (d Decimal) BigIntValue() *big.Int {
 | 
						|
	return d.value
 | 
						|
}
 | 
						|
 | 
						|
// UnmarshalText implements the encoding.TextUnmarshaler interface for XML
 | 
						|
// deserialization.
 | 
						|
func (d *Decimal) UnmarshalText(text []byte) error {
 | 
						|
	str := string(text)
 | 
						|
 | 
						|
	dec, err := ParseDecimal(str)
 | 
						|
	*d = dec
 | 
						|
	if err != nil {
 | 
						|
		return fmt.Errorf("Error decoding string '%s': %s", str, err)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// MarshalText implements the encoding.TextMarshaler interface for XML
 | 
						|
// serialization.
 | 
						|
func (d Decimal) MarshalText() (text []byte, err error) {
 | 
						|
	return []byte(d.String()), nil
 | 
						|
}
 | 
						|
 | 
						|
// StringScaled first scales the decimal then calls .String() on it.
 | 
						|
// NOTE: buggy, unintuitive, and DEPRECATED! Use StringFixed instead.
 | 
						|
func (d Decimal) StringScaled(exp int32) string {
 | 
						|
	return d.rescale(exp).String()
 | 
						|
}
 | 
						|
 | 
						|
func (d Decimal) string(trimTrailingZeros bool) string {
 | 
						|
	if d.exp >= 0 {
 | 
						|
		return d.rescale(0).value.String()
 | 
						|
	}
 | 
						|
 | 
						|
	abs := new(big.Int).Abs(d.value)
 | 
						|
	str := abs.String()
 | 
						|
 | 
						|
	var intPart, fractionalPart string
 | 
						|
 | 
						|
	// this cast to int will cause bugs if d.exp == INT_MIN
 | 
						|
	// and you are on a 32-bit machine. Won't fix this super-edge case.
 | 
						|
	dExpInt := int(d.exp)
 | 
						|
	if len(str) > -dExpInt {
 | 
						|
		intPart = str[:len(str)+dExpInt]
 | 
						|
		fractionalPart = str[len(str)+dExpInt:]
 | 
						|
	} else {
 | 
						|
		intPart = "0"
 | 
						|
 | 
						|
		num0s := -dExpInt - len(str)
 | 
						|
		fractionalPart = strings.Repeat("0", num0s) + str
 | 
						|
	}
 | 
						|
 | 
						|
	if trimTrailingZeros {
 | 
						|
		i := len(fractionalPart) - 1
 | 
						|
		for ; i >= 0; i-- {
 | 
						|
			if fractionalPart[i] != '0' {
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		fractionalPart = fractionalPart[:i+1]
 | 
						|
	}
 | 
						|
 | 
						|
	number := intPart
 | 
						|
	if len(fractionalPart) > 0 {
 | 
						|
		number += "." + fractionalPart
 | 
						|
	}
 | 
						|
 | 
						|
	if d.value.Sign() < 0 {
 | 
						|
		return "-" + number
 | 
						|
	}
 | 
						|
 | 
						|
	return number
 | 
						|
}
 | 
						|
 | 
						|
func (d *Decimal) ensureInitialized() {
 | 
						|
	if d.value == nil {
 | 
						|
		d.value = new(big.Int)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func min(x, y int32) int32 {
 | 
						|
	if x >= y {
 | 
						|
		return y
 | 
						|
	}
 | 
						|
	return x
 | 
						|
}
 | 
						|
 | 
						|
func max(x, y int32) int32 {
 | 
						|
	if x >= y {
 | 
						|
		return x
 | 
						|
	}
 | 
						|
	return y
 | 
						|
}
 | 
						|
 | 
						|
func round(n float64) int64 {
 | 
						|
	if n < 0 {
 | 
						|
		return int64(n - 0.5)
 | 
						|
	}
 | 
						|
	return int64(n + 0.5)
 | 
						|
}
 | 
						|
 | 
						|
func unquoteIfQuoted(value interface{}) (string, error) {
 | 
						|
	bytes, ok := value.([]byte)
 | 
						|
	if !ok {
 | 
						|
		return "", fmt.Errorf("Could not convert value '%+v' to byte array",
 | 
						|
			value)
 | 
						|
	}
 | 
						|
 | 
						|
	// If the amount is quoted, strip the quotes.
 | 
						|
	if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' {
 | 
						|
		bytes = bytes[1 : len(bytes)-1]
 | 
						|
	}
 | 
						|
	return string(bytes), nil
 | 
						|
}
 | 
						|
 | 
						|
func fracDigitsDefault(exp int32) int32 {
 | 
						|
	if exp < 0 {
 | 
						|
		return min(MaxFractionDigits, -exp)
 | 
						|
	}
 | 
						|
 | 
						|
	return 0
 | 
						|
}
 | 
						|
 | 
						|
func fracDigitsPlus(x, y int32) int32 {
 | 
						|
	return max(x, y)
 | 
						|
}
 | 
						|
 | 
						|
func fracDigitsDiv(x int32) int32 {
 | 
						|
	return min(x+DivIncreasePrecision, MaxFractionDigits)
 | 
						|
}
 | 
						|
 | 
						|
func fracDigitsMul(a, b int32) int32 {
 | 
						|
	return min(MaxFractionDigits, a+b)
 | 
						|
}
 |