Implement Is betweeen functionality

FIX Add functionality to compare if a decimal value is between two decimals #319
This commit is contained in:
Elirehema Paul 2023-06-11 11:16:16 +03:00
parent f55dd56454
commit aaa9a02fd2
2 changed files with 116 additions and 116 deletions

View file

@ -41,7 +41,6 @@ import (
// decimal.DivisionPrecision = 3 // decimal.DivisionPrecision = 3
// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) // d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
// d4.String() // output: "0.667" // d4.String() // output: "0.667"
//
var DivisionPrecision = 16 var DivisionPrecision = 16
// MarshalJSONWithoutQuotes should be set to true if you want the decimal to // MarshalJSONWithoutQuotes should be set to true if you want the decimal to
@ -133,7 +132,6 @@ func NewFromBigInt(value *big.Int, exp int32) Decimal {
// d, err := NewFromString("-123.45") // d, err := NewFromString("-123.45")
// d2, err := NewFromString(".0001") // d2, err := NewFromString(".0001")
// d3, err := NewFromString("1.47000") // d3, err := NewFromString("1.47000")
//
func NewFromString(value string) (Decimal, error) { func NewFromString(value string) (Decimal, error) {
originalInput := value originalInput := value
var intString string var intString string
@ -219,7 +217,6 @@ func NewFromString(value string) (Decimal, error) {
// //
// r3 := regexp.MustCompile("[USD\\s]") // r3 := regexp.MustCompile("[USD\\s]")
// d3, err := NewFromFormattedString("5000 USD", r3) // d3, err := NewFromFormattedString("5000 USD", r3)
//
func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) { func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) {
parsedValue := replRegexp.ReplaceAllString(value, "") parsedValue := replRegexp.ReplaceAllString(value, "")
d, err := NewFromString(parsedValue) d, err := NewFromString(parsedValue)
@ -236,7 +233,6 @@ func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, e
// //
// d := RequireFromString("-123.45") // d := RequireFromString("-123.45")
// d2 := RequireFromString(".0001") // d2 := RequireFromString(".0001")
//
func RequireFromString(value string) Decimal { func RequireFromString(value string) Decimal {
dec, err := NewFromString(value) dec, err := NewFromString(value)
if err != nil { if err != nil {
@ -333,7 +329,6 @@ func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal {
// Example: // Example:
// //
// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" // NewFromFloatWithExponent(123.456, -2).String() // output: "123.46"
//
func NewFromFloatWithExponent(value float64, exp int32) Decimal { func NewFromFloatWithExponent(value float64, exp int32) Decimal {
if math.IsNaN(value) || math.IsInf(value, 0) { if math.IsNaN(value) || math.IsInf(value, 0) {
panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) panic(fmt.Sprintf("Cannot create a Decimal from %v", value))
@ -442,7 +437,6 @@ func (d Decimal) Copy() Decimal {
// 1.2345 // 1.2345
// 1.2 // 1.2
// 1.2000 // 1.2000
//
func (d Decimal) rescale(exp int32) Decimal { func (d Decimal) rescale(exp int32) Decimal {
d.ensureInitialized() d.ensureInitialized()
@ -554,9 +548,11 @@ func (d Decimal) Div(d2 Decimal) Decimal {
// QuoRem does division with remainder // QuoRem does division with remainder
// d.QuoRem(d2,precision) returns quotient q and remainder r such that // d.QuoRem(d2,precision) returns quotient q and remainder r such that
//
// d = d2 * q + r, q an integer multiple of 10^(-precision) // d = d2 * q + r, q an integer multiple of 10^(-precision)
// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 // 0 <= r < abs(d2) * 10 ^(-precision) if d>=0
// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 // 0 >= r > -abs(d2) * 10 ^(-precision) if d<0
//
// Note that precision<0 is allowed as input. // Note that precision<0 is allowed as input.
func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) {
d.ensureInitialized() d.ensureInitialized()
@ -599,8 +595,10 @@ func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) {
// DivRound divides and rounds to a given precision // DivRound divides and rounds to a given precision
// i.e. to an integer multiple of 10^(-precision) // i.e. to an integer multiple of 10^(-precision)
//
// for a positive quotient digit 5 is rounded up, away from 0 // for a positive quotient digit 5 is rounded up, away from 0
// if the quotient is negative then digit 5 is rounded down, away from 0 // if the quotient is negative then digit 5 is rounded down, away from 0
//
// Note that precision<0 is allowed as input. // Note that precision<0 is allowed as input.
func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal {
// QuoRem already checks initialization // QuoRem already checks initialization
@ -657,7 +655,6 @@ func (d Decimal) Pow(d2 Decimal) Decimal {
// //
// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000" // NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000"
// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284" // NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284"
//
func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) { func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) {
// Algorithm based on Variable precision exponential function. // Algorithm based on Variable precision exponential function.
// ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham. // ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham.
@ -755,7 +752,6 @@ func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) {
// //
// NewFromFloat(26.1).ExpTaylor(-10).String() // NewFromFloat(26.1).ExpTaylor(-10).String()
// d.String() // output: "220000000000" // d.String() // output: "220000000000"
//
func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { func (d Decimal) ExpTaylor(precision int32) (Decimal, error) {
// Note(mwoss): Implementation can be optimized by exclusively using big.Int API only // Note(mwoss): Implementation can be optimized by exclusively using big.Int API only
if d.IsZero() { if d.IsZero() {
@ -854,7 +850,6 @@ func abs(n int32) int32 {
// -1 if d < d2 // -1 if d < d2
// 0 if d == d2 // 0 if d == d2
// +1 if d > d2 // +1 if d > d2
//
func (d Decimal) Cmp(d2 Decimal) int { func (d Decimal) Cmp(d2 Decimal) int {
d.ensureInitialized() d.ensureInitialized()
d2.ensureInitialized() d2.ensureInitialized()
@ -900,12 +895,18 @@ func (d Decimal) LessThanOrEqual(d2 Decimal) bool {
return cmp == -1 || cmp == 0 return cmp == -1 || cmp == 0
} }
// Betwee (LTE) return true when d is between d1 and d2 inclusive
func (d Decimal) IsBetween(d1 Decimal, d2 Decimal) bool {
cmp1 := d.Cmp(d1)
cmp2 := d.Cmp(d2)
return (cmp1 == 1 || cmp1 == 0) && (cmp2 == -1 || cmp2 == 0)
}
// Sign returns: // Sign returns:
// //
// -1 if d < 0 // -1 if d < 0
// 0 if d == 0 // 0 if d == 0
// +1 if d > 0 // +1 if d > 0
//
func (d Decimal) Sign() int { func (d Decimal) Sign() int {
if d.value == nil { if d.value == nil {
return 0 return 0
@ -1020,7 +1021,6 @@ func (d Decimal) InexactFloat64() float64 {
// Output: // Output:
// //
// -12.345 // -12.345
//
func (d Decimal) String() string { func (d Decimal) String() string {
return d.string(true) return d.string(true)
} }
@ -1037,7 +1037,6 @@ func (d Decimal) String() string {
// NewFromFloat(5.45).StringFixed(2) // output: "5.45" // NewFromFloat(5.45).StringFixed(2) // output: "5.45"
// NewFromFloat(5.45).StringFixed(3) // output: "5.450" // NewFromFloat(5.45).StringFixed(3) // output: "5.450"
// NewFromFloat(545).StringFixed(-1) // output: "550" // NewFromFloat(545).StringFixed(-1) // output: "550"
//
func (d Decimal) StringFixed(places int32) string { func (d Decimal) StringFixed(places int32) string {
rounded := d.Round(places) rounded := d.Round(places)
return rounded.string(false) return rounded.string(false)
@ -1055,7 +1054,6 @@ func (d Decimal) StringFixed(places int32) string {
// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" // NewFromFloat(5.45).StringFixedBank(2) // output: "5.45"
// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" // NewFromFloat(5.45).StringFixedBank(3) // output: "5.450"
// NewFromFloat(545).StringFixedBank(-1) // output: "540" // NewFromFloat(545).StringFixedBank(-1) // output: "540"
//
func (d Decimal) StringFixedBank(places int32) string { func (d Decimal) StringFixedBank(places int32) string {
rounded := d.RoundBank(places) rounded := d.RoundBank(places)
return rounded.string(false) return rounded.string(false)
@ -1075,7 +1073,6 @@ func (d Decimal) StringFixedCash(interval uint8) string {
// //
// NewFromFloat(5.45).Round(1).String() // output: "5.5" // NewFromFloat(5.45).Round(1).String() // output: "5.5"
// NewFromFloat(545).Round(-1).String() // output: "550" // NewFromFloat(545).Round(-1).String() // output: "550"
//
func (d Decimal) Round(places int32) Decimal { func (d Decimal) Round(places int32) Decimal {
if d.exp == -places { if d.exp == -places {
return d return d
@ -1108,7 +1105,6 @@ func (d Decimal) Round(places int32) Decimal {
// NewFromFloat(500).RoundCeil(-2).String() // output: "500" // NewFromFloat(500).RoundCeil(-2).String() // output: "500"
// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11" // NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11"
// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5" // NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5"
//
func (d Decimal) RoundCeil(places int32) Decimal { func (d Decimal) RoundCeil(places int32) Decimal {
if d.exp >= -places { if d.exp >= -places {
return d return d
@ -1134,7 +1130,6 @@ func (d Decimal) RoundCeil(places int32) Decimal {
// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500" // NewFromFloat(-500).RoundFloor(-2).String() // output: "-500"
// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1" // NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1"
// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4" // NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4"
//
func (d Decimal) RoundFloor(places int32) Decimal { func (d Decimal) RoundFloor(places int32) Decimal {
if d.exp >= -places { if d.exp >= -places {
return d return d
@ -1160,7 +1155,6 @@ func (d Decimal) RoundFloor(places int32) Decimal {
// NewFromFloat(500).RoundUp(-2).String() // output: "500" // NewFromFloat(500).RoundUp(-2).String() // output: "500"
// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11" // NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11"
// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4" // NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4"
//
func (d Decimal) RoundUp(places int32) Decimal { func (d Decimal) RoundUp(places int32) Decimal {
if d.exp >= -places { if d.exp >= -places {
return d return d
@ -1188,7 +1182,6 @@ func (d Decimal) RoundUp(places int32) Decimal {
// NewFromFloat(-500).RoundDown(-2).String() // output: "-500" // NewFromFloat(-500).RoundDown(-2).String() // output: "-500"
// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1" // NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1"
// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5" // NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5"
//
func (d Decimal) RoundDown(places int32) Decimal { func (d Decimal) RoundDown(places int32) Decimal {
if d.exp >= -places { if d.exp >= -places {
return d return d
@ -1215,7 +1208,6 @@ func (d Decimal) RoundDown(places int32) Decimal {
// NewFromFloat(546).RoundBank(-1).String() // output: "550" // NewFromFloat(546).RoundBank(-1).String() // output: "550"
// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6" // NewFromFloat(5.55).RoundBank(1).String() // output: "5.6"
// NewFromFloat(555).RoundBank(-1).String() // output: "560" // NewFromFloat(555).RoundBank(-1).String() // output: "560"
//
func (d Decimal) RoundBank(places int32) Decimal { func (d Decimal) RoundBank(places int32) Decimal {
round := d.Round(places) round := d.Round(places)
@ -1237,11 +1229,13 @@ func (d Decimal) RoundBank(places int32) Decimal {
// interval. The amount payable for a cash transaction is rounded to the nearest // interval. The amount payable for a cash transaction is rounded to the nearest
// multiple of the minimum currency unit available. The following intervals are // multiple of the minimum currency unit available. The following intervals are
// available: 5, 10, 25, 50 and 100; any other number throws a panic. // available: 5, 10, 25, 50 and 100; any other number throws a panic.
//
// 5: 5 cent rounding 3.43 => 3.45 // 5: 5 cent rounding 3.43 => 3.45
// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) // 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up)
// 25: 25 cent rounding 3.41 => 3.50 // 25: 25 cent rounding 3.41 => 3.50
// 50: 50 cent rounding 3.75 => 4.00 // 50: 50 cent rounding 3.75 => 4.00
// 100: 100 cent rounding 3.50 => 4.00 // 100: 100 cent rounding 3.50 => 4.00
//
// For more details: https://en.wikipedia.org/wiki/Cash_rounding // For more details: https://en.wikipedia.org/wiki/Cash_rounding
func (d Decimal) RoundCash(interval uint8) Decimal { func (d Decimal) RoundCash(interval uint8) Decimal {
var iVal *big.Int var iVal *big.Int
@ -1311,7 +1305,6 @@ func (d Decimal) Ceil() Decimal {
// Example: // Example:
// //
// decimal.NewFromString("123.456").Truncate(2).String() // "123.45" // decimal.NewFromString("123.456").Truncate(2).String() // "123.45"
//
func (d Decimal) Truncate(precision int32) Decimal { func (d Decimal) Truncate(precision int32) Decimal {
d.ensureInitialized() d.ensureInitialized()
if precision >= 0 && -precision > d.exp { if precision >= 0 && -precision > d.exp {

View file

@ -2542,6 +2542,13 @@ func TestDecimal_Equalities(t *testing.T) {
if c.LessThanOrEqual(b) { if c.LessThanOrEqual(b) {
t.Errorf("%q should not be less than or equal %q", a, b) t.Errorf("%q should not be less than or equal %q", a, b)
} }
if !b.IsBetween(c, a) {
t.Errorf("%q should be less than or equal %q", a, b)
}
if b.IsBetween(a, c) {
t.Errorf("%q should not be less than or equal %q", a, b)
}
} }
func TestDecimal_ScalesNotEqual(t *testing.T) { func TestDecimal_ScalesNotEqual(t *testing.T) {