Boldra has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to generate a range between two large integers

This works:
use bignum; my $x = 2**1024; for ( $i = $x; $i <= ($x+2); $i++) { say $i };
But this does not:
use bignum; my $x = 2**1024 for( $x .. $x+2 ) { say }
Naturally, I prefer the latter for readability. I've never liked c-style loops, and this is really doesn't seem to be the place for them.

The second example aborts with "Range iterator outside integer range". Am I missing something here? Is there another way where I can keep the ( $x.. $x+2) version? 2**1024 is the maximum integer that I will have to deal with, and the C-style loop allows it only when I use bignum (but not Math::BigInt)


- Boldra

Replies are listed 'Best First'.
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by ikegami (Patriarch) on May 07, 2009 at 10:47 UTC

    The range operator (..) isn't overloadable, so bigint can't make it handle Math::BigInt objects.

    I don't know why the range operator isn't overloadable. Maybe it's related to its complexity as an operator. Even if the range operator was overloadable, it's not actually used when doing for (x..y). That's the reason why for (x..y) is efficient.

      Thanks for the simple and accurate answer, and thanks to everyone else who posted.


      - Boldra
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by BrowserUk (Patriarch) on May 07, 2009 at 11:30 UTC

    It's a silly point, but if the delta of your range is anything like a reasonable number, you can still use the iterator for; with a little ingenuity:

    my $x = Math::BigNum->new( 2 ) ** 1024; for my $delta ( 1 .. 2 ) { print $x + $delta; }

    Whether that satisfies is a personal taste thing I think.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by BrowserUk (Patriarch) on May 07, 2009 at 10:49 UTC

    The simple answer is no. Perl limits its range iterators to integers. But even if it allowed floating point iterators it wouldn't help you, as there is no binary floating point representation that can accurately hold a 315,653(*) 309 digit integer!

    (*Perl lied to me! Don't use bignum; and use Math::BigInt; in the same code. It appears to get confused!)


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Perl limits its range iterators to integers

      Actually, signed integers, which gives -2**31..2**31-2

        Well, I never said "unsigned" :) But it's a point worth making. Though on my system the limits are somewhat different:

        ] Perl> print for 1 .. 2**62;; 1 2 3 4 5 6 7 8 9 10 11

        I won't post the rest, so you'll have to take my word that it does actually get beyond 2**31-2 :)


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by Anonymous Monk on May 07, 2009 at 10:36 UTC
    The range operator is kind of primitive.splain
    echo Range iterator outside integer range|splain Range iterator outside integer range (#1) (F) One (or both) of the numeric arguments to the range operator " +.." are outside the range which can be represented by integers interna +lly. One possible workaround is to force Perl to use magical string inc +rement by prepending "0" to your numbers.
    You can always range :)
    sub range { my( $start, $end ) = @_; my @ret; while($start <= $end ){ push @ret, $start; $start++; } return @ret; } use bignum; my $x = 2**1024 for(range( $x , $x+2 )) { say }
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by syphilis (Archbishop) on May 07, 2009 at 10:52 UTC
    ... the C-style loop allows it only when I use bignum (but not Math::BigInt)

    You can use the C-style loop with Math::BigInt, but you just have to create $x in a slightly different way - eg:
    use warnings; use strict; use feature 'say'; use Math::BigInt; my $x = Math::BigInt->new(1); $x <<= 1024; for(my $i = $x; $i <= $x + 2; $i++) { say $i; }
    The C-style loop works with both bignum and Math::BigInt because it makes use of operators that are overloaded. Unfortunately, the '..' operator is not currently overloaded, and that's why the second loop fails.

    Cheers,
    Rob

      but you just have to create $x in a slightly different way

      No you don't. The direct equivalent works just fine.

      >perl -MMath::BigInt -le"my $x = Math::BigInt->new(2) ** Math::BigInt- +>new(1024); print $x" 1797693134862315907729305190789024733617976978942306572734300811577326 +758055009631327084773224075360211201138798713933576587897688144166224 +928474306394741243777678934248654852763022196012460941194530829520850 +057688381506823424628814739131105408272371633505106845862982399472459 +38479716304835356329624224137216

      It can even be simplified

      >perl -MMath::BigInt -le"my $x = Math::BigInt->new(2) ** 1024; print $ +x" 1797693134862315907729305190789024733617976978942306572734300811577326 +758055009631327084773224075360211201138798713933576587897688144166224 +928474306394741243777678934248654852763022196012460941194530829520850 +057688381506823424628814739131105408272371633505106845862982399472459 +38479716304835356329624224137216
        The direct equivalent works just fine

        I was thinking that the "direct equivalent" would be:
        my $x = Math::BigInt->new(2**1024);
        which doesn't work quite so well :-)

        Cheers,
        Rob
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by JavaFan (Canon) on May 07, 2009 at 11:50 UTC
    Just use magical increment.
    use bignum; my $x = 2**1024; for ("A$x" .. "A${\($x+2)}") { say substr $_, 1; }
Re: big integers forcing me to be a C programmer: "range iterator outside integer range"
by NetWallah (Canon) on May 07, 2009 at 17:45 UTC
    This works, and IMHO is reasonably readable:
    my $x = 2**1024; for( map {$x+$_} 0..2){ print qq|$_\n|; }

         ..to maintain is to slowly feel your soul, sanity and sentience ebb away as you become one with the Evil.