[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

I consider this a bug in Ruby...

Randy R

12/4/2007 11:38:00 PM

I would like to know why the following code doesn't work:


# This should be 1 followed by 13 zeroes...
range = 0..10000000000000

# This should be 1 followed by 12 zeroes...
range.step(1000000000000){|i| puts i}


The error I get is this:


RangeError: bignum too big to convert into 'long'


Why is there any "converting" to do? How can this not work?
My best guess is that the Range class is not written in Ruby and, hence,
has funny limitation on how it may work. If this is the case, it is totally
unnecessary. One of the things I like about Ruby is how much of Ruby can be
written in Ruby. "require" can be written in Ruby, "attr_accessor" can be
written in Ruby and Range can be written in ruby.
What's going on, here?
Thank you...



12 Answers

Nobuyoshi Nakada

12/5/2007 2:09:00 AM

0

Hi,

At Wed, 5 Dec 2007 08:40:11 +0900,
Just Another Victim of the Ambient Morality wrote in [ruby-talk:282100]:
> Why is there any "converting" to do? How can this not work?
> My best guess is that the Range class is not written in Ruby and, hence,
> has funny limitation on how it may work.

Yes, and performance issue.


Index: stable/range.c
===================================================================
--- stable/range.c (revision 14103)
+++ stable/range.c (working copy)
@@ -255,10 +255,18 @@ range_each_func(range, func, v, e, arg)

static VALUE
-step_i(i, iter)
+step_i(i, arg)
VALUE i;
- long *iter;
+ VALUE arg;
{
- iter[0]--;
- if (iter[0] == 0) {
+ VALUE *iter = (VALUE *)arg;
+
+ if (FIXNUM_P(iter[0])) {
+ iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
+ }
+ else {
+ VALUE one = INT2FIX(1);
+ iter[0] = rb_funcall(iter[0], '-', 1, &one);
+ }
+ if (iter[0] == INT2FIX(0)) {
rb_yield(i);
iter[0] = iter[1];
@@ -308,11 +316,20 @@ range_step(argc, argv, range)
if (rb_scan_args(argc, argv, "01", &step) == 0) {
step = INT2FIX(1);
+ unit = 1;
+ }
+ else if (FIXNUM_P(step)) {
+ unit = NUM2LONG(step);
+ }
+ else {
+ VALUE tmp = rb_to_int(step);
+ unit = rb_cmpint(tmp, step, INT2FIX(0));
+ step = tmp;
}
-
- unit = NUM2LONG(step);
if (unit < 0) {
rb_raise(rb_eArgError, "step can't be negative");
- }
- if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
+ }
+ if (unit == 0)
+ rb_raise(rb_eArgError, "step can't be 0");
+ if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
long end = FIX2LONG(e);
long i;
@@ -331,11 +348,9 @@ range_step(argc, argv, range)

if (!NIL_P(tmp)) {
- VALUE args[5];
- long iter[2];
+ VALUE args[5], iter[2];

b = tmp;
- if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
args[0] = b; args[1] = e; args[2] = range;
- iter[0] = 1; iter[1] = unit;
+ iter[0] = INT2FIX(1); iter[1] = step;
rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i,
(VALUE)iter);
@@ -344,5 +359,4 @@ range_step(argc, argv, range)
ID c = rb_intern(EXCL(range) ? "<" : "<=");

- if (rb_equal(step, INT2FIX(0))) rb_raise(rb_eArgError, "step can't be 0");
while (RTEST(rb_funcall(b, c, 1, e))) {
rb_yield(b);
@@ -351,7 +365,6 @@ range_step(argc, argv, range)
}
else {
- long args[2];
+ VALUE args[2];

- if (unit == 0) rb_raise(rb_eArgError, "step can't be 0");
if (!rb_respond_to(b, id_succ)) {
rb_raise(rb_eTypeError, "can't iterate from %s",
@@ -359,6 +372,6 @@ range_step(argc, argv, range)
}

- args[0] = 1;
- args[1] = unit;
+ args[0] = INT2FIX(1);
+ args[1] = step;
range_each_func(range, step_i, b, e, args);
}
Index: trunk/range.c
===================================================================
--- trunk/range.c (revision 14103)
+++ trunk/range.c (working copy)
@@ -248,8 +248,14 @@ static VALUE
step_i(VALUE i, void *arg)
{
- long *iter = (long *)arg;
+ VALUE *iter = arg;

- iter[0]--;
- if (iter[0] == 0) {
+ if (FIXNUM_P(iter[0])) {
+ iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
+ }
+ else {
+ VALUE one = INT2FIX(1);
+ iter[0] = rb_funcall(iter[0], '-', 1, &one);
+ }
+ if (iter[0] == INT2FIX(0)) {
rb_yield(i);
iter[0] = iter[1];
@@ -298,13 +304,20 @@ range_step(int argc, VALUE *argv, VALUE
if (rb_scan_args(argc, argv, "01", &step) == 0) {
step = INT2FIX(1);
+ unit = 1;
+ }
+ else if (FIXNUM_P(step)) {
+ unit = NUM2LONG(step);
+ }
+ else {
+ VALUE tmp = rb_to_int(step);
+ unit = rb_cmpint(tmp, step, INT2FIX(0));
+ step = tmp;
}
-
- unit = NUM2LONG(step);
if (unit < 0) {
rb_raise(rb_eArgError, "step can't be negative");
- }
+ }
if (unit == 0)
rb_raise(rb_eArgError, "step can't be 0");
- if (FIXNUM_P(b) && FIXNUM_P(e)) { /* fixnums are special */
+ if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
long end = FIX2LONG(e);
long i;
@@ -323,12 +336,11 @@ range_step(int argc, VALUE *argv, VALUE

if (!NIL_P(tmp)) {
- VALUE args[2];
- long iter[2];
+ VALUE args[2], iter[2];

b = tmp;
args[0] = e;
args[1] = EXCL(range) ? Qtrue : Qfalse;
- iter[0] = 1;
- iter[1] = unit;
+ iter[0] = INT2FIX(1);
+ iter[1] = step;
rb_block_call(b, rb_intern("upto"), 2, args, step_i, (VALUE)iter);
}
@@ -344,5 +356,5 @@ range_step(int argc, VALUE *argv, VALUE
}
else {
- long args[2];
+ VALUE args[2];

if (!rb_respond_to(b, id_succ)) {
@@ -350,6 +362,6 @@ range_step(int argc, VALUE *argv, VALUE
rb_obj_classname(b));
}
- args[0] = 1;
- args[1] = unit;
+ args[0] = INT2FIX(1);
+ args[1] = step;
range_each_func(range, step_i, b, e, args);
}
@@ -867,6 +879,4 @@ void
Init_Range(void)
{
- VALUE members;
-
id_cmp = rb_intern("<=>");
id_succ = rb_intern("succ");


--
Nobu Nakada

botp

12/5/2007 4:09:00 AM

0

On Dec 5, 2007 7:40 AM, Just Another Victim of the Ambient Morality
<ihatespam@hotmail.com> wrote:
> RangeError: bignum too big to convert into 'long'

possible bug. bignum is really too big for long :)

> Why is there any "converting" to do? How can this not work?

range is expensive.
try numeric step,

irb(main):010:0> r=1_000_000_000_000
=> 1000000000000
irb(main):011:0> r.step(r*10,r){|x| p x}
1000000000000
2000000000000
3000000000000
4000000000000
5000000000000
6000000000000
7000000000000
8000000000000
9000000000000
10000000000000
=> 1000000000000
irb(main):012:0>

kind regards -botp

Randy R

12/5/2007 5:23:00 AM

0


"Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
news:20071205020914.E6311E0666@mail.bc9.jp...
> Hi,
>
> At Wed, 5 Dec 2007 08:40:11 +0900,
> Just Another Victim of the Ambient Morality wrote in [ruby-talk:282100]:
>> Why is there any "converting" to do? How can this not work?
>> My best guess is that the Range class is not written in Ruby and,
>> hence,
>> has funny limitation on how it may work.
>
> Yes, and performance issue.

Just so I'm clear on this; the Range class is implemented in C for
performance reasons? Was the performance of a Ruby version actually an
issue? I don't think anybody here uses Ruby for its blazing speed. I've
said this before but I guess it bears repeating. I don't use Ruby to write
fast programs, I use Ruby to write programs fast. This is, obviously, just
a personal opinion but that's the role Ruby plays for me and I think it's
the most common case.
Furthermore, I think there is an important lesson to be had, here.
There are many different stories, out there, that exemplify this but they
all end with the same phrase: I can make my program fast, too, if it didn't
have to work. This implementation of Range doesn't work. At the very
least, it's buggy, which, to some people, is the same thing.
Even if performance were important, it didn't even fall back onto a Ruby
implementation. It might be a little harder to maintain but you could write
a Ruby version and use that whenever you encounter a "RangerError: bignum
too big to convert into 'long'" error. I don't think Range changes too much
between Ruby releases, so I really don't see it being a maintenance
headache. Again, generally, speaking, a slow program that works is better
than a fast program that doesn't work...
Finally, the .each method worked! I didn't let it run all the way to
MAX_LONG, or whatever the constant is, if there is a constant, but you all
know what I mean. Maybe a bug occurs there but what little I let run
worked. How can .each work but .step not work? Especially ironic since
..step produced less iterations than .each. I mean, where's the concern for
performance, there? You'd imagine that there'd be more concern for
performance for .each since it will produce more iterations...
So, perhaps all this can be fixed for Ruby 1.9 and Rite? What do you
all think?
Thank you...



Randy R

12/5/2007 5:36:00 AM

0


"botp" <botpena@gmail.com> wrote in message
news:c39f93e00712042008h64b633ebj3413fc8b9dc7410b@mail.gmail.com...
> On Dec 5, 2007 7:40 AM, Just Another Victim of the Ambient Morality
> <ihatespam@hotmail.com> wrote:
>> RangeError: bignum too big to convert into 'long'
>
> possible bug. bignum is really too big for long :)
>
>> Why is there any "converting" to do? How can this not work?
>
> range is expensive.
> try numeric step,
>
> irb(main):010:0> r=1_000_000_000_000
> => 1000000000000
> irb(main):011:0> r.step(r*10,r){|x| p x}
> 1000000000000
> 2000000000000
> 3000000000000
> 4000000000000
> 5000000000000
> 6000000000000
> 7000000000000
> 8000000000000
> 9000000000000
> 10000000000000
> => 1000000000000
> irb(main):012:0>

In what way is Range expensive? Why is it so expensive?
Thank you...



Nobuyoshi Nakada

12/5/2007 6:11:00 AM

0

Hi,

At Wed, 5 Dec 2007 14:25:07 +0900,
Just Another Victim of the Ambient Morality wrote in [ruby-talk:282132]:
> "Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
> news:20071205020914.E6311E0666@mail.bc9.jp...
> > Hi,
> >
> > At Wed, 5 Dec 2007 08:40:11 +0900,
> > Just Another Victim of the Ambient Morality wrote in [ruby-talk:282100]:
> >> Why is there any "converting" to do? How can this not work?
> >> My best guess is that the Range class is not written in Ruby and,
> >> hence,
> >> has funny limitation on how it may work.
> >
> > Yes, and performance issue.
>
> Just so I'm clear on this; the Range class is implemented in C for
> performance reasons?

It isn't the only reason why Range is implemented in C, I wrote
about your "limitation."

If Range were written in Ruby, it couldn't be used until
something was loaded. It wasn't acceptable for intrinsic
classes.

--
Nobu Nakada

Charles Oliver Nutter

12/5/2007 7:34:00 AM

0

Just Another Victim of the Ambient Morality wrote:
> Just so I'm clear on this; the Range class is implemented in C for
> performance reasons? Was the performance of a Ruby version actually an
> issue? I don't think anybody here uses Ruby for its blazing speed.

Perhaps not yet, or not 1.8.6. But this is going to change.

- Charlie

Lloyd Linklater

12/5/2007 1:01:00 PM

0

Just Another Victim...:
> I would like to know why the following code doesn't work:
>
>
> # This should be 1 followed by 13 zeroes...
> range = 0..10000000000000
>
> # This should be 1 followed by 12 zeroes...
> range.step(1000000000000){|i| puts i}
>

fyi, to help with counting zeros, you can use an underscore like a
comma:

range = 0..10_000_000_000_000
--
Posted via http://www.ruby-....

Randy R

12/5/2007 1:40:00 PM

0


"Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
news:20071205061035.DD12DE0697@mail.bc9.jp...
> Hi,
>
> At Wed, 5 Dec 2007 14:25:07 +0900,
> Just Another Victim of the Ambient Morality wrote in [ruby-talk:282132]:
>> "Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
>> news:20071205020914.E6311E0666@mail.bc9.jp...
>> > Hi,
>> >
>> > At Wed, 5 Dec 2007 08:40:11 +0900,
>> > Just Another Victim of the Ambient Morality wrote in
>> > [ruby-talk:282100]:
>> >> Why is there any "converting" to do? How can this not work?
>> >> My best guess is that the Range class is not written in Ruby and,
>> >> hence,
>> >> has funny limitation on how it may work.
>> >
>> > Yes, and performance issue.
>>
>> Just so I'm clear on this; the Range class is implemented in C for
>> performance reasons?
>
> It isn't the only reason why Range is implemented in C, I wrote
> about your "limitation."

Where did you write about this? I'd be happy to read it...


> If Range were written in Ruby, it couldn't be used until
> something was loaded. It wasn't acceptable for intrinsic
> classes.

Okay, this makes more sense to me. So, some built-in classes use Range
and they couldn't if it were written in Ruby.
This brings up several issues. One would be, why not? Wouldn't it be
nice if the Ruby interpreter's built in classes could be written in Ruby?
Now, I understand that implementation issues can be hard to solve but it's
certainly something to keep in mind for something like Ruby 1.9 or Rite...
Another issue would be: did they have to use a long? Just 'cause the
implementation of Range is written in C doesn't mean that they couldn't
still use Bignum, does it? More to the point, couldn't the Ruby C code be
written so that it didn't care what type was passed in, as long as they
supported integral operations? I'd be surprised if it couldn't...
Thank you...



MonkeeSage

12/5/2007 2:33:00 PM

0

On Dec 5, 7:40 am, "Just Another Victim of the Ambient Morality"
<ihates...@hotmail.com> wrote:
> "Nobuyoshi Nakada" <n...@ruby-lang.org> wrote in message
>
> news:20071205061035.DD12DE0697@mail.bc9.jp...
>
>
>
> > Hi,
>
> > At Wed, 5 Dec 2007 14:25:07 +0900,
> > Just Another Victim of the Ambient Morality wrote in [ruby-talk:282132]:
> >> "Nobuyoshi Nakada" <n...@ruby-lang.org> wrote in message
> >>news:20071205020914.E6311E0666@mail.bc9.jp...
> >> > Hi,
>
> >> > At Wed, 5 Dec 2007 08:40:11 +0900,
> >> > Just Another Victim of the Ambient Morality wrote in
> >> > [ruby-talk:282100]:
> >> >> Why is there any "converting" to do? How can this not work?
> >> >> My best guess is that the Range class is not written in Ruby and,
> >> >> hence,
> >> >> has funny limitation on how it may work.
>
> >> > Yes, and performance issue.
>
> >> Just so I'm clear on this; the Range class is implemented in C for
> >> performance reasons?
>
> > It isn't the only reason why Range is implemented in C, I wrote
> > about your "limitation."
>
> Where did you write about this? I'd be happy to read it...
>
> > If Range were written in Ruby, it couldn't be used until
> > something was loaded. It wasn't acceptable for intrinsic
> > classes.
>
> Okay, this makes more sense to me. So, some built-in classes use Range
> and they couldn't if it were written in Ruby.
> This brings up several issues. One would be, why not? Wouldn't it be
> nice if the Ruby interpreter's built in classes could be written in Ruby?

Well, might be nice for people who want to hack on very low-level ruby
stuff without going into the C, but not a good idea. PyPy (a python
interpreter written in python) is a factor of 2000 times slower(!)
than cPython when running on top of cPython. Implementing the base
classes of ruby in ruby, would have similar negative performance
impact.

> Now, I understand that implementation issues can be hard to solve but it's
> certainly something to keep in mind for something like Ruby 1.9 or Rite...
> Another issue would be: did they have to use a long? Just 'cause the
> implementation of Range is written in C doesn't mean that they couldn't
> still use Bignum, does it? More to the point, couldn't the Ruby C code be
> written so that it didn't care what type was passed in, as long as they
> supported integral operations? I'd be surprised if it couldn't...
> Thank you...

Looks like Nobu posted the patches above.

Regards,
Jordan

Gerardo Santana Gómez Garrido

12/5/2007 4:07:00 PM

0

On Dec 5, 2007 7:46 AM, Just Another Victim of the Ambient Morality
<ihatespam@hotmail.com> wrote:
>
> "Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
> news:20071205061035.DD12DE0697@mail.bc9.jp...
> > Hi,
> >
> > At Wed, 5 Dec 2007 14:25:07 +0900,
> > Just Another Victim of the Ambient Morality wrote in [ruby-talk:282132]:
> >> "Nobuyoshi Nakada" <nobu@ruby-lang.org> wrote in message
> >> news:20071205020914.E6311E0666@mail.bc9.jp...
> >> > Hi,
> >> >
> >> > At Wed, 5 Dec 2007 08:40:11 +0900,
> >> > Just Another Victim of the Ambient Morality wrote in
> >> > [ruby-talk:282100]:
> >> >> Why is there any "converting" to do? How can this not work?
> >> >> My best guess is that the Range class is not written in Ruby and,
> >> >> hence,
> >> >> has funny limitation on how it may work.
> >> >
> >> > Yes, and performance issue.
> >>
> >> Just so I'm clear on this; the Range class is implemented in C for
> >> performance reasons?
> >
> > It isn't the only reason why Range is implemented in C, I wrote
> > about your "limitation."
>
> Where did you write about this? I'd be happy to read it...
>
>
> > If Range were written in Ruby, it couldn't be used until
> > something was loaded. It wasn't acceptable for intrinsic
> > classes.
>
> Okay, this makes more sense to me. So, some built-in classes use Range
> and they couldn't if it were written in Ruby.
> This brings up several issues. One would be, why not? Wouldn't it be
> nice if the Ruby interpreter's built in classes could be written in Ruby?

That's what Rubinius is.

http://...


> Now, I understand that implementation issues can be hard to solve but it's
> certainly something to keep in mind for something like Ruby 1.9 or Rite...
> Another issue would be: did they have to use a long? Just 'cause the
> implementation of Range is written in C doesn't mean that they couldn't
> still use Bignum, does it? More to the point, couldn't the Ruby C code be
> written so that it didn't care what type was passed in, as long as they
> supported integral operations? I'd be surprised if it couldn't...
> Thank you...


That's what Nobuyoshi's patch is about.


--
Gerardo Santana