From 412b023742171585b123cf20fcbb9b94476582ac Mon Sep 17 00:00:00 2001 From: mame Date: Thu, 15 Nov 2012 13:50:55 +0000 Subject: * range.c (range_bsearch): fix some bugs: a documentation bug, a wrong condition, missed break in switch/case, and workaround for GCC optimization. See [ruby-core:49364] in detail. A great patch from Heesob Park. [Bug #7352] [Feature #4766] * array.c (rb_ary_bsearch): fix similar bug (missed break). * test/ruby/test_range.rb: add two test cases for above. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37662 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 11 +++++++++++ array.c | 2 +- range.c | 16 ++++++++-------- test/ruby/test_range.rb | 3 +++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index ccaf18aa08..ee8bd21692 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Thu Nov 15 22:39:32 2012 Yusuke Endoh + + * range.c (range_bsearch): fix some bugs: a documentation bug, a wrong + condition, missed break in switch/case, and workaround for GCC + optimization. See [ruby-core:49364] in detail. A great patch from + Heesob Park. [Bug #7352] [Feature #4766] + + * array.c (rb_ary_bsearch): fix similar bug (missed break). + + * test/ruby/test_range.rb: add two test cases for above. + Thu Nov 15 22:41:57 2012 Koichi Sasada * vm_exec.h (GENTRY): GENTRY should be pointer size. diff --git a/array.c b/array.c index 4fce3285f5..25fd829aa9 100644 --- a/array.c +++ b/array.c @@ -2451,7 +2451,7 @@ rb_ary_bsearch(VALUE ary) else if (rb_obj_is_kind_of(v, rb_cNumeric)) { switch (rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0))) { case 0: return val; - case 1: smaller = 1; + case 1: smaller = 1; break; case -1: smaller = 0; } } diff --git a/range.c b/range.c index 4495d5d314..b5cdc9e442 100644 --- a/range.c +++ b/range.c @@ -513,9 +513,9 @@ range_step(int argc, VALUE *argv, VALUE range) * satisfies the condition, it returns nil. * * ary = [0, 100, 100, 100, 200] - * (0..4).bsearch {|i| 100 - i } #=> 1, 2 or 3 - * (0..4).bsearch {|i| 300 - i } #=> nil - * (0..4).bsearch {|i| 50 - i } #=> nil + * (0..4).bsearch {|i| 100 - ary[i] } #=> 1, 2 or 3 + * (0..4).bsearch {|i| 300 - ary[i] } #=> nil + * (0..4).bsearch {|i| 50 - ary[i] } #=> nil * * You must not mix the two modes at a time; the block must always * return either true/false, or always return a number. It is @@ -543,10 +543,10 @@ range_bsearch(VALUE range) smaller = 0; \ } \ else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \ - switch (rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)) < 0) { \ + switch (rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0))) { \ case 0: return val; \ - case 1: smaller = 1; \ - case -1: smaller = 0; \ + case -1: smaller = 1; break; \ + case 1: smaller = 0; \ } \ } \ else { \ @@ -586,6 +586,7 @@ range_bsearch(VALUE range) double high = RFLOAT_VALUE(rb_Float(end)); double mid, org_high; int count; + org_high = high; #ifdef FLT_RADIX #ifdef DBL_MANT_DIG #define BSEARCH_MAXCOUNT (((FLT_RADIX) - 1) * (DBL_MANT_DIG + DBL_MAX_EXP) + 100) @@ -646,7 +647,7 @@ range_bsearch(VALUE range) } if (isinf(low) && low < 0) { /* the range is (-INFINITY..high) */ - double nlow = -1.0, dec; + volatile double nlow = -1.0, dec; if (nlow > high) nlow = high; count = BSEARCH_MAXCOUNT; /* find lower bound by checking low, low*2, low*4, ... */ @@ -697,7 +698,6 @@ range_bsearch(VALUE range) binsearch: /* find the desired value within low..high */ /* where low is not -INFINITY and high is not INFINITY */ - org_high = high; count = BSEARCH_MAXCOUNT; while (low < high && count >= 0) { mid = low + ((high - low) / 2); diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 0600f694f7..ca0e155f3d 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -417,6 +417,9 @@ class TestRange < Test::Unit::TestCase v = (-inf..0).bsearch {|x| x > -Float::MAX } assert_operator(-Float::MAX, :<, v) assert_equal(nil, v.infinite?) + + assert_in_delta(1.0, (0.0..inf).bsearch {|x| Math.log(x) >= 0 }) + assert_in_delta(7.0, (0.0..10).bsearch {|x| 7.0 - x }) end def test_bsearch_for_bignum -- cgit v1.2.3