Bug #13134

Rational() inconsistency

Added by nobu (Nobuyoshi Nakada) over 3 years ago. Updated over 3 years ago.

Target version:


Rational() parses a float, an integer divided by an integer, and a float divided by an integer.

Rational("3.1")     #=> (31/10)
Rational("3/2")     #=> (3/2)
Rational("3.1/2")   #=> (31/20)

But a float is not allowed as a denominator.

Rational("3.1/2.0") #=> ArgumentError

I'd expect the last also passes and results in (31/20), or the third also raises an ArgumentError

A patch to let all pass.

Updated by mrkn (Kenta Murata) over 3 years ago

  • Assignee set to mrkn (Kenta Murata)
  • Status changed from Open to Assigned

Updated by snood1205 (Eli Sadoff) over 3 years ago

I propose leaving the behavior the way it is. A float denominator is filled with possible unexpected behavior. For example, one would hypothesize that (a/b).to_r == Rational("#{a}/#{b}") yet (3.1/2.0).to_r != Rational('3.1/2.0'). The imprecision that can come with float denominators is why this behavior should not be allowed. Either we would have to allow for (a/b).to_r == Rational("#{a}/#{b}") to not always be true, or we would turn Rational('3.1/2.0') into (6980579422424269/4503599627370496) which defeats the purpose of the rational class.

Updated by shyouhei (Shyouhei Urabe) over 3 years ago

I don't think Rational("3.1/2.0") should introduce imprecision because the argument string has nothing to do with inexact numbers (at least seems to me).

So Eli's argument is ultimately "should we hold (a/b).to_r == Rational("#{a}/#{b}") ?" and I think this is a valid argument. No opinion on this point though.

Updated by stomar (Marcus Stollsteimer) over 3 years ago

The imprecision that can come with float denominators is why this behavior should not be allowed.

Note there already is this kind of "unexpected" behavior:

2.4.0 :001 > (3.1/2).to_r == Rational("3.1/2")  # => false

or even

2.4.0 :002 > 1.2.to_r == Rational("1.2")  # => false

It's not caused by float denominators at all. So I don't see why strings with float denominator should raise an exception.

Updated by Eregon (Benoit Daloze) over 3 years ago

Floating-point numbers in String are exact, Float literal are inexact by nature.
So I would not expect any relation with to_r, even more so when float division is involved.
A Floating-point denominator in String sounds fine to me.

The equation that should hold is
Rational("#{a}/#{b}") == Rational(a) / Rational(b)
with a and b floating-point numbers as Strings.

Note that Float#rationalize produces a nicer-looking Rational, but there is no guarantee to how much precision might be lost on floating-point operations (e.g. 1.1-1.0),
so it is moot to expect a relation between those.


Updated by nobu (Nobuyoshi Nakada) over 3 years ago

  • Status changed from Assigned to Closed

Applied in changeset r57990.

rational.c: float denom

  • rational.c (parse_rat): allow float as a denominator as well as a numerator. [ruby-core:79104] [Bug #13134]

Also available in: Atom PDF