Skip to content

Allow BigDecimal accept Float without precision #314

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions ext/bigdecimal/bigdecimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3458,11 +3458,7 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
}

if (digs == SIZE_MAX) {
if (!raise_exception)
return Qnil;
rb_raise(rb_eArgError,
"can't omit precision for a %"PRIsVALUE".",
CLASS_OF(val));
digs = 0;
}
else if (digs > BIGDECIMAL_DOUBLE_FIGURES) {
if (!raise_exception)
Expand Down Expand Up @@ -3712,12 +3708,12 @@ rb_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception)
*
* - Integer, Float, Rational, Complex, or BigDecimal: converted directly:
*
* # Integer, Complex, or BigDecimal value does not require ndigits; ignored if given.
* # Integer, Complex, Float, or BigDecimal value does not require ndigits; ignored if given.
* BigDecimal(2) # => 0.2e1
* BigDecimal(Complex(2, 0)) # => 0.2e1
* BigDecimal(BigDecimal(2)) # => 0.2e1
* # Float or Rational value requires ndigits.
* BigDecimal(2.0, 0) # => 0.2e1
* BigDecimal(2.0) # => 0.2e1
* # Rational value requires ndigits.
* BigDecimal(Rational(2, 1), 0) # => 0.2e1
*
* - String: converted by parsing if it contains an integer or floating-point literal;
Expand Down
7 changes: 4 additions & 3 deletions test/bigdecimal/test_bigdecimal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ def test_BigDecimal_with_float
assert_equal(BigDecimal("0.1235"), BigDecimal(0.1234567, 4))
assert_equal(BigDecimal("-0.1235"), BigDecimal(-0.1234567, 4))
assert_equal(BigDecimal("0.01"), BigDecimal(0.01, Float::DIG + 1))
assert_raise_with_message(ArgumentError, "can't omit precision for a Float.") { BigDecimal(4.2) }
assert_nothing_raised { BigDecimal(4.2) }
assert_equal(BigDecimal(4.2), BigDecimal('4.2'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrzasa Could you add more assertions to check many cases, especially for numbers that don't have accurate representations in Float?
Moreover, we must compare two values by assert_in_delta and pass an appropriate value to the delta argument for the original Float value; it should be 0.5ulp.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reconsidered how to check here.

I suggest comparing the result of to_f with the original Float value, like this: assert_equal(4.2, BigDecimal(4.2).to_f).
This approach is preferable because it doesn’t depend on the specific decimal representation for a given Float value. I’d like to avoid relying on the particular algorithm used for converting a Float to a BigDecimal.

assert_raise(ArgumentError) { BigDecimal(0.1, Float::DIG + 2) }
assert_nothing_raised { BigDecimal(0.1, Float::DIG + 1) }

Expand Down Expand Up @@ -242,10 +243,10 @@ def test_BigDecimal_with_exception_keyword
assert_equal(nil, BigDecimal(42.quo(7), exception: false))
}
assert_raise(ArgumentError) {
BigDecimal(4.2, exception: true)
BigDecimal(4.2, Float::DIG + 2, exception: true)
}
assert_nothing_raised(ArgumentError) {
assert_equal(nil, BigDecimal(4.2, exception: false))
assert_equal(nil, BigDecimal(4.2, Float::DIG + 2, exception: false))
}
# TODO: support conversion from complex
# assert_raise(RangeError) {
Expand Down
Loading