Why BigDecial#fix return a BigDecimal instead of a Fixnum?

Hi!

According the docs,
http://www.ruby-doc.org/stdlib-2.1.5/libdoc/bigdecimal/rdoc/BigDecimal.html#method-i-fix,
Decimal#fix return the integer part of the number. I wonder why the
object
returned by the fix method is an instance of BigDecimal instead of an
instance of Fixnum Similar problem happens with frac method.

a = BigDecimal(7)
=> #BigDecimal:7fb18015e698,‘0.7E1’,9(27)
a.fix
=> #BigDecimal:7fb180185d38,‘0.7E1’,9(18)
a.fix.to_i
=> 7

Thanks,

On Thursday, December 4, 2014, Juanjo C. [email protected] wrote:

Decimal#fix return the integer part of the number. I wonder why the
object

returned by the fix method is an instance of BigDecimal instead of an
instance of Fixnum

Off the top of my pointy little head: probably because the value may be
too
big for a Fixnum.

On 2014-Dec-4, at 10:16 , Dave A.
[email protected] wrote:

On Thursday, December 4, 2014, Juanjo C. [email protected] wrote:

Decimal#fix return the integer part of the number. I wonder why the object
returned by the fix method is an instance of BigDecimal instead of an instance of
Fixnum

Off the top of my pointy little head: probably because the value may be too big
for a Fixnum.

If that’s what you want, try something like this:

irb2.1.5> require ‘bigdecimal’
#2.1.5 => true
irb2.1.5> d = BigDecimal(7)
#2.1.5 => #BigDecimal:7ffa1d88fee0,‘0.7E1’,9(27)
irb2.1.5> d.fix
#2.1.5 => #BigDecimal:7ffa1d88e130,‘0.7E1’,9(18)
irb2.1.5> Integer(d.fix)
#2.1.5 => 7
irb2.1.5> Integer(d.fix).class
#2.1.5 => Fixnum

irb2.1.5> d = BigDecimal(“3478654456787654567898765”)
#2.1.5 => #<BigDecimal:7ffa1b8f9928,‘0.3478654456 7876545678
98765E25’,27(36)>
irb2.1.5> d.fix
#2.1.5 => #<BigDecimal:7ffa1d85f178,‘0.3478654456 7876545678
98765E25’,27(36)>
irb2.1.5> Integer(d.fix)
#2.1.5 => 3478654456787654567898765
irb2.1.5> Integer(d.fix).class
#2.1.5 => Bignum

-Rob

So, fix should return Fixnum or Bignum, not Decimal. I’m tempted to
report
it as a bug. Don’t you agree?

2014-12-04 12:30 GMT-03:00 Rob B. [email protected]:

Just glanced at the tests in ruby, this is all I found
(test/bigdecimal/test_bigdecimal.rb).

Doesn’t provide much clarification.

def test_fix
x = BigDecimal.new(“1.1”)
assert_equal(1, x.fix)
end

On Thu, Dec 4, 2014 at 9:44 AM, Rob B.
[email protected]
wrote:

returned a Fixnum 0 even though there is no fractional part of 7. (And, of

wrote:

#2.1.5 => 7
#2.1.5 => 3478654456787654567898765
Mi primer novela ya se puede conseguir en:
juanjoconti.com.ar

http://www.kapowevents.com/?utm_campaign=signature&utm_medium=email&utm_source=office&utm_content=kapow-events
SAAD REHMANI | CTO
O: 312-374-4101 | C: 469-774-6267
KapowEvents.com
http://www.kapowevents.com/?utm_campaign=signature&utm_medium=email&utm_source=office&utm_content=kapow-events
Corporate events made easy.

On 2014-Dec-4, at 10:37 , Juanjo C. [email protected] wrote:

So, fix should return Fixnum or Bignum, not Decimal. I’m tempted to report it as
a bug. Don’t you agree?

No, I don’t agree. Integer and Decimal are both Numeric, but I think
that it’s less surprising for #fix and #frac to both return the same
typeBigDecimal. It would be completely surprising if
BigDecimal(“7”).frac returned a Fixnum 0 even though there is no
fractional part of 7. (And, of course, BigDecimal(“7”).frac.zero? is
true)

-Rob

Yup, you’re probably right. Thanks.

2014-12-04 13:00 GMT-03:00 Bryce K. [email protected]:

Python works the same way:

decimal.Decimal(7).imag
Decimal(‘0’)
decimal.Decimal(7).real
Decimal(‘7’)

2014-12-04 13:08 GMT-03:00 Juanjo C. [email protected]:

On Dec 4, 2014, at 10:37, Juanjo C. [email protected] wrote:

So, fix should return Fixnum or Bignum, not Decimal. I’m tempted to report it as
a bug. Don’t you agree?

I don’t agree. BigDecimal#fix returns a BigDecimal because it’s
convenient; the documentation doesn’t make any guarantees about type,
and the code doesn’t do any particular conversions:

https://github.com/ruby/ruby/blob/bc0f131277af6b6cd65a5e75c3b8a2d9d8b073ad/ext/bigdecimal/bigdecimal.c#L1643

https://github.com/jruby/jruby/blob/e86c673ba2c3c1e776382b0588fd08cea4109fae/core/src/main/java/org/jruby/ext/bigdecimal/RubyBigDecimal.java#L1515-L1532

In most cases, I don’t find myself caring about the class of the result,
just that the result responds as expected to further usage.
BigDecimal(7) works enough like Integer(7) that I don’t need to get
picky about the type.

If you’re having issues with how the number is displayed to the user,
look into using the sprintf method on Kernel, which gives you much
more control.

Rob B. wrote in post #1164010:

a bug. Don’t you agree?

No, I don’t agree. Integer and Decimal are both Numeric, but I think
that it’s less surprising for #fix and #frac to both return the same
typeBigDecimal. It would be completely surprising if
BigDecimal(“7”).frac returned a Fixnum 0 even though there is no
fractional part of 7. (And, of course, BigDecimal(“7”).frac.zero? is
true)

-Rob

in BigDecimal doc , we found:

exponent()

Returns the exponent of the BigDecimal number, as an Integer.

fix()

Return the integer part of the number.

floor(n)

Return the largest integer less than or equal to the value, as a
BigDecimal.

so fix() doc should say “return … as a BigDecimal”
as for floor() , no ?

On Thu, Dec 4, 2014 at 10:13 PM, Colin B.
[email protected] wrote:

To avoid ambiguity it might be helpful if the documentation for
BigDecimal#fix said that it returned the integer part of the value as
a BigDecimal.

Generally math operations return the most appropriate type. For
example from a Fixnum multiplication you can get back a Fixnum or a
Bignum. You really should not be caring about the type too much, I
think. Note that even printf will happily output a BigDecimal as
integer value.

This behaviour could be useful if you want to convert something to an
“integer value”, and then want to be able to divide into that “integer
value” without the result being truncated to an integer.

It is also useful to avoid unnecessary conversions. By returning
BigDecimal method #fix probably does less work. If a conversion to
Fixnum or Bignum was integrated then the user could never get a
BigDecimal out of #fix and it may have to be recreated during a
#coerce call done in another math operation. So that would mean a lot
unnecessary work.

If you really need an Integer then BigDecimal#to_i and
BigDecimal#floor seem to work.

I’d rather use #to_int than #to_i because that is the proper method
which enforces integerness.

If you are interested in how numeric classes usually work in Ruby I
have blogged about this a looong time ago:
http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html

Kind regards

robert

Am 04.12.2014 um 22:13 schrieb Colin B.:

To avoid ambiguity it might be helpful if the documentation for
BigDecimal#fix said that it returned the integer part of the value as
a BigDecimal.

I submitted a patch today that clarifies the docs accordingly.

(See Bug #10576: [DOC] Several fixes for the BigDecimal documentation - Ruby master - Ruby Issue Tracking System)

Best regards,
Marcus

To avoid ambiguity it might be helpful if the documentation for
BigDecimal#fix said that it returned the integer part of the value as
a BigDecimal.

This behaviour could be useful if you want to convert something to an
“integer value”, and then want to be able to divide into that “integer
value” without the result being truncated to an integer.

If you really need an Integer then BigDecimal#to_i and
BigDecimal#floor seem to work.

On Thu, Dec 4, 2014 at 10:13 PM, Colin B.
[email protected] wrote:


If you really need an Integer then BigDecimal#to_i and
BigDecimal#floor seem to work.

On 12/5/14, Robert K. [email protected] wrote:


I’d rather use #to_int than #to_i because that is the proper method
which enforces integerness.

If you are interested in how numeric classes usually work in Ruby I
have blogged about this a looong time ago:
http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html

Sorry for my delay in responding.

Yes, I agree about #to_int. I should have paid closer attention to
your blog when I read it when it first came out!

I also managed not to notice the text in later editions of Programming
Ruby on the difference between unstrict and strict conversion
functions. (In my “defence”, when I learned Ruby in the early 2000s
from the first (hard copy) edition of “Programming Ruby”, there wasn’t
a Fixnum#to_int. At least, it isn’t documented in the online version
Programming Ruby: The Pragmatic Programmer's Guide although String#to_str is
and I didn’t take the reason for that and #to_s onboard at the time.)

Just to reinforce the distinction in my mind, these make a similar
point.

http://www.rubyfleebie.com/to_i-vs-to_int/

http://globaldev.co.uk/2013/09/ruby-tips-part-2/

“Why are there two methods, to_i and to_int, in BigDecimal when they
are exactly same in terms of functionality. …”

Updated by Nobuyoshi N. over 2 years ago:
They are not specific to BigDecimal.
to_i is for explicit conversion, called by users.
to_int is for implicit conversion, called by core/libraries.

I don’t understand what’s the difference between to_s and to_str (the
same for to_i - to_int, to_a - to_ary, and so), and why we need both
method styles.

Dave T.'s reply: The short forms (to_s, to_i, etc) say “do your
best to give me a string/integer/… representation of the receiver).
The to_str longer-form methods say instead that the receiver can
effectively be viewed as a string, and ask for the string
representation. So the short forms are permissive, and the long forms
will give an error if no exact conversion exists.

Now I might remember and use the distinction!