diff --git a/decimal.go b/decimal.go index 818c66b..dafa87c 100644 --- a/decimal.go +++ b/decimal.go @@ -188,14 +188,22 @@ func NewFromFloat32(f float32) Decimal { return newFromDecimal(decimal.NewFromFloat32(f)) } -// fallback: +// optimized: // NewFromFloatWithExponent converts a float64 to Decimal, with an arbitrary // number of fractional digits. // // Example: // // NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" +// +// NOTE: this will panic on NaN, +/-inf func NewFromFloatWithExponent(value float64, exp int32) Decimal { + decimalPlaces := -exp // decimalPlaces could be 0..12 here, inclusive + formatted := strconv.FormatFloat(value, 'f', int(decimalPlaces), 64) + if fixed, ok := parseFixed([]byte(formatted)); ok { + return Decimal{fixed: fixed} + } + return newFromDecimal(decimal.NewFromFloatWithExponent(value, exp)) } diff --git a/decimal_test.go b/decimal_test.go index 4442cf1..c44dcc3 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -176,12 +176,54 @@ func TestDecimal(t *testing.T) { }) t.Run("NewFromFloatWithExponent", func(t *testing.T) { - input := 123.456 + { + input := 123.456 - x := alpacadecimal.NewFromFloatWithExponent(input, -2) - y := decimal.NewFromFloatWithExponent(input, -2) + x := alpacadecimal.NewFromFloatWithExponent(input, -2) + y := decimal.NewFromFloatWithExponent(input, -2) - require.Equal(t, x.String(), y.String()) + require.Equal(t, x.String(), y.String()) + require.True(t, x.IsOptimized()) + } + + { + input := 123.4567890192214 + + x := alpacadecimal.NewFromFloatWithExponent(input, -12) + y := decimal.NewFromFloatWithExponent(input, -12) + + require.Equal(t, x.String(), y.String()) + require.True(t, x.IsOptimized()) + } + + { + input := 123.4567890192214 + + x := alpacadecimal.NewFromFloatWithExponent(input, -14) + y := decimal.NewFromFloatWithExponent(input, -14) + + require.Equal(t, x.String(), y.String()) + require.False(t, x.IsOptimized()) + } + + { + input := 1_123_123.4567890192214 + + x := alpacadecimal.NewFromFloatWithExponent(input, -12) + y := decimal.NewFromFloatWithExponent(input, -12) + + require.Equal(t, x.String(), y.String()) + require.True(t, x.IsOptimized()) + } + { + input := 9_323_123.4567890192214 // max support decimal is 9_223_372.000_000_000_000 + + x := alpacadecimal.NewFromFloatWithExponent(input, -12) + y := decimal.NewFromFloatWithExponent(input, -12) + + require.Equal(t, x.String(), y.String()) + require.False(t, x.IsOptimized()) + } }) t.Run("NewFromFormattedString", func(t *testing.T) {