Perl Function – Infinity Multiplication – Beyond Memory

Advertisement
directory-software-online-bussiness-script

# "Copyright Notice", please do not remove.
# Written by Kevin Ng
# The full tutorial on this subject can be found @ http://kevinhng86.iblog.website or http://programming.world.edu.
# Release date to http://programming.world.edu will lag at least one week after release on http://kevinhng86.iblog.website 
# This source code file is a part of Kevin Ng's Z library.
# This source code is licenses under CCDL-1.0  A copy of CDDL1.0 can be found at https://opensource.org/licenses/CDDL-1.0
# End "Copyright Notice" 

# Notice: This is the protype version of infiXF.   
#         This version does support decimal calculation.
#         InfiXF is for sciencetific use.

# Limitation: Although had not calculate the number to be that large yet, in theory InfiXF can calculate two strings of digits that are 1/5 the size of the hard drive.
#             If the hard drive is 1 Terabyte, This program can calculate the multiplication procedure for two strings of digit with the combine storage of 200 GB.
#             That is about 100 billion digits in length for each string of digits.
#             This version does not come with the renderer.
#             After a huge calculation, and if the answer file is larger than 1GB another program woulb be requires to render the answer on screen.
#             InfiXF does not consume memory and have very little memory foot print.
#             InfiXF however does requires the storage space as large as the two files that contained the strings of digits to produce the answer string.
#             100 * 100 GB would requires 400 GB for storing the temporary files and 200 Gb for the result file. 

use strict;
use warnings;

package libZ;
    sub infiXF{
        my $afile = "a.infiX"; 
        my $bfile = "b.infiX";
        my $atmp = $afile . ".tmp";
        my $btmp = $bfile . ".tmp";
        my $outputfile = "result.infiX";
        my $outputtmp = $outputfile . ".tmp";
        my $dAfterDecA = -1;
        my $dAfterDecB = -1;
        my $dAfterDecT = 0;
        
        my $perReadTmp = 50; # This is changeable, how many character to read at once during temporary file reading.
        my $asize = -s $afile; 
        my $bsize = -s $bfile;
        my $tmpDReadA = 0;
        my $tmpDReadB = 0;

        my $readA;
        my $readB;

        open (FileA,"<", $afile) or die;
            sysseek (FileA, 0 ,0);
            sysread(FileA, $readA, 1);
            my $isaNeg = $readA eq "-";
            
            open (TmpA, ">", $atmp) or die;
                sysseek (FileA, 0 ,0);
                read(FileA, $readA, $perReadTmp);
                $readA =~  s/^[+-]+//g;
                chomp $readA;                        
                $dAfterDecA = index($readA, ".");
                $dAfterDecA = $dAfterDecA > -1? length($readA) - $dAfterDecA - 1 : $dAfterDecA; 
                if ($dAfterDecA > -1){
                    $readA =~ s/[.]//g;
                }                        
                print TmpA $readA;
                
                while (read(FileA, $readA, $perReadTmp)){
                    chomp $readA;                        
                    if ($dAfterDecA < 0){
                        $dAfterDecA = index($readA, ".");
                        $dAfterDecA = $dAfterDecA > -1? length($readA) - $dAfterDecA - 1 : $dAfterDecA; 
                        $readA =~ s/[.]//g;
                    } else {
                        $tmpDReadA = length($readA);
                        $dAfterDecA = $dAfterDecA + $tmpDReadA;    
                    }
                    print TmpA $readA;
                }    
            close (TmpA);
        close (FileA);

        open (FileB,"<", $bfile) or die;
            sysseek (FileB, 0 ,0);
            sysread(FileB, $readB, 1);
            my $isbNeg = $readB eq "-";

            open (TmpB, ">", $btmp) or die;
                sysseek (FileB, 0 ,0);
                read(FileB, $readB, $perReadTmp);
                $readB =~  s/^[+-]+//g;
                chomp $readB;                        
                $dAfterDecB = index($readB, ".");
                $dAfterDecB = $dAfterDecB > -1? length($readB) - $dAfterDecB - 1 : $dAfterDecB; 
                if ($dAfterDecB > -1){
                    $readB =~ s/[.]//g;
                }            
                            
                print TmpB $readB;
                while (read(FileB, $readB, $perReadTmp)){
                    chomp $readB;
                    if ($dAfterDecB < 0){
                        $dAfterDecB = index($readB, ".");
                        $dAfterDecB = $dAfterDecB > -1? length($readB) - $dAfterDecB - 1 : $dAfterDecB; 
                        $readB =~ s/[.]//g;
                    } else {
                        $tmpDReadB = length($readB);
                        $dAfterDecB = $dAfterDecB + $tmpDReadB;    
                    }
                    print TmpB $readB;
                }    
            close (TmpB);
        close (FileB);

        $dAfterDecA = $dAfterDecA < 0? 0 : $dAfterDecA;
        $dAfterDecB = $dAfterDecB < 0? 0 : $dAfterDecB;
        $dAfterDecT = $dAfterDecA + $dAfterDecB;
        my $atmpsize = -s $atmp;
        my $btmpsize = -s $btmp;
        my $digit = 9; # This is the amount of digits to calculate per cycle.
        my $digitneg = $digit * -1;
        my $pad0 = "";
        while (length($pad0) < ($digit - 1)){
            $pad0 = "0" . $pad0;
        }

        open (OutputTmp,">", $outputtmp) or die;
            my $idn = 0;
            my $premakeoutlen = ($atmpsize + $btmpsize) + ($digit * 2) ;
            while ($idn < $premakeoutlen ){
                print OutputTmp ($pad0 || "0");
                $idn = $idn + (($digit - 1) || 1 );
            }
            
        close (OutputTmp);

        my $a = 0;
        my $b = 0;
        my $o = 0;
        my $posrB = 1;
        my $posrO = 1;
        my $loopidxB = 1;

        my $temp = 0;
        my $tempadd = 0;
        my $blen = $btmpsize;
        my $olen = -s $outputtmp;

        open(TmpB, "<", $btmp) or die;
            while ( $posrB != 0 ){
                my $alen = $atmpsize;
                my $loopidxA = 1;
                my $posrA = 1;
                my $leftover = 0;
                my $remainder = 0;
                $posrB = $blen - ($loopidxB * $digit);
                sysseek(TmpB, ($posrB > 0 ? $posrB : 0) ,0);    
                sysread(TmpB, $b, ($posrB > 0 ? $digit : $digit + $posrB));
    
                open(TmpA, "<", $atmp) or die;
                    open(OutputTmp, "+<", $outputtmp) or die;
                        while ( $posrA != 0 ){
                            $posrO = $olen - (($loopidxA + $loopidxB - 1) * $digit);
                            $posrA = $alen - ($loopidxA * $digit);
                            sysseek(TmpA, ($posrA > 0 ? $posrA : 0),0);    
                            sysread(TmpA, $a, ($posrA > 0? $digit : $digit + $posrA));
            
                            $temp = int($b) * int($a) + $remainder + $leftover;
                            $leftover =    int(substr($temp,0, $digitneg) || 0 );
                            sysseek(OutputTmp, $posrO, 0);
                            sysread(OutputTmp, $o, $digit);
                            $tempadd = int(substr($temp,$digitneg)) + int($o || 0) ;  
                            $remainder = int(substr($tempadd,0, $digitneg) || 0 );
                            sysseek(OutputTmp, $posrO, 0);
                            syswrite(OutputTmp, (substr($pad0 . substr($tempadd,$digitneg), $digitneg)));                
                            $posrA = $posrA > 0 ? $posrA : 0;
                            $loopidxA = $loopidxA + 1;    
                        }
                        if ( $remainder + $leftover > 0 ){
                            $posrO = $posrO - $digit;
                            sysseek(OutputTmp, $posrO, 0);
                            syswrite(OutputTmp,substr($pad0 . ($remainder + $leftover), $digitneg));
                        }
                    close(OutputTmp);
                close(TmpA);
        
                $posrB = $posrB > 0 ? $posrB : 0;
                $loopidxB = $loopidxB + 1;
            }
        close(TmpB);


        my $dBeforeDec = (-s $outputtmp) - $dAfterDecT; 
        my $lead0End = 0;
        my $posw = 0;
        my $readOutputTmp = "";
        my $checker = "";
        my $truncatediff = 0;
        my $truncatelen = 0;
        my $truncatestr = "";
 

        open(OutputTmp, "<", $outputtmp);
            open (Output, "+>", $outputfile);
                if ( $isaNeg ne $isbNeg ){
                    print Output "-";
                }
    
                while ($posw < $dBeforeDec ){
                    sysseek(OutputTmp, $posw, 0);
                    sysread(OutputTmp, $readOutputTmp,(($posw + $perReadTmp < $dBeforeDec)? $perReadTmp : $dBeforeDec - $posw));
                    if ( $lead0End == 0 ){
                        $readOutputTmp =~ s/^0+//g;
                        $lead0End = length($readOutputTmp) > 0? 1 : 0; 
                    }
        
                    print Output $readOutputTmp;
                    $posw = ($posw + $perReadTmp < $dBeforeDec + 1)? $posw + $perReadTmp : $dBeforeDec  ;
                }
            close(Output);
    
    
            my $outputlen = -s $outputfile;
            open (Output, "+>>", $outputfile);    
                if ($outputlen < 2){
                    sysseek(Output, 0 , 0);
                    sysread(Output, $checker, 2);
                    if ( length($checker) < 1 || $checker eq "-"){
                        print Output "0";
                    }                
                } 
    
                if ( $dAfterDecT > 0 ){
                    print Output ".";
                }
    
                while ( $posw < $olen ){
                    sysseek(OutputTmp, $posw, 0);
                    sysread(OutputTmp, $readOutputTmp, $perReadTmp);
                    $truncatestr = $readOutputTmp;
                    $truncatestr =~ s/0+$//g ;
                    $truncatediff = length($readOutputTmp) - length($truncatestr);
                    $truncatelen =  $truncatediff == length($readOutputTmp)? $truncatediff + $truncatelen : $truncatediff;        
                    print Output $readOutputTmp;                
                    $posw = $posw + $perReadTmp;
                }
            close(Output);
        close(OutputTmp);  
    
        $outputlen = -s $outputfile;
    
        open (Output, ">>", $outputfile);    
            truncate(Output,  ($outputlen - $truncatelen));
        close(Output);

        $outputlen = -s $outputfile;
        open (Output, "+>>", $outputfile);    
            sysseek(Output, $outputlen - 1, 0);
            sysread(Output, $readOutputTmp, 1 );
            if ( $readOutputTmp eq "."){
                truncate(Output, $outputlen - 1);
            }
        close(Output);
    }

    sub fileRand{
        my $randDigitA = int(rand(350)) + 40;
        my $randDigitB = int(rand(350)) + 40;

        my $randDecPOSA = int(rand($randDigitA - 20)) + 10; 
        my $randDecPOSB = int(rand($randDigitB - 20)) + 10;


        open(RANDOMA, ">"."a.infiX") or die "Could not open file $!";
            for (our $id = 0; $id < $randDigitA; $id++){
                print RANDOMA int(rand(9));
                if ($id == $randDecPOSA){
                    print RANDOMA ".";    
                }    
               }
        close(RANDOMA);


        open(RANDOMB, ">"."b.infiX") or die "Could not open file $!";
            for (our $id = 0; $id < $randDigitB; $id++){
                print RANDOMB int(rand(9));
                if ($id == $randDecPOSB){
                    print RANDOMB ".";    
                }    
               }
        close(RANDOMB);
    }

package main;

libZ::fileRand();
libZ::infiXF();
print "Check in the current directory.\n a.infiX is the file that hold the first set of digits.\n b.infiX is the second file that hold the digits.\n result.infiX is the result of the multiplication procedure.\n";
print "The name of the temporary file for them are a.infiX.tmp, b.infiX.tmp, result.infiX.tmp.\n";
print "Temporary files can be delete after execution, but are currently kept for debuging purposes.";
Advertisement


Random Article You May Like