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

Hello to everyone, I have a sub{} that gets a number, divies it by 222 and prints out the reasult :
#!/usr/bin/perl -w use strict; sub longdiv($) { # take the parameter passed into the sub and store in $in my $in = shift; # initialise $carry and $out variables my $carry = 0; my $out = ''; # for each position in the $in string for (my $i = 0; $i < length($in); $i++) { # take a single character at that position and store in $numer +ator my $numerator = substr($in, $i, 3); # add $carry to it $numerator += $carry; # $carry equals $numerator mod 222 $carry = ($numerator % 222); # append the integer division of $numerator by two to the end +of the $out variable $out .= int($numerator / 222); } # return the result return $out; } # call the function and print the output print longdiv2("15000000") . "\n";
now, i hope there's no problem up to here; but what i need is that function in reverse (yes... i have slight problems with mathematics...), that means that the new function should get the $carry and $out of longdive() and reasult with $in, but not by just $out*222+$carry, because i work with numbers that have thousands of digits... Thanks in advance.

Replies are listed 'Best First'.
Re: Reversed long division
by ikegami (Patriarch) on Jun 29, 2005 at 16:39 UTC
    Have you tried Math::BigInt or Math::BigFloat? It does work with numbers with thousands of digits.
    use Math::BigFloat (); $x = Math::BigFloat->new("15000000") / 222; print("$x\n"); # 67567.56756756756756756756756756756756757 $x = Math::BigFloat->new("67567.57") * 222; print("$x\n"); # 15000000.54
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Reversed long division
by ikegami (Patriarch) on Jun 29, 2005 at 17:27 UTC

    I worked out a solution, but the problem is that it prepends to $out instead of appending, so converting $out to a file handle is out.

    $in = '67567'; $carry = 126; $out = sprintf('%06d', substr($in, -3, 3, '') * 222 + $carry); while (length($in)) { substr($out, 0, 3, sprintf('%04d', substr($out, 0, 3) + substr($in, -1, 1, '') * 222 )); } $out =~ s/^0+//; print($out, "\n");

    You'll need to put some work into reversing it. Show some effort.

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Reversed long division
by tlm (Prior) on Jun 29, 2005 at 22:15 UTC

    Interesting problem. Here's a straightforward extension of ikegami's solution to work off a file. I post it more for the record than for the OP (who I doubt will find it useful, since using it will require a modicum of honest work ;-) ):

    mult takes three arguments: a file, a divisor, and a remainder. The file must contain the quotient (base 10) without any leading 0s or any whitespace anywhere in the file digits of the quotient in reverse order. mult computes the dividend (i.e. the sum of the remainder plus the product of the quotient and the divisor) and puts it, again, with digits in reverse order, in a file whose name is obtained from the name of the input file. The input is read into memory in chunks of size 8192 and processed (though the size of these chunks is easily configurable, by setting the $STRIDE variable).

    It processed a file containing a quotient of 1,000,000,000 digits in 35 minutes. Minimally tested, though.

    And to the OP, you are welcome to tweak this further to suit your needs.

    Update: Fixed the script so that now the digits in the input and output files are in the correct (not reverse) order. Also fixed some lurking bugs relating to mixing sysread calls with seek and tell calls.

    the lowliest monk

Re: Reversed long division
by thundergnat (Deacon) on Jun 29, 2005 at 18:56 UTC

    Hmmm, an interesting diversion...

    Here's my version of both longdiv and longmul with a little test script. Dividing a random 1000 digit number by 222 and then multiplying the result by 222 is accurate to at least 12 decimal places for me. (The inaccuracy is due to the limit of accuracy for the fractional portion of the number while dividing.) And it takes much longer to print the number to the screen than it does to calculate it.

    #!/usr/bin/perl use warnings; use strict; my $number; for(0..999) { $number .= int(rand 9); } print "$number\n\n"; print longdiv($number, 222) . "\n\n"; print longmul(longdiv($number, 222), 222) . "\n"; sub longdiv { my @digits = split //, shift; my $demoninator = shift; my $carry = 0; my $out = ''; my $numerator; while (@digits) { $numerator = shift @digits; $numerator += $carry * 10; $carry = $numerator % $demoninator; $out .= int($numerator / $demoninator) if @digits; } $out =~ s/^0+//; $out .= ($numerator / $demoninator); return $out; } sub longmul { my @digits = reverse split //, shift; my $multiplier = shift; my $out = ''; my ($digit, $progress); while (@digits) { $digit = shift @digits; if ($digit eq '.') { $out = '.' . $out; next; } $progress += $digit * $multiplier; $out = ($progress % 10) . $out; $progress = int($progress / 10); } $out = $progress . $out; return $out; }
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Reversed long division
by tlm (Prior) on Jun 29, 2005 at 16:48 UTC
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Reversed long division
by BrowserUk (Patriarch) on Jun 29, 2005 at 19:40 UTC

    Would this help?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
Re: Reversed long division
by zentara (Cardinal) on Jun 30, 2005 at 11:52 UTC
    Have you thought of running "bc" through backticks,expect or IPC? It will handle thousands of digits, and is fast.

    I'm not really a human, but I play one on earth. flash japh

      I am not so sure, because bc internally calculates in decimal (at least the GNU version does), so you'd have to convert the very long base 222 number to base 10, and the result back, which could take much time.

      Of course, there are other bignum libraries apart from bc, but all of those I know calculates in a fixed base, which is either a power of 2, or a power of 10. It's unlikely that you'll find a pre-written bignum library that uses base 222. (However, you could still learn much from their code.)