Ruby Function – Infinity Multiplication – Beyond Memory

Advertisement

# "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 400 Gb for the result file.
class LibZ
    def self.infiXF()
        _afile = "a.infiX"
        _bfile = "b.infiX"
        _atmp = _afile + ".tmp"
        _btmp = _bfile + ".tmp"
        _outputfile = "result.infiX"
        _outputtmp = _outputfile + ".tmp"
        _dAfterDecA = -1
        _dAfterDecB = -1
        _dAfterDecT = 0
        _perReadTmp = 50 # This is changeable, how many character to read at once during temporary file reading.
        _tmpDReadA = 0
        _tmpDReadB = 0
        _readA = ""
        _readB = ""

        _FileA = open(_afile, "r")
            _readA = _FileA.read(1)
            _isaNeg = _readA == "-"
            _TmpA = open(_atmp, "w")
                _FileA.seek(0, 0)
                _readA = _FileA.read(_perReadTmp)
                _readA = _readA.gsub(/^[+-]/,"")
                _readA = _readA.chomp

                _dAfterDecA = _readA.index(".") || -1
                _dAfterDecA = (_dAfterDecA > -1)? _readA.length - 1 - _dAfterDecA : _dAfterDecA
                if (_dAfterDecA > -1)
                    _readA = _readA.gsub(/[.]/, "")
                end    
                _TmpA << _readA

                while !(_FileA.eof)
                    _readA = _FileA.read(_perReadTmp)
                    _readA = _readA.chomp
                    if (_dAfterDecA < 0)
                        _dAfterDecA = _readA.index(".") || -1
                        _dAfterDecA = (_dAfterDecA > -1)? _readA.length - 1 - _dAfterDecA : -1
                        if (_dAfterDecA > -1)
                            _readA = _readA.gsub(/[.]/, "")
                        end
                    else
                        _tmpDReadA = _readA.length
                        _dAfterDecA = _dAfterDecA + _tmpDReadA
                    end
                    _TmpA << _readA
                end
            _TmpA.close()
        _FileA.close()
        
        _FileB = open(_bfile, "r")
            _readB = _FileB.read(1)
            _isbNeg = _readB == "-"
            _TmpB = open(_btmp, "w")
                _FileB.seek(0, 0)
                _readB = _FileB.read(_perReadTmp)
                _readB = _readB.gsub(/^[+-]/,"")
                _readB = _readB.chomp

                _dAfterDecB = _readB.index(".") || -1
                _dAfterDecB = (_dAfterDecB > -1)? _readB.length - 1 - _dAfterDecB : _dAfterDecB
                if (_dAfterDecB > -1)
                    _readB = _readB.gsub(/[.]/, "")
                end    
                _TmpB << _readB

                while !(_FileB.eof)
                    _readB = _FileB.read(_perReadTmp)
                    _readB = _readB.chomp
                    if (_dAfterDecB < 0)
                        _dAfterDecB = _readB.index(".") || -1
                        _dAfterDecB = (_dAfterDecB > -1)? _readB.length - 1 - _dAfterDecB : -1
                        if (_dAfterDecB > -1)
                            _readB = _readB.gsub(/[.]/, "")
                        end
                    else
                        _tmpDReadB = _readB.length
                        _dAfterDecB = _dAfterDecB + _tmpDReadB
                    end
                    _TmpB << _readB
                end
            _TmpB.close()
        _FileB.close()
        
        _dAfterDecA = (_dAfterDecA < 0)? 0 : _dAfterDecA
        _dAfterDecB = (_dAfterDecB < 0)? 0 : _dAfterDecB
        _dAfterDecT = _dAfterDecA + _dAfterDecB
        _atmpsize = File.size(_atmp)
        _btmpsize = File.size(_btmp)
        _digit = 9; # This is the amount of digits to calculate per cycle.
        _digitneg = _digit * -1
        _pad0 = ""

        while (_pad0.length < (_digit - 1))
            _pad0 = "0" + _pad0
        end
        _OutputTmp = open(_outputtmp, "w")
            _idn = 0
            _premakeoutlen = (_atmpsize + _btmpsize) + (_digit * 2)
            while (_idn < _premakeoutlen)
                _OutputTmp << ((_pad0.length > 0)? _pad0 : "0")
                _idn = _idn + ((_digit - 1 == 0)? 1 : _digit - 1)
            end
        _OutputTmp.close()

        _a = 0
        _b = 0
        _o = 0
        _posrB = 1
        _posrO = 1
        _loopidxB = 1
        _temp = 0
        _tempadd = 0
        _blen = _btmpsize
        _olen = File.size(_outputtmp)

        _TmpB = open(_btmp, "r")
            while (_posrB != 0)
                _alen = _atmpsize
                _posrA = 1
                _leftover = 0
                _remainder = 0
                _loopidxA = 1
                _posrB = _blen - (_loopidxB * _digit)

                _TmpB.seek((_posrB > 0? _posrB : 0), 0)
                _b = _TmpB.read(((_posrB > 0)? _digit : _digit + _posrB))
                _TmpA = open(_atmp, "r")
                    _OutputTmp = open(_outputtmp, "r+")
                        while (_posrA != 0)
                            _posrO = _olen - ((_loopidxA + _loopidxB - 1) * _digit)
                            _posrA = _alen - (_loopidxA * _digit)

                            _TmpA.seek((_posrA > 0? _posrA : 0), 0)
                            _a = _TmpA.read(((_posrA > 0)? _digit : _digit + _posrA))

                            _temp = (_b.to_i * _a.to_i + _remainder + _leftover).to_s
                            _leftover = _temp[0..._digitneg].to_i
                
                            _OutputTmp.seek(_posrO, 0)
                            _o = _OutputTmp.read(_digit)

                            _tempadd = ((_temp[_digitneg..-1] || _temp[0..-1]).to_i + _o.to_i).to_s
                            _remainder = _tempadd[0..._digitneg].to_i
                            _OutputTmp.seek(_posrO, 0)
                            _OutputTmp << (_pad0 + (_tempadd[_digitneg..-1] || _tempadd[0..-1]))[_digitneg..-1]

                            _posrA = _posrA > 0? _posrA : 0
                            _loopidxA = _loopidxA + 1
                        end
                        if (_remainder + _leftover > 0)
                            _posrO = _posrO - _digit
                            _OutputTmp.seek(_posrO, 0)
                            _OutputTmp << (_pad0 + (_leftover + _remainder).to_s)[_digitneg..-1]
                        end
                    _OutputTmp.close()
                _TmpA.close()
                _posrB = _posrB > 0? _posrB : 0
                _loopidxB = _loopidxB + 1
            end
        _TmpB.close()

        _dBeforeDec = _olen - _dAfterDecT
        _lead0End = 0
        _posw = 0
        _readOutputTmp = ""
        _checker = ""
        _truncatediff = 0
        _truncatelen = 0
        _truncatestr = ""

        _OutputTmp = open(_outputtmp, "r")
            _Output = open(_outputfile, "w")
                if (_isaNeg != _isbNeg)
                    _Output << "-"
                end
                while (_posw < _dBeforeDec)
                    _OutputTmp.seek(_posw, 0)
                    _readOutputTmp = _OutputTmp.read(((_posw + _perReadTmp < _dBeforeDec)? _perReadTmp : _dBeforeDec - _posw))
                    if (_lead0End == 0)
                        _readOutputTmp = _readOutputTmp.gsub(/^0+/, "")
                        _lead0End = _readOutputTmp.length > 0? 1 : 0
                    end
                    _Output << _readOutputTmp
                    _posw = (_posw + _perReadTmp < _dBeforeDec)? _posw + _perReadTmp : _dBeforeDec
                end
            _Output.close()

            _outputlen = File.size(_outputfile)
            _Output = open(_outputfile, "a+")
                if (_outputlen < 2)
                    _Output.seek(0,0)
                    _checker = _Output.read(1) || ""
                    if (_checker.length < 1 || _checker == "-")
                        _Output << "0"
                    end
                end
                _Output.seek(_outputlen,0)
                if (_dAfterDecT > 0)
                    _Output << "."
                end
            
                while (_posw < _olen)
                    _OutputTmp.seek(_posw, 0)
                    _readOutputTmp = _OutputTmp.read(_perReadTmp)
                    _truncatestr = _readOutputTmp
                    _truncatestr = _readOutputTmp.gsub(/0+$/,"")
                    _truncatediff = _readOutputTmp.length - _truncatestr.length
                    _truncatelen = (_truncatediff == _readOutputTmp.length)? _truncatediff + _truncatelen : _truncatediff
                    _Output  << _readOutputTmp
                    _posw = _posw + _perReadTmp
                end
            _Output.close()
        _OutputTmp.close()

        _outputlen = File.size(_outputfile)

        _Output = open(_outputfile, "r+")
            _Output.truncate(_outputlen - _truncatelen)
        _Output.close()

        _outputlen = File.size(_outputfile)

        _Output = open(_outputfile, "a+")
            _Output.seek(_outputlen - 1, 0)
            _readOutputTmp = _Output.read(1)
            if (_readOutputTmp == ".")
                _Output.truncate(_outputlen - 1)
            end
        _Output.close()
    end    
    
    def self.randFile()
        _randDigitA = rand(0...350) + 40
        _randDigitB = rand(0...350) + 40

        _randDecPOSA = rand(0...(_randDigitA - 20)) + 20
        _randDecPOSB = rand(0...(_randDigitB - 20)) + 20

        open("a.infiX", "w") do |_RANDOMA|
            _RANDOMA << "-"
            for _idn in 0.._randDigitA
                _RANDOMA << rand(0...10)
                if (_idn == _randDecPOSA)
                    _RANDOMA << "."
                end
            end
        end
        open("b.infiX", "w") do |_RANDOMB|
            for _idn in 0.._randDigitB
                _RANDOMB << rand(0...10)
                if (_idn == _randDecPOSB)
                    _RANDOMB << "."
                end
            end
        end
    end
end

LibZ.randFile()
LibZ.infiXF()
puts "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."
puts "The name of the temporary file for them are a.infiX.tmp, b.infiX.tmp, result.infiX.tmp."
puts "Temporary files can be delete after execution, but are currently kept for debuging purposes."
Advertisement


Random Article You May Like