OK. I agree that requiring mathn avoids that buggy part.  Thanks for =
clarifying.  I guess I'm just a little uncomfortable with Rationals and =
Fixnums being promoted/demoted as needed, but maybe it's all OK and I'm =
just being paranoid.

While playing around with this, I see that integer Floats also have some =
special handling:

# Without mathn...

$ ruby -e 'p [1/2.0, 1/2.5]'
[0.5, 0.4]

# With mathn...

$ ruby -r mathn -e 'p [1/2.0, 1/2.5]'
[(1/2), 0.4]

Oddly though, this can result in non-reduced Rationals:

$ ruby -r mathn -e 'p [2/2.0, 2/2.5]'
[(2/2), 0.8]

Weird.

Also, why do integer Floats not get changed to Fixnums like Rational and =
Complex do?

$ ruby -r mathn -e 'p Rational(1).class'
Fixnum

$ ruby -r mathn -e 'p Complex(1).class'
Fixnum

$ ruby -r mathn -e 'p Float(1).class'
Float

Thanks,
Dave

On Sep 10, 2013, at 3:28 PM, marcandre (Marc-Andre Lafortune) wrote:

>=20
> Issue #8883 has been updated by marcandre (Marc-Andre Lafortune).
>=20
> Status changed from Open to Rejected
>=20
> Mmm, sorry, misread.
>=20
> I think the idea is that the buggy part (Rational(2) / Rational(3)  # =
=3D> 0) won't happen if you require 'mathn'
>=20
> ----------------------------------------
> Bug #8883: Rational canonicalization unexpectedly converts to Fixnum
> https://bugs.ruby-lang.org/issues/8883#change-41727
>=20
> Author: melquiades (Paul Cantrell)
> Status: Rejected
> Priority: Normal
> Assignee:=20
> Category: lib
> Target version:=20
> ruby -v: ruby 2.0.0p247 (2013-06-27 revision 41674) =
[x86_64-darwin12.3.0]
> Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN
>=20
>=20
> The documentation for Rational =
(http://www.ruby-doc.org/core-2.0.0/Rational.html) states that the =
result of creating or doing arithmetic on Rationals returns Rationals, =
as one would expect. Examples from the docs:
>=20
>    Rational(1)      #=3D> (1/1)
>    3.to_r           #=3D> (3/1)
>    Rational(-2, 9) * Rational(-9, 2)  #=3D> (1/1)
>=20
> These all work as documented in 1.9. In 2.0, however, they all return =
Fixnum:
>=20
>    Rational(1)      #=3D> 1
>    3.to_r           #=3D> 3
>    Rational(-2, 9) * Rational(-9, 2)  #=3D> 1
>=20
> This leads to unexpected behavior:
>=20
>    Rational(2) / Rational(3)  # =3D> 0  ...but returns (2/3) in 1.9
>=20
> That behavior is potentially dangerous. Math that may *usually* work, =
but suddenly start suffering from truncation errors depending on =
intermediate results. For example:
>=20
>  def should_always_return_one(a, b, c)
>    (Rational(a, c) + Rational(b, c)) / (a + b) * c
>  end
>=20
> Under 1.9:
>=20
>    should_always_return_one(2, 3, 7) #=3D> (1/1)
>    should_always_return_one(2, 4, 7) #=3D> (1/1)
>    should_always_return_one(2, 5, 7) #=3D> (1/1)
>    should_always_return_one(2, 6, 7) #=3D> (1/1)
>=20
> Under 2.0:
>=20
>    should_always_return_one(2, 3, 7) #=3D> 1
>    should_always_return_one(2, 4, 7) #=3D> 1
>    should_always_return_one(2, 5, 7) #=3D> 0   Oops!
>    should_always_return_one(2, 6, 7) #=3D> 1
>=20
> Either the docs are wrong, or this is a bug. I vote bug. Whether =
arithmetic expressions truncate the result should not depend on whether =
intermediate values just happen to be integers! Such behavior renders =
Rational almost too dangerous to use in situations where exact results =
are required. (Yes, I realize that requiring 'mathn' fixes this, but =
even with such a workaround as an option, this is dangerously broken. =
See also #2121.) Note that floating point arithmetic does _not_ exhibit =
this behavior.
>=20
>=20
>=20
> --=20
> http://bugs.ruby-lang.org/