code.vegaprotocol.io/vega@v0.79.0/libs/num/decimal.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package num
    17  
    18  import (
    19  	"errors"
    20  	"math/big"
    21  
    22  	"github.com/shopspring/decimal"
    23  )
    24  
    25  type Decimal = decimal.Decimal
    26  
    27  var (
    28  	dzero      = decimal.Zero
    29  	d1         = decimal.NewFromFloat(1)
    30  	dm1        = decimal.NewFromFloat(-1)
    31  	d2         = decimal.NewFromFloat(2)
    32  	maxDecimal = decimal.NewFromBigInt(maxU256, 0)
    33  	e          = MustDecimalFromString("2.7182818285")
    34  )
    35  
    36  func MustDecimalFromString(f string) Decimal {
    37  	d, err := DecimalFromString(f)
    38  	if err != nil {
    39  		panic(err)
    40  	}
    41  	return d
    42  }
    43  
    44  func DecimalOne() Decimal {
    45  	return d1
    46  }
    47  
    48  func DecimalMinusOne() Decimal {
    49  	return dm1
    50  }
    51  
    52  func DecimalTwo() Decimal {
    53  	return d2
    54  }
    55  
    56  func DecimalZero() Decimal {
    57  	return dzero
    58  }
    59  
    60  func DecimalE() Decimal {
    61  	return e
    62  }
    63  
    64  func MaxDecimal() Decimal {
    65  	return maxDecimal
    66  }
    67  
    68  func NewDecimalFromFloat(f float64) Decimal {
    69  	return decimal.NewFromFloat(f)
    70  }
    71  
    72  func NewDecimalFromBigInt(value *big.Int, exp int32) Decimal {
    73  	return decimal.NewFromBigInt(value, exp)
    74  }
    75  
    76  func DecimalFromUint(u *Uint) Decimal {
    77  	return decimal.NewFromUint(&u.u)
    78  }
    79  
    80  func DecimalFromInt(u *Int) Decimal {
    81  	d := decimal.NewFromUint(&u.U.u)
    82  	if u.IsNegative() {
    83  		return d.Neg()
    84  	}
    85  	return d
    86  }
    87  
    88  func DecimalFromInt64(i int64) Decimal {
    89  	return decimal.NewFromInt(i)
    90  }
    91  
    92  func DecimalFromFloat(v float64) Decimal {
    93  	return decimal.NewFromFloat(v)
    94  }
    95  
    96  func DecimalFromString(s string) (Decimal, error) {
    97  	return decimal.NewFromString(s)
    98  }
    99  
   100  func DecimalPart(a Decimal) Decimal {
   101  	return a.Sub(a.Floor())
   102  }
   103  
   104  func MaxD(a, b Decimal) Decimal {
   105  	if a.GreaterThan(b) {
   106  		return a
   107  	}
   108  	return b
   109  }
   110  
   111  func MinD(a, b Decimal) Decimal {
   112  	if a.LessThan(b) {
   113  		return a
   114  	}
   115  	return b
   116  }
   117  
   118  // calculates the mean of a given slice.
   119  func Mean(numbers []Decimal) (Decimal, error) {
   120  	if len(numbers) == 0 {
   121  		return DecimalZero(), errors.New("cannot calculate the mean of an empty list")
   122  	}
   123  	total := DecimalZero()
   124  	for _, num := range numbers {
   125  		total = total.Add(num)
   126  	}
   127  	return total.Div(DecimalFromInt64(int64(len(numbers)))), nil
   128  }
   129  
   130  // calculates the variance of a decimal slice.
   131  func Variance(numbers []Decimal) (Decimal, error) {
   132  	if len(numbers) == 0 {
   133  		return DecimalZero(), errors.New("cannot calculate the variance of an empty list")
   134  	}
   135  	m, _ := Mean(numbers)
   136  	total := DecimalZero()
   137  	for _, num := range numbers {
   138  		total = total.Add(num.Sub(m).Pow(d2))
   139  	}
   140  	return total.Div(DecimalFromInt64(int64(len(numbers)))), nil
   141  }
   142  
   143  func UnmarshalBinaryDecimal(data []byte) (Decimal, error) {
   144  	d := decimal.New(0, 1)
   145  	err := d.UnmarshalBinary(data)
   146  	return d, err
   147  }