in reply to Converting an array of bytes into a BigInt - speed considerations

It sounds like you would want pack() or unpack() for a BigInt. But as far as I can see, the docs don't mention this as an option.

OK, perhaps a slightly faster implementation might be to replace the multiplication by a shift left. And definitely drop the exponentiation if you can. I suspect this is the real cause for the long processing time.

Er... you have a Little Endian representation in the "byte array", haven't you? Big Endian is easier to process. OK, here I go:

use Math::BigInt; print bytearray_to_bigint(127,2); use Data::Dumper; sub bytearray_to_bigint { my @array = reverse @_; #Big Endian my $result = Math::BigInt->new('0'); foreach my $a (@array) { ($result <<= 8) += $a; # This alternative doesn't work: # $result = $result->blsft(8)->badd($a); } return $result; }
To be honest, I'd rather have replaced the overloaded operators with explicit calls to blsft and badd, but for some reason unknown to me these appear to return simple strings, not Math::BigInt objects, as I gather from the docs they should. (BTW I'm using 0.01, as it comes with perl 5.6.1.) Oh well. I hope this is a decent starting point anyway.

Update: I have the impression that Math::BigInt is a Pure Perl implementation by default. Ugh! If you use it with one of the XS "driver" libraries, you might get a real speed boost. See the section on "MATH LIBRARY" in the new docs. Math::BigInt::BitVect+Bit::Vector and Math::BigInt::FastCalc look like the most promising candidates to me. You might have to download an update to Math::BigInt to make use of it. They are available for Windows, Perl 5.6.x at the 5.6plus repository. Ooh, "Math::BigIntFast" looks nice, too, even though I can't find a trace of it on CPAN. Odd.

Update: It suddenly dawned on me that it's easy to get up to a factor 4 of speedup, by unpacking your byte stream into long integers (unsigned 32 bits) instead of in bytes. That way, you can construct your bigint in 4 bytes per step, instead of just 1 byte for each loop.

Unpacking a string to longs, on a PC (Little Endioan), can be done using:

@ulongs = unpack 'V*', $bytestring;
Of course, that means that you need to shift left by 32 bits, instead of by 8, per step.

Replies are listed 'Best First'.
Re: Re: Converting an array of bytes into a BigInt - speed considerations
by dempa (Friar) on Jan 23, 2003 at 16:02 UTC

    Thanks for the suggestions (everyone)!

    I just updated Math::BigInt to v1.64 and now my program won't work. Apparently, brsft doesn't return the remainder anymore, only the quotient (it used to return a list with (quo,rem)).

    Why, oh, why didn't I pay more attention in math class at college! :)

    update: I was just voicing my frustration, not asking anyone to post a solution for me.

    -- 
    dempa

      That's a bummer. However, it needn't be a total disaster. You can get both quotient and remainder, by making two calls on the same data. For example, band() seems to work just fine as follows, to get at the remainder of a division by 256:
      use Math::BigInt; $a = new Math::BigInt(0xFE78A3); printf '%02X', $a->band(0xFF);
      Result:
      A3
      This is with Math::BigInt version 1.64.

      Update: Yeah, the real solution would be for you to go back to school. ;-)

        Yeah, well I solved it like this:

        sub bigint_to_bytearray { my $bigint = shift; my @bytes; while(1) { push(@bytes,($bigint & 255)); $bigint->brsft(8); last if $bigint == 0; } return @bytes; }

        -- 
        dempa