Optimize Range#bsearch for beginless/endless ranges within Fixnum
This commit is contained in:
parent
ab637cad2b
commit
7e350f5310
@ -1,9 +1,21 @@
|
|||||||
prelude: |
|
prelude: |
|
||||||
r = (1..)
|
re = (1..)
|
||||||
|
rb = (..0)
|
||||||
|
|
||||||
benchmark:
|
benchmark:
|
||||||
'10**1': r.bsearch { |x| x >= 10 }
|
'endless 10**0': re.bsearch { |x| x >= 1 }
|
||||||
'10**2': r.bsearch { |x| x >= 100 }
|
'endless 10**1': re.bsearch { |x| x >= 10 }
|
||||||
'10**3': r.bsearch { |x| x >= 1000 }
|
'endless 10**2': re.bsearch { |x| x >= 100 }
|
||||||
'10**4': r.bsearch { |x| x >= 10000 }
|
'endless 10**3': re.bsearch { |x| x >= 1000 }
|
||||||
'10**5': r.bsearch { |x| x >= 100000 }
|
'endless 10**4': re.bsearch { |x| x >= 10000 }
|
||||||
|
'endless 10**5': re.bsearch { |x| x >= 100000 }
|
||||||
|
'endless 10**10': re.bsearch { |x| x >= 10000000000 }
|
||||||
|
'endless 10**100': re.bsearch { |x| x >= 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
|
||||||
|
'beginless -10**0': rb.bsearch { |x| x >= -1 }
|
||||||
|
'beginless -10**1': rb.bsearch { |x| x >= -10 }
|
||||||
|
'beginless -10**2': rb.bsearch { |x| x >= -100 }
|
||||||
|
'beginless -10**3': rb.bsearch { |x| x >= -1000 }
|
||||||
|
'beginless -10**4': rb.bsearch { |x| x >= -10000 }
|
||||||
|
'beginless -10**5': rb.bsearch { |x| x >= -100000 }
|
||||||
|
'beginless -10**10': rb.bsearch { |x| x >= -10000000000 }
|
||||||
|
'beginless -10**100': rb.bsearch { |x| x >= -10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 }
|
||||||
|
32
range.c
32
range.c
@ -703,10 +703,10 @@ range_bsearch(VALUE range)
|
|||||||
* (-1...0.0).bsearch to yield -0.0.
|
* (-1...0.0).bsearch to yield -0.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BSEARCH(conv) \
|
#define BSEARCH(conv, excl) \
|
||||||
do { \
|
do { \
|
||||||
RETURN_ENUMERATOR(range, 0, 0); \
|
RETURN_ENUMERATOR(range, 0, 0); \
|
||||||
if (EXCL(range)) high--; \
|
if (excl) high--; \
|
||||||
org_high = high; \
|
org_high = high; \
|
||||||
while (low < high) { \
|
while (low < high) { \
|
||||||
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
|
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
|
||||||
@ -726,22 +726,26 @@ range_bsearch(VALUE range)
|
|||||||
return satisfied; \
|
return satisfied; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define BSEARCH_FIXNUM(beg, end, excl) \
|
||||||
|
do { \
|
||||||
|
long low = FIX2LONG(beg); \
|
||||||
|
long high = FIX2LONG(end); \
|
||||||
|
long mid, org_high; \
|
||||||
|
BSEARCH(INT2FIX, (excl)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
beg = RANGE_BEG(range);
|
beg = RANGE_BEG(range);
|
||||||
end = RANGE_END(range);
|
end = RANGE_END(range);
|
||||||
|
|
||||||
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
|
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
|
||||||
long low = FIX2LONG(beg);
|
BSEARCH_FIXNUM(beg, end, EXCL(range));
|
||||||
long high = FIX2LONG(end);
|
|
||||||
long mid, org_high;
|
|
||||||
BSEARCH(INT2FIX);
|
|
||||||
}
|
}
|
||||||
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
||||||
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
|
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
|
||||||
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
|
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
|
||||||
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
|
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
|
||||||
int64_t mid, org_high;
|
int64_t mid, org_high;
|
||||||
BSEARCH(int64_as_double_to_num);
|
BSEARCH(int64_as_double_to_num, EXCL(range));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (is_integer_p(beg) && is_integer_p(end)) {
|
else if (is_integer_p(beg) && is_integer_p(end)) {
|
||||||
@ -755,7 +759,12 @@ range_bsearch(VALUE range)
|
|||||||
VALUE mid = rb_funcall(beg, '+', 1, diff);
|
VALUE mid = rb_funcall(beg, '+', 1, diff);
|
||||||
BSEARCH_CHECK(mid);
|
BSEARCH_CHECK(mid);
|
||||||
if (smaller) {
|
if (smaller) {
|
||||||
return bsearch_integer_range(beg, mid, 0);
|
if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
|
||||||
|
BSEARCH_FIXNUM(beg, mid, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return bsearch_integer_range(beg, mid, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
||||||
beg = mid;
|
beg = mid;
|
||||||
@ -768,7 +777,12 @@ range_bsearch(VALUE range)
|
|||||||
VALUE mid = rb_funcall(end, '+', 1, diff);
|
VALUE mid = rb_funcall(end, '+', 1, diff);
|
||||||
BSEARCH_CHECK(mid);
|
BSEARCH_CHECK(mid);
|
||||||
if (!smaller) {
|
if (!smaller) {
|
||||||
return bsearch_integer_range(mid, end, 0);
|
if (FIXNUM_P(mid) && FIXNUM_P(end)) {
|
||||||
|
BSEARCH_FIXNUM(mid, end, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return bsearch_integer_range(mid, end, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
||||||
end = mid;
|
end = mid;
|
||||||
|
@ -1047,7 +1047,10 @@ class TestRange < Test::Unit::TestCase
|
|||||||
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 })
|
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| ary[i - bignum] >= 100 })
|
||||||
assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true })
|
assert_equal(bignum + 0, (bignum...bignum+ary.size).bsearch {|i| true })
|
||||||
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false })
|
assert_equal(nil, (bignum...bignum+ary.size).bsearch {|i| false })
|
||||||
|
|
||||||
|
assert_equal(bignum * 2 + 1, (0...).bsearch {|i| i > bignum * 2 })
|
||||||
assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 })
|
assert_equal(bignum * 2 + 1, (bignum...).bsearch {|i| i > bignum * 2 })
|
||||||
|
assert_equal(-bignum * 2 + 1, (...0).bsearch {|i| i > -bignum * 2 })
|
||||||
assert_equal(-bignum * 2 + 1, (...-bignum).bsearch {|i| i > -bignum * 2 })
|
assert_equal(-bignum * 2 + 1, (...-bignum).bsearch {|i| i > -bignum * 2 })
|
||||||
|
|
||||||
assert_raise(TypeError) { ("a".."z").bsearch {} }
|
assert_raise(TypeError) { ("a".."z").bsearch {} }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user