In the previous chapter of “Infinity Multiplication”, we had discussed and demonstrated a productional version of InfiX that is capable of multiplying two large strings of digits together. However, the strings of digits were limited by memory. In a normal usage environment, the majority of us would not go beyond multiplying numbers that are beyond what memory could store. Take into account that it only require around 500 Mb of memory to multiply two strings that contained 100 millions digits per string.

That is for normal usage, but what if we want to multiply numbers that contained more than one billion digits together? What if we want to multiply the largest number the computer can ever multiply. To be able to multiply numbers that so large and is beyond the capability of what memory can handle, we first must find a solution to our formula so that our formula does not bound to memory limitation. This is chapter four of the “Infinity Multiplication” subject with the name “Beyond Memory”. This is the Groovy’s version.

Take note that the source code at the end of this article is a prototype. The program itself is capable of producing results for multiplying two very large numbers together and the program does not require memory to operate. Nevertheless, the program does require disk space for storing the temporary files and the final result value. Although this version of InfiXF is a prototype, it is very powerful. I actually tested calculated a number with 25000 digits lengthwise multiply by another number that is 25000 digits lengthwise and verify the answer with the InfiX and I also verify the answer with other big numbers calculator. The next test for the prototype which I have not done as of right now is to calculate a billion digits multiply by another billion digits. Nevertheless, InfiXF prototype did go through some extensive testing for smaller numbers multiplication between the length of forty and 390 digits. Nevertheless, in theory, infiXF can actually calculate digits that can be 1/5 the size of the available space on the hard drive.

Previous Chapter: Optimised The Code | Next Chapter: To Be Release |

#### Beyond Memory – Reaching For Billion of Digits

When we are multiplying numbers that are beyond what memory can store, the first challenge we would have is how to store the numbers. Since the numbers are now larger than the capability of what memory can store, we can only store each number in a file. The second challenge we would face is that we can’t load the complete file into memory since they are larger than memory. In my formula, since we can’t load the entire file into memory we will read the numbers that are stored in multiple files piece by piece and process the multiplication formula for the numbers also piece by piece. In context, this formula would be the same formula as the previous chapter of “Infinity Multiplication”. Instead of working with the numbers that were stored in string format, we are now working with numbers that are stored in a file format.

When storing a number that can contain million of digits long in a file, the first issue we would have is the format of how the digits are stored. In my formula, the digits would be stored as a single straight line in ASCII code without any formatting characters. This formula also built for calculating the decimal placement for the numbers. A negative or positive sign can be appended to the beginning of the file.

When we are working in a file base system, we can’t simply trim off the positive or negative sign in the beginning of a file. Nor can we remove the binary block that held the decimal. Since we are reading the files piece by piece, if we keep the decimal and the negative or positive sign intact we would have to evaluate each block of digits that we are grabbing from the files. For this example let imagine that we are grabbing nine digits at a time from a file that name A. If we were to grab nine digits from the file and the block does contain the decimal, we would have to remove the decimal and get an extra digit to have consistency with the number of digits we are grabbing for each calculation cycle in our formula. Besides that, we would also have to keep track of how many digits that are behind the decimal for our number in the event if there was a decimal in our number. Thus in my formula, before processing the files that contained the numbers we wanted to multiply, we first transfer the digits contents of the files into temporary files. In the temporary files, we would only store the digits without the decimal nor the plus or negative sign if there were any.

When we are reading the digits, we use the RandomAccessFile class. We would read A file by bytes block. Therefore we would create a byte array as a buffer reader. After reading A file and we have filled the byte array with digits from A file, we then have to convert the bytes in the byte array to string format for processing. We also have to check if the byte array length is longer than the current position of the file pointer to the end of the file. We do not want to read beyond the end of the file. When we are reading beyond the end of the file, the empty arrays within the byte array will not convert properly to string format. When writing back this information in a file, we might add extra bytes that are not intended.

The first step for the procedure of this step would be to read the first character at the beginning of our A file to check whether if that position does indeed contain a negative or a plus sign. If the position does contain a negative or a plus sign our isaNeg variable would be set to true or a value of “1”. Since we read the first position already and the file is still open, our pointer would be moved to the second position in the file. If the file did contain a positive or a negative sign it would be ok to read the second position and start grabbing digits to transfer to our temporary file. Nevertheless, if the file did not contain a positive or a negative sign we would be missing out on a digit, thus we would have to reset the pointer back to the zero position of the file.

For the purpose of this prototype, I set the amount of position we are reading from A file was set at 50 in a variable with the named perReadTmp. This variable can be changed to read more or less. You can probably read more than 10,000 positions at a time. For the first time we read the file to get the digits out, we would have to remove any positive and plus sign from the string. We do not need to trim the string off any formatting character if our file is only stored by our program. Nevertheless, when a file is edited with a text editor, a text editor would usually add a formatting character to the end of the line. Thus I would trim the block of digits we read in the event where it is at the end of the line and there is a formatting character.

When we grab a block of digits from the A file, we would check to see if there is a decimal and the position of the decimal. If it is the block we found the decimal in, we would subtract the length of the block we read minus the decimal position then minus one to know how many digits are behind the decimal. We have to minus one because positioning in Groovy starts at zero, so the length is always larger than the last position by one. If we has already found the decimal and there are more block of digits to read, the length of each additional block of digits would be added to the total of the amount of digit that we would require to have after the decimal in our result value. When we found the decimal we would also remove the decimal from the variable that currently held the value that we just read from file A.

After removing the negative sign or positive sign and or the decimal if there was in our block of digits, we would transfer only the digits to a temporary file. The name of the temporary file for our A file is defined by the atmp variable. This code block below demonstrates the above procedures. What procedures we were applying to file A will also apply to file B.

try{ RandomAccessFile FileA = new RandomAccessFile(afile, "r") FileWriter TmpA = new FileWriter(atmp) bufferR = new byte[(FileA.length() - 0 > perReadTmp? perReadTmp : (int)(FileA.length() - 0))] FileA.read(bufferR) readA = new String(bufferR) isaNeg = readA.charAt(0) == '-' readA = readA.replaceAll("^[-+]+", "") readA = readA.trim() dAfterDecA = readA.indexOf('.') dAfterDecA = dAfterDecA > -1? readA.length() - 1 - dAfterDecA : dAfterDecA if (dAfterDecA > -1){ readA = readA.replaceAll("[.]", "") } TmpA.write(readA); while (FileA.getFilePointer() < FileA.length() ){ bufferR = new byte[(FileA.length() - FileA.getFilePointer() > perReadTmp? perReadTmp : (int)(FileA.length() - FileA.getFilePointer()))] FileA.read(bufferR) readA = new String(bufferR) readA = readA.trim() if (dAfterDecA < 0){ dAfterDecA = readA.indexOf(".") dAfterDecA = dAfterDecA > -1? readA.length() - 1 - dAfterDecA : -1 if (dAfterDecA > -1){ readA = readA.replaceAll("[.]", "") } } else { tmpDReadA = readA.length() dAfterDecA = dAfterDecA + tmpDReadA } TmpA.write(readA) } TmpA.close() FileA.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to process " + afile + "file" , e) }

The first challenge we face for applying the multiplication formula of each block of digits in number A to each block of digits in number B in a text file format would be when we are writing the result to a file. When information is appended to a file, we can only append new information to the end of the file and not the beginning of the file. However, for multiplication, we are reading the string on the right side first. When translated to how we read from a file, we are also reading from the back of the file and calculating results for digits block from the end of the file to the beginning of the file. Therefore when calculating and producing a result value we would also produce the result value from the right to the left, which in term also mean that we would need to append new result value before the result value that already contained in the answer file.

For a multiplication procedure, the maximum digits in a result value can only be the total of length of number A plus the total length of number B. By knowing this we can pre-create an answer file full of zeroes that is as large as the total amount of digits in number A plus the total amount of digits in number B. I added some extra digits bases on the amount of digit we are calculating per cycle for the event where there are variations in the last block of digits. As similar to the previous chapter the pad0 variable would be required to make up for the missing length of our digits block for each calculation. The below code will create a temporary answer file full of zeroes.

while (pad0.length() < (digit - 1)){ pad0 = "0".concat(pad0) } String pad0tmp = pad0.length() < 1? "0" : pad0 int digittmp = digit < 1? 1 : digit - 1 try{ FileWriter OutputTmp = new FileWriter(outputtmp); long idn = 0 while (idn < premakeoutlen){ OutputTmp.write(pad0tmp) idn = idn + digittmp } OutputTmp.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to create " + outputtmp + " file" , e) }

Similar to the previous chapter of InfiX, we would first read from file B. We would read from the end of file B until we read the zero position in B file, which would be the beginning of the file. Since we are reading the file backward, we would need to keep track of our index count. We could use a wrapper library to also achieve reading the file backward. Nevertheless, I chose to not incorporate any additional library into the infiXF program. To get the position of where we are in the file, we first need to know many times the loop has executed. I started the loopidxB with the value one. This is because when we are getting the position to read from, we need to subtract B file length to the result value of the loop count times the amount of digit we are multiplying at a time. For this program, we are calculating nine digits at a time. Our first position we are reading from is not the end position of the file, but nine digits away from the end of the file. We would read from that position to the end of the file.

For the last block of digits that is at the beginning of the file, the number of digits can vary and may not match the total amount of digits we are working with at one time. Thus if our read position turned into a negative value, we would convert the value to zero. Since zero is when the loop will end, the loop will also exit after the zero block is calculated. To get the amount of digit out of B file when we are reading B file, we use the digit variable.

However, when our read position turned into a negative value we would be reset at zero. Which mean we would be grabbing more digits than needed. Therefore if our position turned into a negative we would have to add the negative value to the “digit” variable’s value. For example, if we were reading at position five, our read position would be a negative four. We have to change the negative value to zero so that our read does not go out of bound. Since we changed our read position to the zero position, if we were to grab nine digits from that position we would be grabbing four extra digits that we already grab from the previous loop. Nevertheless, if we take nine plus negative four, we would have a five value. That is the amount of digit we would need to grab. The code block below demonstrates the above procedures for Groovy.

RandomAccessFile TmpB = new RandomAccessFile(btmp, "r") while (posrB != 0){ posrB = blen - (loopidxB * digit) bufferC = new byte[(posrB > 0? digit : digit + (int)(posrB))] TmpB.seek(posrB > 0? posrB : 0) TmpB.read(bufferC) b = Long.parseLong(new String(bufferC)) // A loop go here posrB = posrB > 0? posrB : 0 loopidxB = loopidxB + 1 } TmpB.close();

Before we are moving into the procedure inside the loop for reading A file, these are the variables that need to be declared inside the loop that read B file but outside of the loop that read A file. Remainder and leftover have to be reset. Position read for A file and loop index count for A file would have to reset after each time we loop through the digits in A file.

alen = atmpsize posrA = 1 leftover = 0 remainder = 0 loopidxA = 1

The formula for getting the leftover value and the remainder value would still be the same as the previous chapters. The only difference this time is when we are adding values to our temporary answer file. To get the current value that already held inside our temporary answer file, we would apply the same method of grabbing the digits from B file. When we are writing the new result value to the temporary answer file, we would write the value to the exact spot where we just grabbed the value from the temporary answer file. Therefore our write and read position for our temporary answer file is the same.

To calculate the current position of where we are working within the temporary file, we add the total amount of how many times loop A and B have executed and minus the value to one. We have to minus one because both our loop A and B started at one, and we do not move over one until our loop A finished executing the first loop. The value of the previous step would then be multiply by the amount of digit the program was set to work with. We would then subtract the length of the temporary answer file to this value to get the position we are working with. The code block below demonstrates the above procedures.

while (posrA != 0){ posrO = olen - ((loopidxA + loopidxB - 1) * digit) posrA = alen - (loopidxA * digit) bufferC = new byte[(posrA > 0? digit : digit + (int)(posrA))] TmpA.seek((posrA > 0? posrA : 0)) TmpA.read(bufferC) a = Long.parseLong(new String(bufferC)) temp = (b * a + remainder + leftover) tempstr = String.valueOf(temp) leftover = tempstr.length() > digit? Long.parseLong(tempstr.substring(0,tempstr.length() - digit)) : 0 tempstr = pad0.concat(tempstr) bufferC = new byte[digit] OutputTmp.seek(posrO) OutputTmp.read(bufferC) o = Long.parseLong(new String(bufferC)) tempadd = Long.parseLong(tempstr.substring(tempstr.length() - digit )) + o tempaddstr = String.valueOf(tempadd) remainder = tempaddstr.length() > digit? Long.parseLong(tempaddstr.substring(0,tempaddstr.length() - digit)) : 0 tempaddstr = pad0.concat(tempaddstr) OutputTmp.seek(posrO) OutputTmp.writeBytes(tempaddstr.substring(tempaddstr.length() - digit)) posrA = posrA > 0? posrA : 0 loopidxA = loopidxA + 1 }

After looping through the digits in A file, if there are any leftover or remainder we would add this value to the next position in our temporary answer file. Because the final leftover and remainder would always be before the current values that are being held in the temporary answer file. We do not need to get a value from the temporary answer file.

if (remainder + leftover > 0){ posrO = posrO - digit leftoverstr = pad0.concat(String.valueOf(leftover + remainder)) OutputTmp.seek(posrO) OutputTmp.writeBytes(leftoverstr.substring(leftoverstr.length() - digit)) }

After finished calculating the multiplication for all the digits in A file multiple to all the digits in B file, we would have an answer value in our temporary answer file. Nevertheless, this answer value is not formatted and does not contain a decimal or a negative sign. Thus our next challenge would be to convert the value in our temporary answer file to the true result. Because we can’t simply inject a negative sign to the front of the file or inject a decimal in the middle of the file or remove trailing and leading zeroes, we would have to create a new file and append values from our temporary answer file. This new file I would call the final answer file.

The first character we would append to the final answer file is a negative sign if file A and file B is different in negative and positive base value. Secondly, we would add all the digits that are supposed to be before the decimal to our final answer file from our temporary answer file. To get the position for the amount of digit that supposed to be before the decimal, we would subtract the temporary answer file’s length to the amount of the total digits that we require to have after the decimal. For the demonstration purpose of this article, the amount of position we are reading each time for temporary reading was set at 50 in the perReadTmp variable.

When we are reading the block of digits from the temporary answer file, we will trim off leading zeroes for the first time we read. If after trimming off all the leading zeroes and the block we just read became zero in length, we would trim off leading zeroes for the next block we read. If after trimming off leading zeroes and the block we just read had a length that is greater than zero, we do not trim any more zeroes from subsequence blocks that we read. We would read the temporary answer file until we reach the digits before decimal position. This code block below demonstrate the above procedures.

RandomAccessFile OutputTmp = new RandomAccessFile(outputtmp, "r") FileWriter Output = new FileWriter(outputfile) if (isaNeg != isbNeg){ Output.write("-") } while (posw < dBeforeDec){ bufferR = new byte[(posw + perReadTmp < dBeforeDec? perReadTmp : (int)(dBeforeDec - posw))] OutputTmp.seek(posw) OutputTmp.read(bufferR) readOutputTmp = new String(bufferR) if (lead0End == false){ readOutputTmp = readOutputTmp.replaceAll("^0+", "") lead0End = readOutputTmp.length() > 0? true : false } Output.write(readOutputTmp) posw = (posw + perReadTmp < dBeforeDec)? posw + perReadTmp : dBeforeDec } Output.close()

After adding all the digits before the decimal from our temporary answer file to the final answer file and in the event where zeroes were the only digits before the decimal and we trimmed off all the zeroes, we would have either a negative sign in the final answer file or a zero length answer file. Therefore we would have to add a zero to the final answer file for formatting before we add the decimal to the final answer file.

When we are adding the decimal to the final answer file, we would only add the decimal if the amount of digit after the decimal is more than zero. Otherwise, the decimal would always be added to the final answer file.

long outputlen = new File(outputfile).length() RandomAccessFile Output2 = new RandomAccessFile(outputfile, "rw") if (outputlen < 2){ bufferR = new byte[1] Output2.read(bufferR) checker = new String(bufferR) if (outputlen < 1 || checker.equals("-")){ Output2.seek(Output2.length()) Output2.writeBytes("0") } } if (dAfterDecT > 0){ Output2.seek(Output2.length()) Output2.writeBytes(".") }

After moving all the digits before the decimal from the temporary answer file to the final answer file. We would be moving the digits after the decimal from the temporary answer file to the final answer file. In the event where there are trailing zeroes after the decimal, we would have to remove the trailing zeroes. We can’t simply trim off the zeroes similar to when we were working with digits in string format, we can only truncate the file to the necessary length. To calculate how many zeroes are trailing, we calculate this from the first block we read.

For this example, the readOutputTmp variable is the variable where we hold the value of the current position we are reading from in the temporary answer file. We assign readOutputTmp variable’s value to our truncatestr variable, we then trim off zeroes in our truncatestr variable. We then minus the length of the readOutputTmp variable to the length of our truncatestr variable. This value is what I call the truncate different. If the truncate different value is equal to the length of the readOutputTmp str. That mean that the string only contained zeroes, therefore if there was a truncate different value from our previous read, we would add that value to the current truncate difference.

For any other circumstances, the truncate different value would be reset after each time we read. Thus we would only trim off the requires amount of zeroes in the final read. Nevertheless, if zeroes were the only digits after the decimal, they would all be truncate off from the final answer file. The truncate different value is first stored in the variable name truncatediff but would finally be stored in the variable name truncatelen. After we writing the value to our final answer file we would get the length of our file so that we can truncate the file in the event where we are removing the trailing zeroes from our final answer file.

Output2.seek(Output2.length()) while (posw < olen){ OutputTmp.seek(posw) bufferR = new byte[(olen - posw > perReadTmp? perReadTmp : (int)(olen - OutputTmp.getFilePointer()))] OutputTmp.read(bufferR) readOutputTmp = new String(bufferR) truncatestr = readOutputTmp truncatestr = readOutputTmp.replaceAll('0+$', "") truncatediff = readOutputTmp.length() - truncatestr.length() truncatelen = truncatediff == readOutputTmp.length()? truncatediff + truncatelen : truncatediff Output2.writeBytes(readOutputTmp) posw = posw + perReadTmp }

After getting the truncate length we would truncate the file by getting the current length of the final answer file minus the value that contained in the truncatelen variable. If after truncating off all the unnecessary zeroes and the last character of our final answer file is a decimal we would also truncate off the decimal. To truncate the file, we simply set the length of the file.

outputlen = Output2.length() Output2.setLength(outputlen - truncatelen) outputlen = Output2.length() Output2.seek(outputlen - 1) bufferR = new byte[1] Output2.read(bufferR) readOutputTmp = new String(bufferR) if (readOutputTmp.equals(".")){ Output2.setLength(outputlen - 1) }

The program below is the full working program. For demonstrating purpose, I also included a random generator that will generate two files. The first file is a.infiX and the second file is b.infiX. There will be a random amount of digit in these two files. Each file will contain a minimum of 40 digits to a maximum of 390 digits. The decimal will be injected into a random position for both files. The program will then calculate the multiplication result from the digits within the two files mentioned. The program will first produce a.infiX.tmp and b.infiX.tmp as temporary files for holding the digits of A and B. The program will also produce a result.infiX.tmp as a temporary answer file for the unprocessed result value. The final answer value will be available inside the result.infiX. All these files would be created inside the same folder as where the program executed.

**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. */ public class libZ { public static void infiXF() { boolean isaNeg boolean isbNeg String afile = "a.infiX" String bfile = "b.infiX" String atmp = afile.concat(".tmp") String btmp = bfile.concat(".tmp") String outputfile = "result.infiX" String outputtmp = outputfile.concat(".tmp") String readA = "" String readB = "" long dAfterDecA = -1 long dAfterDecB = -1 long dAfterDecT = 0 long tmpDReadA = 0 long tmpDReadB = 0 int perReadTmp = 50 // This is changeable, how many character to read at once during temporary file reading. byte[] bufferR try{ RandomAccessFile FileA = new RandomAccessFile(afile, "r") FileWriter TmpA = new FileWriter(atmp) bufferR = new byte[(FileA.length() - 0 > perReadTmp? perReadTmp : (int)(FileA.length() - 0))] FileA.read(bufferR) readA = new String(bufferR) isaNeg = readA.charAt(0) == '-' readA = readA.replaceAll("^[-+]+", "") readA = readA.trim() dAfterDecA = readA.indexOf('.') dAfterDecA = dAfterDecA > -1? readA.length() - 1 - dAfterDecA : dAfterDecA if (dAfterDecA > -1){ readA = readA.replaceAll("[.]", "") } TmpA.write(readA); while (FileA.getFilePointer() < FileA.length() ){ bufferR = new byte[(FileA.length() - FileA.getFilePointer() > perReadTmp? perReadTmp : (int)(FileA.length() - FileA.getFilePointer()))] FileA.read(bufferR) readA = new String(bufferR) readA = readA.trim() if (dAfterDecA < 0){ dAfterDecA = readA.indexOf(".") dAfterDecA = dAfterDecA > -1? readA.length() - 1 - dAfterDecA : -1 if (dAfterDecA > -1){ readA = readA.replaceAll("[.]", "") } } else { tmpDReadA = readA.length() dAfterDecA = dAfterDecA + tmpDReadA } TmpA.write(readA) } TmpA.close() FileA.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to process " + afile + "file" , e) } try{ RandomAccessFile FileB = new RandomAccessFile(bfile, "r") FileWriter TmpB = new FileWriter(btmp) bufferR = new byte[(FileB.length() - 0 > perReadTmp? perReadTmp : (int)(FileB.length() - 0))] FileB.read(bufferR) readB = new String(bufferR) isbNeg = readB.charAt(0) == '-' readB = readB.replaceAll("^[-+]+", "") readB = readB.trim() dAfterDecB = readB.indexOf('.') dAfterDecB = dAfterDecB > -1? readB.length() - 1 - dAfterDecB : dAfterDecB if (dAfterDecB > -1){ readB = readB.replaceAll("[.]", "") } TmpB.write(readB) while (FileB.getFilePointer() < FileB.length() ){ bufferR = new byte[(FileB.length() - FileB.getFilePointer() > perReadTmp? perReadTmp : (int)(FileB.length() - FileB.getFilePointer()))] FileB.read(bufferR) readB = new String(bufferR) readB = readB.trim() if (dAfterDecB < 0){ dAfterDecB = readB.indexOf(".") dAfterDecB = dAfterDecB > -1? readB.length() - 1 - dAfterDecB : -1 if (dAfterDecB > -1){ readB = readB.replaceAll("[.]", "") } } else { tmpDReadB = readB.length(); dAfterDecB = dAfterDecB + tmpDReadB } TmpB.write(readB) } TmpB.close() FileB.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to process " + bfile + " file" , e) } String pad0 = "" dAfterDecA = (dAfterDecA < 0)? 0 : dAfterDecA dAfterDecB = (dAfterDecB < 0)? 0 : dAfterDecB dAfterDecT = dAfterDecA + dAfterDecB int digit = 9; // This is the amount of digits to calculate per cycle. long atmpsize = new File(atmp).length() long btmpsize = new File(btmp).length() long premakeoutlen = (atmpsize + btmpsize) + (digit * 2) while (pad0.length() < (digit - 1)){ pad0 = "0".concat(pad0) } // This code is for the event of someone setting the digit variable to 1. // The event most likely not to occur. nevertheless being able to set the digit variable to one also offer the greatest backward compatibility in technology. String pad0tmp = pad0.length() < 1? "0" : pad0 int digittmp = digit < 1? 1 : digit - 1 try{ FileWriter OutputTmp = new FileWriter(outputtmp); long idn = 0 while (idn < premakeoutlen){ OutputTmp.write(pad0tmp) idn = idn + digittmp } OutputTmp.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to create " + outputtmp + " file" , e) } long a = 0 long b = 0 long o = 0 long posrB = 1 long posrO = 1 long loopidxB = 1 long temp = 0 long tempadd = 0 long blen = btmpsize long alen = 0 long posrA = 0 long leftover = 0 long remainder = 0 long loopidxA = 0 long olen = new File(outputtmp).length() byte[] bufferC = new byte[digit] String tempaddstr = "" String tempstr = "" String leftoverstr = "" try{ RandomAccessFile TmpB = new RandomAccessFile(btmp, "r") while (posrB != 0){ alen = atmpsize posrA = 1 leftover = 0 remainder = 0 loopidxA = 1 posrB = blen - (loopidxB * digit) bufferC = new byte[(posrB > 0? digit : digit + (int)(posrB))] TmpB.seek(posrB > 0? posrB : 0) TmpB.read(bufferC) b = Long.parseLong(new String(bufferC)) RandomAccessFile TmpA = new RandomAccessFile(atmp, "r") RandomAccessFile OutputTmp = new RandomAccessFile(outputtmp, "rw") while (posrA != 0){ posrO = olen - ((loopidxA + loopidxB - 1) * digit) posrA = alen - (loopidxA * digit) bufferC = new byte[(posrA > 0? digit : digit + (int)(posrA))] TmpA.seek((posrA > 0? posrA : 0)) TmpA.read(bufferC) a = Long.parseLong(new String(bufferC)) temp = (b * a + remainder + leftover) tempstr = String.valueOf(temp) leftover = tempstr.length() > digit? Long.parseLong(tempstr.substring(0,tempstr.length() - digit)) : 0 tempstr = pad0.concat(tempstr) bufferC = new byte[digit] OutputTmp.seek(posrO) OutputTmp.read(bufferC) o = Long.parseLong(new String(bufferC)) tempadd = Long.parseLong(tempstr.substring(tempstr.length() - digit )) + o tempaddstr = String.valueOf(tempadd) remainder = tempaddstr.length() > digit? Long.parseLong(tempaddstr.substring(0,tempaddstr.length() - digit)) : 0 tempaddstr = pad0.concat(tempaddstr) OutputTmp.seek(posrO) OutputTmp.writeBytes(tempaddstr.substring(tempaddstr.length() - digit)) posrA = posrA > 0? posrA : 0 loopidxA = loopidxA + 1 } if (remainder + leftover > 0){ posrO = posrO - digit leftoverstr = pad0.concat(String.valueOf(leftover + remainder)) OutputTmp.seek(posrO) OutputTmp.writeBytes(leftoverstr.substring(leftoverstr.length() - digit)) } OutputTmp.close() TmpA.close() posrB = posrB > 0? posrB : 0 loopidxB = loopidxB + 1 } TmpB.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to process caculation for " + afile + " file and " + bfile + " file." , e) } boolean lead0End = false long dBeforeDec = olen - dAfterDecT long posw = 0 long truncatediff = 0 long truncatelen = 0 String readOutputTmp = "" String checker = "" String truncatestr = "" try{ RandomAccessFile OutputTmp = new RandomAccessFile(outputtmp, "r") FileWriter Output = new FileWriter(outputfile) if (isaNeg != isbNeg){ Output.write("-") } while (posw < dBeforeDec){ bufferR = new byte[(posw + perReadTmp < dBeforeDec? perReadTmp : (int)(dBeforeDec - posw))] OutputTmp.seek(posw) OutputTmp.read(bufferR) readOutputTmp = new String(bufferR) if (lead0End == false){ readOutputTmp = readOutputTmp.replaceAll("^0+", "") lead0End = readOutputTmp.length() > 0? true : false } Output.write(readOutputTmp) posw = (posw + perReadTmp < dBeforeDec)? posw + perReadTmp : dBeforeDec } Output.close() long outputlen = new File(outputfile).length() RandomAccessFile Output2 = new RandomAccessFile(outputfile, "rw") if (outputlen < 2){ bufferR = new byte[1] Output2.read(bufferR) checker = new String(bufferR) if (outputlen < 1 || checker.equals("-")){ Output2.seek(Output2.length()) Output2.writeBytes("0") } } if (dAfterDecT > 0){ Output2.seek(Output2.length()) Output2.writeBytes(".") } Output2.seek(Output2.length()) while (posw < olen){ OutputTmp.seek(posw) bufferR = new byte[(olen - posw > perReadTmp? perReadTmp : (int)(olen - OutputTmp.getFilePointer()))] OutputTmp.read(bufferR) readOutputTmp = new String(bufferR) truncatestr = readOutputTmp truncatestr = readOutputTmp.replaceAll('0+$', "") truncatediff = readOutputTmp.length() - truncatestr.length() truncatelen = truncatediff == readOutputTmp.length()? truncatediff + truncatelen : truncatediff Output2.writeBytes(readOutputTmp) posw = posw + perReadTmp } outputlen = Output2.length() Output2.setLength(outputlen - truncatelen) outputlen = Output2.length() Output2.seek(outputlen - 1) bufferR = new byte[1] Output2.read(bufferR) readOutputTmp = new String(bufferR) if (readOutputTmp.equals(".")){ Output2.setLength(outputlen - 1) } Output2.close() OutputTmp.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to process result file." , e) } } public static void randFile() { String fileA = "a.infiX" String fileB = "b.infiX" int randDigitA = (int)(Math.random() * (350 - 0) + 40) int randDigitB = (int)(Math.random() * (350 - 0) + 40) int randDecPOSA = (int)(Math.random() * (randDigitA - 20) + 20) int randDecPOSB = (int)(Math.random() * (randDigitB - 20) + 20) try { FileWriter RANDOMA = new FileWriter(fileA); RANDOMA.write("-") for (int idn = 0; idn < randDigitA; idn++){ RANDOMA.write(""+(int)(Math.random() * (9 - 0) + 0)) if (idn == randDecPOSA){ RANDOMA.write(".") } } RANDOMA.close() FileWriter RANDOMB = new FileWriter(fileB) for (int idn = 0; idn < randDigitB; idn++){ RANDOMB.write(""+(int)(Math.random() * (9 - 0) + 0)) if (idn == randDecPOSB){ RANDOMB.write(".") } } RANDOMB.close() } catch (IOException e) { throw new IllegalArgumentException("Unable to create " + fileA + " and " + fileB , e) } } } libZ.randFile() libZ.infiXF() System.out.println("Check in the current directory.") System.out.println(" a.infiX is the file that hold the first set of digits.") System.out.println(" b.infiX is the second file that hold the digits.") System.out.println(" result.infiX is the result of the multiplication procedure.") System.out.println("The name of the temporary file for them are a.infiX.tmp, b.infiX.tmp, result.infiX.tmp.") System.out.println("Temporary files can be delete after execution, but are currently kept for debuging purposes.")

It took a lot of time and dedication for developing the Infinity formula and the article. Please give respect to the copyright credit. This article is licensed under Attribution-NonCommercial 4.0 International (CC BY-NC 4.0). InfiFX’s source code license is written as comments inside the source code.

Copyright secured by Digiprove © 2017This post was written by Kevin and was first post @ http://kevinhng86.iblog.website.

Original Post Name: "Working With Number – Infinity Multiplication – Beyond Memory – Groovy".

Original Post Link: http://kevinhng86.iblog.website/2017/03/09/working-with-number-infinity-multiplication-beyond-memory-groovy/.

**Advertisement**