Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

c-style for loop versus list for loop, and bigint

by AR (Friar)
on May 19, 2011 at 20:12 UTC ( [id://905791]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks,

I am completely stumped by why these two pieces of code act so differently when I run them. This came from a project euler question 48, if you're interested.

Consider

use strict; use warnings; use bigint; my $answer = 0; for my $i ( 1 .. 999 ) { print "$i: $answer\n"; $answer += $i ** $i; } $answer %= 10 ** 10; print "$answer\n";

versus:

use strict; use warnings; use bigint; my $answer = 0; for ( my $i = 1; $i < 1000; $i++ ) { print "$i: $answer\n"; $answer += $i ** $i; } $answer %= 10 ** 10; print "$answer\n";

The first piece of code assigns inf when $i == 145, but the second piece of code keeps on going. Why is the case?

Replies are listed 'Best First'.
Re: c-style for loop versus list for loop, and bigint
by BrowserUk (Patriarch) on May 19, 2011 at 20:40 UTC

    Because the range operator (integer iterator) is not affected by bigint. You can also do:

    use strict; use warnings; use bigint; my $answer = 0; for my $i ( map 0+$_,1 .. 999 ) { print "$i: $answer\n"; $answer += $i ** $i; } $answer %= 10 ** 10; print "$answer\n";

    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.

      Because the range operator (integer iterator) is not affected by bigint

      Is that intentional?

        Is that intentional?

        Yes. The range operator is intended to be efficient for the majority of every day use cases.

        As you've already discovered, if you need to iterate infinite precision integers, you can easily use the c-style alternative.


        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.
        >Is that intentional?

        let's say it's historical. :)

        I suppose the range iterator is just older than bigint.

        I wouldn't be surprised if bigint is just just a hack to overload scalars with objects and the effect of iterating over a range was forgotten.

        Cheers Rolf

Re: c-style for loop versus list for loop, and bigint
by LanX (Saint) on May 19, 2011 at 20:27 UTC
    IIRC the range operator works internally only on unsigned integers, i.e. 32 bits or 64 bits depending on your compilation. I suppose bigint doesn't influence it.

    I'll search and update a similar discussion we had about this.

    UPDATE: here it is Infinity and Inf?

    IMHO a bug or at least a reasonable feature request.

    Cheers Rolf

    UPDATE:

    A two part answer to your question:

    Part1:

    As I thought, the range operator only returns "normal" integers, and 145**145 causes an overflow and becomes INF.

    But copying to another var helps.

    my $answer = 1; for my $j ( 1 .. 999 ) { print "$i: $answer\n"; $i=$j+0; # $i is now bigint $answer += $i ** $i; }

    For the records, I didn't say brute force is the best way to solve an Euler question... ;)

    Part2:

    The second part of the answer is that foreach doesn't do a scalar assignment to $i, where bigint could intercept by auto-blessing $i into Math::BigInt. Foreach makes $i an alias of the integer values from the range, such that the **-operator isn't overloaded and produces an overflow.

    So the only way to solve this is to make the range operator operating on big-ints on demand.

Re: c-style for loop versus list for loop, and bigint
by Fletch (Bishop) on May 19, 2011 at 20:23 UTC

    My off the cuff guess would be that the bigint pragma isn't affecting the iterator underlying your 1..999 (which I want to say is optimized under the covers so an actual list isn't built) whereas it does affect the explicit incrementing.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: c-style for loop versus list for loop, and bigint
by wind (Priest) on May 19, 2011 at 20:53 UTC

    You can confirm that this issue is isolated to the range operator by first taking it out of the for loop and then throwing in a translation with map.

    Problem still exists below, so it's not some optimization of the for loop:

    my @a = (1..999); for my $i (@a) {

    Problem goes away due to using integers not created by the range operator:

    my $j = 0; my @a = map {++$j} (1..999); for my $i (@a) {

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://905791]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (7)
As of 2024-04-16 09:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found