go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/sdk/decimal/decimal.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package decimal
     9  
    10  import (
    11  	"encoding/json"
    12  	"fmt"
    13  )
    14  
    15  const _exp = 1e3
    16  
    17  var (
    18  	_ json.Marshaler = (*Decimal)(nil)
    19  )
    20  
    21  // New returns a new decimal.
    22  func New(v any) Decimal {
    23  	d := new(Decimal)
    24  	switch typed := v.(type) {
    25  	case float64:
    26  		d.Set(typed)
    27  	case float32:
    28  		d.Set(float64(typed))
    29  	case int32:
    30  		d.Set(float64(typed))
    31  	case int64:
    32  		d.Set(float64(typed))
    33  	case uint32:
    34  		d.Set(float64(typed))
    35  	case uint64:
    36  		d.Set(float64(typed))
    37  	case int:
    38  		d.Set(float64(typed))
    39  	case Decimal:
    40  		*d = typed
    41  	default:
    42  		panic("invalid origin type for decimal")
    43  	}
    44  	return *d
    45  }
    46  
    47  // Decimal is a fixed precision number with (4) digits of precision.
    48  //
    49  // It blends the benefits of an arbitrary precision type (e.g. math.big)
    50  // with the performance of register types for common operations.
    51  //
    52  // Addition and subtraction can be done directly on values with the
    53  // builtin operators. For everything else, there are helper
    54  // functions on the type itself.
    55  type Decimal int64
    56  
    57  // Float64 returns a float64 for the given decimal value.
    58  func (d Decimal) Float64() float64 {
    59  	return float64(d) / float64(_exp)
    60  }
    61  
    62  // Set sets the decimal value.
    63  func (d *Decimal) Set(v float64) {
    64  	*d = Decimal(int64(v * _exp))
    65  }
    66  
    67  // Add adds this decimal to a given decimal.
    68  //
    69  // It is equivalent to d + v.
    70  func (d Decimal) Add(v Decimal) Decimal {
    71  	return Decimal(d + v)
    72  }
    73  
    74  // Sub subtracts this decimal from a given decimal.
    75  //
    76  // It is equivalent to d - v.
    77  func (d Decimal) Sub(v Decimal) Decimal {
    78  	return Decimal(d - v)
    79  }
    80  
    81  // Div divides this decimal by a given decimal.
    82  //
    83  // It is equivalent to d / v.
    84  func (d Decimal) Div(v Decimal) Decimal {
    85  	if d < v {
    86  		d0 := d * _exp
    87  		return (d0 / v)
    88  	}
    89  	return (d / v) * _exp
    90  }
    91  
    92  // Mul multiplies this decimal by a given decimal.
    93  //
    94  // It is equivalent to d * v.
    95  func (d Decimal) Mul(v Decimal) Decimal {
    96  	return Decimal((d * v) / _exp)
    97  }
    98  
    99  // Abs returnst the absolute value of the decimal.
   100  //
   101  // It is equivalent to -d if d < 0.
   102  func (d Decimal) Abs() Decimal {
   103  	if d < 0 {
   104  		return Decimal(-d)
   105  	}
   106  	return d
   107  }
   108  
   109  // Neg inverts the sign of this decimal.
   110  //
   111  // It is equivalent to -d.
   112  func (d Decimal) Neg() Decimal {
   113  	return Decimal(-d)
   114  }
   115  
   116  // Invert inverts the value of this decimal.
   117  //
   118  // It is equivalent to 1/d.
   119  func (d Decimal) Invert() Decimal {
   120  	return ((_exp * _exp) / d * _exp) / _exp
   121  }
   122  
   123  // String returns a string representation of the decimal.
   124  func (d *Decimal) String() string {
   125  	return fmt.Sprintf("%.4f", d.Float64())
   126  }
   127  
   128  // MarshalJSON marshals the decimal as a json.
   129  func (d Decimal) MarshalJSON() ([]byte, error) {
   130  	return []byte(d.String()), nil
   131  }