https://bugs.ruby-lang.org/
https://bugs.ruby-lang.org/favicon.ico?1711330511
2010-07-21T11:33:20Z
Ruby Issue Tracking System
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12433
2010-07-21T11:33:20Z
shyouhei (Shyouhei Urabe)
shyouhei@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Open</i> to <i>Rejected</i></li></ul><p>=begin<br>
irb(main):001:0> x = 10.0 ** 20<br>
=> 1.0e+20<br>
irb(main):002:0> y = x + 1<br>
=> 1.0e+20<br>
irb(main):003:0> y == x<br>
=> true<br>
irb(main):004:0></p>
<p>Welcome to the Real world. It is a Float's "fault". Do not blame us.<br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12438
2010-07-21T14:44:10Z
shyouhei (Shyouhei Urabe)
shyouhei@ruby-lang.org
<ul></ul><p>=begin<br>
For a record: Akira Tanaka kindly told me that this behaviour was intentionally introduced since revision r1800, to make 100000000000000000000000 == 100000000000000000000000.0</p>
<p><a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bignum.c?r1=1800&r2=1799&pathrev=1800" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/bignum.c?r1=1800&r2=1799&pathrev=1800</a><br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12454
2010-07-21T22:52:32Z
taw (Tomasz Wegrzanowski)
Tomasz.Wegrzanowski@gmail.com
<ul></ul><p>=begin<br>
This isn't how Floats and other numbers work. No numerical type can represent every real number, and many operations are implicitly followed by rounding to nearest representable value. But once rounded a number corresponds to a precise mathematical value - and comparisons never need to involve any further rounding.</p>
<p>Integer 10 means exactly 10, not everything that would end up as 10 if rounded. 10 == 10.2 #=> false</p>
<p>And r1800 is wrong. 100000000000000000000000.to_f is a precise number 99999999999999991611392,<br>
and it doesn't equal 100000000000000000000000 any more than 10.2.to_i equals 10.2.<br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12456
2010-07-22T00:55:30Z
marcandre (Marc-Andre Lafortune)
marcandre-ruby-core@marc-andre.ca
<ul><li><strong>Category</strong> set to <i>core</i></li></ul><p>=begin<br>
Hi,</p>
<p>On Wed, Jul 21, 2010 at 9:52 AM, Tomasz Wegrzanowski <a href="mailto:redmine@ruby-lang.org" class="email">redmine@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>And r1800 is wrong. 100000000000000000000000.to_f is a precise number 99999999999999991611392,<br>
and it doesn't equal 100000000000000000000000 any more than 10.2.to_i equals 10.2.</p>
</blockquote>
<p>You should think of floats as a range of values. For example, the float 10.2 is a range of value and the mathematical value 10.2 is simply the one that has the smallest decimal form. That range of value does not contain 10, so in Ruby <code>10 != 10.2</code></p>
<p>One the other hand, the float 100000000000000000000000.to_f is a range that contains both the integer 99999999999999991611392 and the integer 100000000000000000000000. The fact that the binary representation of 100000000000000000000000.to_f corresponds to 99999999999999991611392 is not important here; one the conversion to a float is done, there is no way to know which exact number was supposed to be represented, if any.</p>
<h2>Please refer to previous discussions about floats, for instance: <a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/25662" class="external">http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/25662</a>
</h2>
<p>Marc-André<br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12462
2010-07-22T03:01:56Z
taw (Tomasz Wegrzanowski)
Tomasz.Wegrzanowski@gmail.com
<ul></ul><p>=begin</p>
<blockquote>
<p>You should think of floats as a range of values.</p>
</blockquote>
<p>This is a very common misunderstanding about floats, but it<br>
is exactly the opposite of how IEEE 754 specifies floats to work.<br>
They are exact numbers, and every basic floating point operation<br>
acts as if it:</p>
<ul>
<li>converted arguments to infinitely long numbers</li>
<li>performed operation on that</li>
<li>rounded this infinitely long result the way you specified,<br>
also returning information if this caused any loss of precision.</li>
</ul>
<p>If you treated floats as (value +- half ulp), then it would only be<br>
consistent to treat integers as (value +- half ulp), that is 10<br>
equaling everything in (9.5..10.5) range. That still wouldn't make<br>
comparisons sensible if two numbers compared had different ulps,<br>
like when comparing integers with floats.</p>
<p>Reading this would be a good start:<br>
<a href="http://docs.sun.com/source/806-3568/ncg_goldberg.html" class="external">http://docs.sun.com/source/806-3568/ncg_goldberg.html</a><br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12476
2010-07-22T13:16:16Z
shyouhei (Shyouhei Urabe)
shyouhei@ruby-lang.org
<ul><li><strong>Status</strong> changed from <i>Rejected</i> to <i>Assigned</i></li><li><strong>Assignee</strong> set to <i>matz (Yukihiro Matsumoto)</i></li></ul><p>=begin</p>
<blockquote>
<p>Integer 10 means exactly 10, not everything that would end up as 10 if rounded. 10 == 10.2 #=> false</p>
</blockquote>
<p>but 10 == 10.0. 100000000000000000000000 should == 100000000000000000000000.0</p>
<p>You know, if you think it should not, you have to persuade us.</p>
<a name="Assigning-this-to-matz-because-it-turned-out-to-be-a-design-matter"></a>
<h1 >Assigning this to matz because it turned out to be a design matter.<a href="#Assigning-this-to-matz-because-it-turned-out-to-be-a-design-matter" class="wiki-anchor">¶</a></h1>
<p>=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=12532
2010-07-25T12:25:39Z
taw (Tomasz Wegrzanowski)
Tomasz.Wegrzanowski@gmail.com
<ul></ul><p>=begin</p>
<blockquote>
<blockquote>
<p>Integer 10 means exactly 10, not everything that would end up as 10 if rounded. 10 == 10.2 #=> false<br>
but 10 == 10.0. 100000000000000000000000 should == 100000000000000000000000.0<br>
You know, if you think it should not, you have to persuade us.</p>
</blockquote>
<a name="Assigning-this-to-matz-because-it-turned-out-to-be-a-design-matter"></a>
<h1 >Assigning this to matz because it turned out to be a design matter.<a href="#Assigning-this-to-matz-because-it-turned-out-to-be-a-design-matter" class="wiki-anchor">¶</a></h1>
</blockquote>
<p>To me 100000000000000000000000.0 means 100000000000000000000000.to_f,<br>
or "floating point number closest to 100000000000000000000000".<br>
This doesn't have to be exactly 100000000000000000000000.</p>
<p>Some arguments follow.</p>
<p>== Argument from other languages ==</p>
<p>This treatment of float equality seem to be unique to Ruby.<br>
Compare with Python:</p>
<p>print(100000000000000000000000 == 100000000000000000000000.0) #=> False<br>
print( 99999999999999991611392 == 100000000000000000000000.0) #=> True<br>
print(Fraction(1,3) == 1.0/3.0) #=> False<br>
print(Fraction(1,4) == 1.0/4.0) #=> True</p>
<p>With Perl it's more complicated, as Perl's standard number type<br>
switches between native int, native float, and decimal the way Ruby switches<br>
between fixint and bigint - so 1000000000000000000.0 in Perl is<br>
decimal, not float and so exact.</p>
<p>Still, it doesn't follow "equal if converts".<br>
This is the same regardless of $x being decimal or float internally.</p>
<p>my $x = 1000000000000000000;<br>
my $a = Math::BigInt->new('1000000000000000000');<br>
my $b = Math::BigInt->new('1000000000000000001');</p>
<p>print($x == $a->numify() ? "equal" : "not"); #=> equal<br>
print($x == $b->numify() ? "equal" : "not"); #=> equal<br>
print($x == $a ? "equal" : "not"); #=> equal<br>
print($x == $b ? "equal" : "not"); #=> not</p>
<p>A counterexample to this would be C, which is quite explicit that<br>
operations involving different numeric types involve implicit conversion.<br>
It doesn't have bignums, but comparing float vs int or<br>
double vs long long will convert and lose precision before comparison.<br>
It also loses precision this way when comparing integers of<br>
different signedness etc. - this mess is a good example of what<br>
we shouldn't do ;-)</p>
<p>== Argument from sort ==</p>
<p>What would you guess this code to print?</p>
<a name="Build-array-of-bignums-add-extra-floats"></a>
<h1 >Build array of bignums, add extra floats<a href="#Build-array-of-bignums-add-extra-floats" class="wiki-anchor">¶</a></h1>
<p>big = 10**50<br>
values = (1..10).map{|x| big + x}<br>
values += (1..10).map{ big.to_f }</p>
<a name="Make-sure-its-sorted"></a>
<h1 >Make sure it's sorted<a href="#Make-sure-its-sorted" class="wiki-anchor">¶</a></h1>
<p>values.shuffle!<br>
values.sort!</p>
<a name="Just-cleanup-for-printing"></a>
<h1 >Just cleanup for printing<a href="#Just-cleanup-for-printing" class="wiki-anchor">¶</a></h1>
<p>values.reject!{|x| x.is_a?(Float)}<br>
values.map!{|x| x - big}<br>
p values</p>
<p>If you guessed [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],<br>
you'd be wrong most of the time.</p>
<p>sort relies on transitivity of <=>, so if <=><br>
says big.to_f equals both big+1 and big+7,<br>
it naturally assumes big+1 <=> big+7 will also be 0.</p>
<p>It's not a bug in sort - it's how <=> works for everything<br>
except floats.</p>
<p>== Argument from mathematics ==<br>
Ruby has a few equality-like relations - ==, eql?, equal?.<br>
They differ, but they're all (almost) mathematical equivalence relations.<br>
For all three, these can be expected:</p>
<ul>
<li>a == a</li>
<li>a == b iff b == a</li>
<li>if a == b and b == c then a == c</li>
</ul>
<p>I can think of one good exception to a == a -<br>
with things like float NaNs and sql nulls - but these really<br>
are more techniques for handling errors than real values.</p>
<p>I really cannot think of a single case where it would<br>
make sense to make equality either non-symmetric,<br>
or non-transitive.</p>
<p>Similar reasoning applies to <=> - normally it defines<br>
partial order between objects:</p>
<ul>
<li>a >= b and b >= a only if a == b</li>
<li>if a >= b and b >= c then a >= c</li>
</ul>
<p>Transitivity of equality, and transitivity of partial ordering<br>
seem to be violated only in one case in Ruby - for comparisons<br>
between floats and other numeric types. (and this causes sort<br>
to break).</p>
<p>Can you think of any other type that does something like that?</p>
<p>== Argument from rationals ==<br>
When you have mixed type operations, and one type is bigger,<br>
the most obvious thing to do is simply converting argument<br>
of smaller type to bigger type.</p>
<p>For example you can define pretty much every Rational vs Integer<br>
operation as:</p>
<p>class Rational<br>
def something(x)<br>
x = x.to_r if x.is_a?(Integer)<br>
...</p>
<p>And you can do this for Complex operations<br>
and non-complex arguments etc.</p>
<p>You never do it the other way around -<br>
converting to smaller type.<br>
This would be obviously wrong:</p>
<p>class Integer<br>
def something(x)<br>
x = x.to_i if x.is_a?(Rational)<br>
...</p>
<p>So why, if Rational can represent every floating<br>
point value (except nans/infinities/negative zero that is),<br>
do rational vs float operations downconvert to float,<br>
instead of upconverting to rational?</p>
<p>I can think of no other such case anywhere.</p>
<p>With bignum vs float, neither is strictly wider than other,<br>
but both can be represented as rationals.</p>
<p>This doesn't mean I want bignum + float to return rationals,<br>
downconversion before returning is perfectly fine.<br>
I just want it to be pretty much equivalent to this:<br>
class Integer<br>
def +(x)<br>
if x.is_a?(Float) and x.finite?<br>
return (self.to_r + x.to_r).to_f<br>
...</p>
<p>== Argument from IEEE 754 ==<br>
This .to_r/.to_f above might be puzzling, but look at this.<br>
All basic floating point operations are defined by IEEE 754<br>
standard as mathematically equivalent to this:<br>
def +(x)<br>
return (self.to_real + x.to_real).to_f(rounding_mode)<br>
end</p>
<p>Where .to_real means conversion to actual mathematical<br>
real number with potentially infinite precision, all extra<br>
bits being 0s.</p>
<p>Of course it's not implemented like that - but the result<br>
is guaranteed to be exactly the same as if it was.</p>
<p>== Other inaccuracies ==<br>
I'm not really terribly bothered by that, only by equality<br>
and <=>, but a lot of operations involving floats and other<br>
types downconvert to float too early and lose precision.</p>
<p>puts(Rational(15,11)*11.0 == 15.0) #=> false<br>
puts((Rational(15,11) * 11.0.to_r).to_f == 15.0) # => true<br>
puts(100000000000000000000000 - 100000000000000000000000.0) #=> 0<br>
puts((100000000000000000000000 - 100000000000000000000000.0.to_i).to_f) #=> 8388608.0</p>
<p>Such precision loss never happens for anything that involves<br>
only floats, or only non-floats. And it really wouldn't be<br>
that difficult to avoid it if we cared, but if even I don't,<br>
I doubt others will.<br>
=end</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=18247
2011-06-26T13:42:07Z
akr (Akira Tanaka)
akr@fsij.org
<ul><li><strong>Project</strong> changed from <i>Ruby</i> to <i>Ruby master</i></li><li><strong>Category</strong> changed from <i>core</i> to <i>core</i></li></ul>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=28026
2012-07-14T14:26:26Z
ko1 (Koichi Sasada)
<ul><li><strong>Description</strong> updated (<a title="View differences" href="/journals/28026/diff?detail_id=20690">diff</a>)</li><li><strong>Assignee</strong> changed from <i>matz (Yukihiro Matsumoto)</i> to <i>akr (Akira Tanaka)</i></li><li><strong>Target version</strong> set to <i>2.0.0</i></li></ul>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=28028
2012-07-14T14:28:01Z
akr (Akira Tanaka)
akr@fsij.org
<ul></ul><p>I think Bignum <=> Integer (and Integer <=> Bignum) can be implemented specially to compare them precisely.</p>
Ruby master - Bug #3589: Converting Bignums to Float for equality checks is wrong
https://bugs.ruby-lang.org/issues/3589?journal_id=28142
2012-07-16T18:09:01Z
akr (Akira Tanaka)
akr@fsij.org
<ul><li><strong>Status</strong> changed from <i>Assigned</i> to <i>Closed</i></li><li><strong>% Done</strong> changed from <i>0</i> to <i>100</i></li></ul><p>This issue was solved with changeset r36404.<br>
Tomasz, thank you for reporting this issue.<br>
Your contribution to Ruby is greatly appreciated.<br>
May Ruby be with you.</p>
<hr>
<ul>
<li>bignum.c (rb_big_float_cmp): compare an integer and float precisely.<br>
<a href="/issues/3589">[ruby-core:31376]</a> [Bug <a class="issue tracker-1 status-5 priority-4 priority-default closed" title="Bug: Converting Bignums to Float for equality checks is wrong (Closed)" href="https://bugs.ruby-lang.org/issues/3589">#3589</a>] reported by Tomasz Wegrzanowski.</li>
</ul>