Working With Number – Infinity Multiplication – Optimised The Code – JavaScript

In the previous two chapters of the “Infinity Multiplication” series for JavaScript, I had demonstrated the methods and the programming codes for multiplying together two numbers that were stored as string type data, and the equation was processed at the rate of one digit at a time. If you need a reference on the procedures for the multiplication equation, please refer to chapter one and two of the “Infinity Multiplication” series. The chapters’ names are “Infinity Multiplication – Beyond integer” and “Infinity Multiplication – Decimal, Precise Float Calculation”.

The previous two chapters’ programming codes are error proof. This is because the programming codes for the previous chapters were built to process the equation at the rate of only one digit at a time. Besides that, we were also storing the answer for each cycle of multiplication on a separate temporary answer string before joining the temporary answer string to the final output string. By having a temporary answer string, it is easier to inspect if there are any errors in the formula or in the code. Nonetheless, the programming codes of the previous chapters are inefficient and should not be used in a production environment.

In this chapter, I will demonstrate what in my opinion consider to be the most optimized way for optimizing the previous chapters’ programming codes and methods. By optimizing the methods and the codes, our program can execute efficiently, and therefore, we can utilize the program for the production environment. Same as the previous chapters, the source code of this chapter was tested against hundred of thousand plus test cases. With this article, I also included the source code for testing all the previous chapters’ programming codes and including the code of this chapter. I also did a benchmark test for this production version of infiX versus the previous versions of infiX. Note that infiX is the name of the program that is the programming code examples for this chapter and the all the previous chapters.

Previous Chapter: Decimal, Precise Float CalculationNext Chapter: Chapter 3B

Optimizing The Code

Before further discussion in regard to how to optimize the program to operate more efficiently, I will first present the results of the benchmark test for this version of infiX versus the previous version of infiX. When testing for how fast the program executes, I produced two strings of digits, each string contained forty digits. The strings are then passed into each version of infiX 100,000 times, and the time it took for each version of infiX to complete the calculation was recorded as the benchmark score. This test ran twice and the average result between the two tests is used as the final benchmark score. Note that both versions of infiX were calculating the same two strings of digits 100,000 times.

This version of infiX for JavaScript took 6.952 seconds to compute the results for 100,000 cases, and the test strings didn’t have a fractional part. With the decimal, the program took 7.254 seconds to compute the results 100,000 times. For a comparison of the execution time, the previous version of infiX took 42.450 seconds to compute the results for 100,000 cases, and the test string didn’t have a fractional part. When there is a fractional part, the previous version took 43.609 seconds to compute the result for 100,000 test cases.

What are the changes in the methods and in the programming code that give the program the ability to operate almost ten times faster? Instead of processing one digit at a time, the program was converted to process the equation at the rate of five digits at a time. For a summary of each multiplication cycle, the previous version of infiX had to convert a digit that was stored as string type data to an integer type data twice, convert the result value to string type data, stores the result value of the multiplication procedure to a temporary answer string, add the temporary answer string to the final output string, and calculate the carry-over values for both, the addition and the multiplication procedures. By converting the program to compute the equation at the rate of five digits at a time, we would still have the same procedures for each multiplication cycle. Nonetheless, instead of only consuming a single digit from both numbers per multiplication cycle, each of our multiplication cycles would now consume five digits. Thus, any single process in the multiplication cycle would be applied to a block of five digits and not just one. By processing more digits per cycle, the program saves processing time from all its sub-process of a multiplication cycle.

Besides processing more digits per cycle, the temporary answer string is now removed and the program would only use the single output string for storing and processing all the result values. By removing the temporary answer string, the program would also save memory usage, and therefore, requires far less memory to operate.

Besides the above changes, the “for” loop was converted into the “while” loop. The “while” loop was benchmarked to execute faster than the “for” loop. The substring() and the slice() function were chosen due to their speed and execution time. For replacing a value in a string or searching for a value in a string, where it is possible, instead of using the regex engine, I used the native built-in function that can manipulate strings. Native built-in functions that involve modifying or searching for a value within a string was tested and shown to execute faster than if to use the regex engine for the same purpose. Nonetheless, the native built-in functions might not be as flexible when it’s come to complex conditions. I can only assume that the regex engine took longer to compute a result is because the regex engine needs to evaluate the pattern’s information to understand the conditions within pattern before applying the conditions onto a string.

Although this version of infiX only processes five digits at a time, this number may have to be configurated to a lower amount if we are truly working in a 32 bits environment. This is because the maximum value that a 32 bits integer can hold is 2,147,483,647. Which is about 10 digits in length. For a multiplication equation, five digits multiply by another five digits have the potential to produce a maximum result value that is ten digits in length and that value is 9,999,999,999. This is a value that is a little bit larger than the maximum value that a 32 bits integer can hold. Thus, if truly working in a 32 bits environment, the number of digits to be processed per cycle should be configurated at the rate of four digits at a time.

When it comes to the formula for multiplying five digits at a time, the formula is similar to the formula of multiplying one digit at a time. Nonetheless, when writing the result to the output string it can be a complicated task. This simply because the program would now operate without a temporary answer string. Before going into the examples and the explanations of the programming code, let’s first look at the new formula for the multiplication procedures.

*** Carry-overM = the carry-over value for the multiplication procedure.
    Carry-overA = the carry-over value for the addition procedure.

Example: 92345 67890 x 12545 89085
                                                         92345  67890
                                                       x 12545  89085
                                                        --------------
Multiply 67890 to 89085                                       (80650)  | carry-overM = 60479 and carry-overA = 0
  
Multiply 92345 to 89085                                 54325          | carry-overM = 82265
Add carry-overA and carry-overM                            +0
                                                       +60479          
Value of this position                                 (14804)         | carry-overA = 1
Add carry-overA and carry-overM                      1
                                                +82265
Value of this position                          (82266)                | 0 carry-overM and 0 carry-overA

Current answer                                   82266  14804  80650                 
                                                          
Multiply 67890 to 12545                                 80050          | carry-overM = 8516
Add current position value in answer string            +14804               
Value of this position                                 (94854)         | carry-overA = 0

Multiply 92345 to 12545                          68025                 | carry-overM = 15584
Add current position value in answer string     +82266
Add carry-overA and carry-overM                  +8516 
                                                     0
Value of this position                          (58807)                | carry-overA = 1
Add carry-overA and carry-overM               1
                                         +15584
Value of this position                   (15585)
                                         ----------------------------
Add the previous results together         15585  58807  94854  80650                                                              

With the formula above in context, we can see that we are multiplying all the digits in A string to the digits of B string in a block of five digits at a time. Each block of five digits in A string is multiplied by the first block of five digits in B string, then to the second block, then to third and so on if there is. For each time when we multiplied a block of five digits from A to the first block of five digits in B, starting from right to left of the answer string, we would only store a block of five digits at a time to the answer string. When there are more than five digits in the result value then all the digits after the fifth digits is to be kept as the carry-over value for the next equation. When storing the result into the answer string, the first five digits that are the rightmost in the result value would be the digits that are to be stored into the answer string. The sixth digits and beyond would be kept as the carry-over value.

When it comes to the procedure of when we are adding the carry-over value to the result value of the equation. Similar to the above, the first five most digits that are the rightmost in the result is the result value, digits that are beyond that is the carry-over value.

After multiplying all the digits in A string to the first block of five digits in B string, we would then multiply all the digits in A string to the next block of five digits in B string. When we are moving over to the next block of five digits in B string, our starting position for adding the equation’s result value into the answer string would move over to the left by one block that is five digits in length. Every time when the equation is moving to another block of five digits in B string, the starting position in the answer string would also move over to the left by one block of digits. For the procedure of adding the result value of an equation into the answer string, the rules from above that are in regard to the carry-over values, and how many digits are the result and how many digits are the carry-over value would also apply to this procedure.

When it comes to the variables that we need in the program, the first variable our program needs is a variable that store a value that represents how many digits that the program is processing per multiplication cycle. This value can extend the flexibility of the program. If we were to work in an environment where the integer data type is stored in larger bit blocks then we can increase this value so that the program can process more digits per cycle of calculation. On the other hand, in the event where we have to work in a more restricted environment and integer values are stored in smaller bit blocks then we can decrease this value to adapt the program to the environment. For the naming context, the mentioned variable is named “digit”.

The second variable we would need is a variable that will store a value that is the index count of how many times we had read from B string. In the circumstance of this article, we know that each time we read a string, we are reading a block of five digits. When it comes to the ending of the strings, the amount of how many digits that are left for the program to read from can vary. Nonetheless, this program was built to considers the variation on the number of digits in the final block of digits for both strings. For the naming context, the variable for storing the value of the read count for B string is named “posr”.

Besides the above variables, the program would also need a variable that stores a value that represents the position that the program is working on in the answer string. That variable is named “posw”. For a fourth new variable, the variable is named “prepos”. When utilizing the substring() function, the behavior of the substring() function is that when a negative value is passed into the substring() function, then the substring() function will treat that value as a position in the string counting from right to left, with negative one being the rightmost position. This is the opposite of when a positive value is passed into the substring() function. Since we are working from right to left in the strings, for some procedures, it is easier to use negative values. Therefore, a negative version of the value that is stored in the “digit” variable is assigned to the “prepos” variable to enhance the simplicity for the equation. This below is the variables that we need to declare outside of the calculation loop.

   var temp = 0,
       alen = a.length,
       blen = b.length,
       output = "",
       bi = blen,
       posr = 0,
       posw = 0,
       digit = 5,
       prepos = digit * -1;

For every time the program process a position in B string, the program would have to process all the positions in A string. Thus, the outer loop will stay at a position in B string until all the position in A string is read, and after each cycle, the outer loop will move the read point for B string by five positions. For the inner loop, after processing a position in A string, the loop will also move the read point for A string by five positions.

To get five digits from B string, we can use the substring() function. The first position we want to input into the substring() function is the position “from”, which is the current position of where we are at in B string subtract to the number of digits that the program is processing per cycle. When passing a value that represents the “to” position into the substring() function, the value would be the current position of where we are at in B string. Notice that we do not subtract the string’s length to a value of one to get the current position. This is because of the substring() function’s behavior. The substring() function will only grab the characters before the “to” position and would not get the character that is in the “to” position. Counting from left to right, if the “to” position that was passed into the substring() function is before the leftmost position in the string then the substring() function will only get from the string a single character that is at the zero position, which is the leftmost position.

When we are executing the inner loop for the calculating procedures and when the answer string did not yet contain a value, we would simply place the result value of the procedures into the output string bases on the following conditions. When it comes to processing the result value of the current procedure, one of the values that we have to evaluate for is the carry-over value. To get the carry-over value from the result value, we can utilize the slice() function to extract the number of digits that are beyond five digits from the result value. Then we would assign the extracted value to the carryOverM variable. The carryOverM variable is the variable that holding the carry-over value for the multiplication procedure.

For what to input into the slice() function, the first value is a value of zero and the second value is the value that was defined by the “prepos” variable, which is the negative value of the value that represents the number of digits that the program is processing per cycle. The slice() function treat negative values as positions that are counting from right to left of the string. When the result value does not have carry-over value, which means we are extracting a character from the zero position to the zero positions. In the case of the slice() function’s behavior, the previous also mean that we are not extracting anything from the input value. Therefore, the slice() function would give back an empty value. If this happens then the parseInt() function will produce a NAN result.

Thus, we also apply a conditional or statement. This statement will assign a value of zero to the carryOverM variable in the event where the slice() function fail to obtain a value. When it comes to appending the result value to the answer string, we would always append the result value in the format of a digits block that is five digits in length. Therefore, we would have to append to the result a number of zeroes for the event of when the result value contains less than five digits. The following examples will demonstrate the circumstance of how the result value can have less than five digits. For the first example, we have an equation of 1 00125 x 1 00001. In that equation, when executing the equation, the first block of five digits from A multiply by the first block of five digits of B would translate into an equation of 1 x 125. The result value of the equation would be a value of 125. If we do not append zeroes to the beginning of the result value to make up for the missing length then when it comes to the next calculation, there will only be a value of one that is going to be added to the beginning of the result value. Which will give us a value of 1125 as the result value for the equation instead of the correct answer of 1 00125. To be able to always consistently produce a result value that is five digits in length, we add four zeroes to the left side of the result value. We then utilize the slice() function to extract the five rightmost digits from the just modified result value. For adding zeroes to the result value, we would only execute this procedure after when we had completed the evaluation of the result value for any carry-over value.

After multiplying all the digits block of A string to the first block of digits in B string, we then append any carry-over value to the leftmost of the answer string. The principle of a consistent number of digits in a block of digits would also apply to this procedure. Take note here that when I subtract the index count for A string, of which the value is held by a variable that named “ai”, it can also be done by subtracting “ai” to the value of the “digit” variable as mentioned earlier. This code here is just for the demonstration purpose of which showed that we are moving by five positions per cycle. Nonetheless, for easy customization, this can be changed to “ai – digit”, and when modifying the value of “bi”, it can also be changed to “bi – digit”.

This code block below demonstrate the mentioned procedures in JavaScript.

while (bi > 0){
     var z = parseInt(b.substring(bi - digit, bi)),
         outlen = output.length,
         ai = alen,
         carryOverM = 0;

     if (outlen < 1){        
          while (ai > 0){
              temp = parseInt(a.substring(ai - digit, ai), 10) * z + carryOverM;
              carryoverM = parseInt(temp.toString().slice(0, prepos)) || 0;
              output = ("0000" + temp.toString().slice(prepos)).slice(prepos) + output;
              ai = ai - 5;
          }
          output = carryOverM > 0? ("0000" + carryOverM.toString()).slice(prepos) + output : output;
     }

The previous procedures are for when the answer string did not yet contain a value. However, it can get a bit complicated for when the answer string does contain a value. Each time we read a digits block in A string, we would have to calculate the positions of where we are working on in the answer string. Besides the working on position, the starting position for the answer string would move over to the left by one digits block for each digits block that we read in B string. Also, the position that we are working on in the answer string would also move over to the left by one digits block after we process a digits block from A string.

To calculate the position that we are working on in the answer string, we would first calculate the starting position of the answer string. To get the starting position of the answer string, we multiply how many times we had read from B string to the value of the “prepos” variable, which is just the negative version of the “digit” variable. After getting the starting position of the answer string, we then multiply the number of times we had read from A string to the value of the “prepos” variable. Then we add the result value of that equation to the value of the starting position of the answer string.

For this time of multiplying a digits block from A string to the digits block in B string, we have to add the result value of the equation to a value that exists in the position of where we are working on in the answer string. The result value for this equation is stored in a temporary placeholder, the temporary placeholder is the variable with the name “tempadd”. To get the digits from the answer string, we will utilize the slice() function. For the “from” position that we are going to pass to the slice() function, we use the negative version of the current position that we are working on in the answer string and add that value to the value of the “prepos” variable. For the “to” position, that value would be the position that we are working on in the answer string.

If the tempadd variable holds a value that is more than five digits in length then we would produce a carry-over value for the addition procedure. The carry-over value for our addition procedure is held by a variable that is named carryOverA. For an addition equation, the carry-over value can never be more than a value of one if we are only adding two sets of digits together. Thus, our carry-over value our addition procedure can only be a value of one when the result value contains a value that is more than five digits in length. Else, we will assign a zero value to the carry-over value. The value of the carryOverM and the carryOverA variable will be added to the result value of the equation of next loop execution.

After producing a value for the tempadd variable, we would then place the value of the tempadd variable into our answer string. When it comes to placing the tempadd’s value into the answer string, we first get all the digits from the beginning of the answer string to the position that is before the position of where we grabbed the first digit from the answer string. We then place our tempadd’s value to the right side of the previous value. Then we get the digits from the position that is after the position of the last digit that we grabbed from the answer string to the end of the answer string. We place this value on the right side of where we placed the tempadd’s value. All the digits that we pieced up together with the tempadd’s value are assigned as a new value to the answer string.

After completely multiplying all the digits in A string to a set of digits in B string, we would add the value of the carryOverM and carryOverA variable together, and place this value to the left of the answer string. The below code block demonstrate the above procedures into programming statements for JavaScript.

while ( ai > 0){
     posw = (posr * prepos) + (loopidx * prepos);
     temp = parseInt(a.substring(ai - digit, ai)) * z + carryOverM + carryOverA;
     carryOverM = parseInt(temp.toString().slice(0, prepos)) || 0;
     tempadd = parseInt(temp.toString().slice(prepos), 10) + ( parseInt(output.slice(posw + prepos,posw ),10) || 0);   
     carryOverA = tempadd > 99999? 1 : 0;
     output = output.slice(0, posw + prepos) + ("0000" + tempadd.toString().slice(prepos)).slice(prepos) + output.slice(posw);
     loopidx = loopidx + 1;
     ai = ai - 5;               
}
output = carryOverA + carryOverM > 0? ("0000" + (carryOverA + carryOverM).toString()).slice(prepos) + output: output;

As for testing and debugging the infiX program, the code block below is what I used to test the previous version of InfiX against the native built-in multiplication feature of the JavaScript’s platform. For the previous version of infiX, the program was built to process the multiplication equation at the rate of only one digit at a time. Therefore, if the program always correctly produces result values for equations that involve smaller strings of digits, then the program would also be able to consistently produces correct result values for larger strings of digits. I also tested the infiX program against Ruby’s native multiplication feature. As it seems, Ruby’s native multiplication feature can also calculate very large numbers.

When it comes to numbers that do have a fractional part, do take into consideration that the native built-in calculating feature would not be able to provide the actual precise floating point calculation. The tester code below will produce two random numbers for each test case. The tester will then multiplying the numbers together using the native multiplication feature of JavaScript. The tester will then pass the numbers as string type data into the infiX function. If there is a mismatch between the two result values, then the tester will print the test case information.

To use this tester, simply look for version two of infiX, which included in the chapter that is called “Decimal, Precise Float Calculation” for JavaScript. Then place this tester code with the program. The number of test cases that the tester will execute was preset at a value of 5000. This value can be increased or decreased as necessary. For JavaScript, it is safe to set the number of cases to run at less than or equal to 100,000 cases at a time. Otherwise, it might take sometimes to get back the results value and could also freeze the browser. This code block below is the tester code for the version two of infiX.

var um = 0;
for (var id = 0; id < 5000; id++){
    
    var a = parseInt(Math.random() * (9949 - 0) + 0, 10);
    var ac = parseInt(Math.random() * (999 - 0) + 0, 10); // This is decimal in A string, turn 999 to 0 to calculate only whole number.
    
    var b = parseInt(Math.random() * (99999 - 0) + 0, 10);  
    var bc = parseInt(Math.random() * (99999 - 0) + 0, 10); // this is decimal in B string turn the 99999 to 00000 to only calculate whole numbe4r
       
   
    var padA = "";
    var padB = "";
    var idn1 = 0;
 	var idn2 = 0;
    while (idn1 < parseInt(Math.random() * (3 - 0) + 0, 10) ){
    	padA = "0" + padA; // This is to produce a "0" to "000" and pad behind the decimal in A string.
        idn1++;
    }
    while (idn2 < parseInt(Math.random() * (3 - 0) + 0, 10) ){
    	padB = "0" + padB; // This is to produce a "0" to "000" and pad behind the decimal in B string.
        idn2++;
    }
    
    
    ta = parseFloat("-" + a.toString() + "." + padA + ac.toString());
    tb = parseFloat("-" + b.toString() + "." + padB + bc.toString());
    
    var test1 = ta * tb;
    test2 = infiX2(ta.toString(), tb.toString() );
    test1 = test1.toString();
    
    
    if (test1 !== test2){
    	um++;
        document.write("Unmatch: " + um + "<br>");
        document.write("Question: " + ta.toString() + " * " + tb.toString() + "<br>");
        document.write("Native Multiply: " + test1 + " | InfiX: " + test2 + "<br><br>");
    }
    
}

When it comes to testing this version of infiX, I tested the result values of this version of infiX to the result values of the previous version of infiX. Since the previous version of infiX was already thoroughly tested, this version’s result value would be correct if matches the result values of the previous version. The previous version of infiX does take a long time to produce result values. Nonetheless, as a prototype, I built the previous version as a demonstrator for the articles that I wrote and also as a tester for testing future releases of the infiX program.

To use the tester code below, simply place this version of infiX and the version two of infiX in the same file and with the tester code. Rename one of the infiX function to infiX2. This tester will produce five blocks of random digits that are before the decimal for each string of digits. The random blocks of digits can be anywhere between one or five digits. The tester will then pad 0 to 15 zeroes behind the decimal, and then the tester will place three blocks of random numbers to the right of the zeroes that were just added to the string. After that, the tester will place another 0 to 15 zeroes and then the last two blocks of random digits to the right side of the previous 3 block of random digits. It is a recommendation that this tester should not be set to execute more than 50,000 cases at a time. It can take a very long time to produce the results. This is because the previous version of InfiX does take a long time to produce an answer.

The below code block is the tester code for JavaScript.

for (var id = 0; id < 10000; id++){
    var a1 = parseInt(Math.random() * (99999 - 1) + 0, 10),
        a2 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        a3 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        a4 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        a5 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        ac1 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	ac2 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	ac3 = parseInt(Math.random() * (9999 - 0) + 0, 10),
    	ac4 = parseInt(Math.random() * (9999 - 0) + 0, 10),
    	ac5 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        padA1 = "",
        padA2 = "";
    
    var b1 = parseInt(Math.random() * (99999 - 1) + 1, 10),
        b2 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        b3 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        b4 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        b5 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        bc1 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	bc2 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	bc3 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	bc4 = parseInt(Math.random() * (99999 - 0) + 0, 10),
    	bc5 = parseInt(Math.random() * (99999 - 0) + 0, 10),
        padB1 = "",
        padB2 = "";
        
    var idn = 0,
        idn2 = 0;
   	while ( idn < parseInt(Math.random() * (15 - 0) + 0, 10) ){
    	padA1 = "0" + padA1;
        idn++;
    }
    while ( idn < parseInt(Math.random() * (30 - 15) + 15, 10) ){
    	padA2 = "0" + padA2;
        idn++;
    }
    while ( idn2 < parseInt(Math.random() * (15 - 0) + 0, 10) ){
    	padB1 = "0" + padB1;
        idn2++;
    }
    while ( idn2 < parseInt(Math.random() * (30 - 15) + 15, 10) ){
    	padB2 = "0" + padB2;
        idn2++;
    }
    
    
    ta = "-" + a1.toString() + a2.toString() + a3.toString() + a4.toString() + a5.toString() + "." + padA1 + ac1.toString() + ac2.toString() + ac3.toString() + padA2 + ac4.toString() + ac5.toString();  
    tb = "+" + b1.toString() + b2.toString() + b3.toString() + b4.toString() + b5.toString() + "." + padB1 + bc1.toString() + bc2.toString() + bc3.toString() + padB2 + bc4.toString() + bc5.toString();  
    
    var test1 = infiX(ta, tb),
        test2 = infiX2(ta, tb); 
    
    if (test1 !== test2){
        document.write(ta + " * " + tb + "<br>");
        document.write(test1 + " | " + test2 + "<br><br>");
    }
    
}

The below code snippet is the infiX program. This version is usable for a production environment.


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 
// 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 normal usage version of infinity multiplication written for JavaScript and is designed for a production environment.  
//         The first limitation of this version is how much memory JavaScript allow the string to be store.
//         The second limitation is how much memory JavaScript can assign to the program.
//         If memory allow, for this version a string can only be less than 1,073,741,823 digits
//
//    Example of memory usage calculation:
//         500 megabyte string of digits multiply to another 500 megabyte string of digits.
//         1000 Mb of memory to store the strings outside of the function.
//         1000 Mb of memory for when the strings are passing into the function. 
//         1000 Mb for the answer string.
//          100 Mb (this can vary but most likely to be less than this) for script operation.
//         3100 Mb of memory is requires for multiplying two strings of digits where each string is 500MB in size.

function infiX(a, b){     
    var isaNeg = a[0] === "-"? 1 : 0,
        isbNeg = b[0] === "-"? 1 : 0,
    a = a.replace(/^[-+]+/g, "");
    b = b.replace(/^[-+]+/g, "");    
    a = a.replace(/^0+/g, "");
    b = b.replace(/^0+/g, ""); 
    
    var aDecPos = a.indexOf("."),
        bDecPos = b.indexOf("."),
        oDecPos = 0;
  
    if (aDecPos > -1){
        a = a.replace(/0+$/g, "");
        aDecPos = (a.length - 1 - aDecPos) > 0? (a.length - 1 - aDecPos) : 0;
        a = a.replace(/[.]/g, ""); 
    }
    if (bDecPos > -1){    
        b = b.replace(/0+$/g, "");
        bDecPos = (b.length - 1 - bDecPos) > 0? (b.length - 1 - bDecPos) : 0;
        b = b.replace(/[.]/g, "");
    }
    
    if (a.length < 1 || b.length < 1){
        return "0";    
    }
    
    if (a == "1" && aDecPos < 1){
        if (bDecPos > 0){
            b = b.slice(0, b.length - bDecPos) + "." + b.slice(b.length - bDecPos); 
            b = b[0] === "."? "0" + b: b;
            return ((isaNeg !== isbNeg)? "-" + b : b);
        }
        return ((isaNeg !== isbNeg)? "-" + b : b);
    }
  
    if (b == "1" && bDecPos < 1){
        if (aDecPos > 0){
            a = a.slice(0, a.length - aDecPos) + "." + a.slice(a.length - aDecPos); 
            a = a[0] === "."? "0" + a: a;
            return ((isaNeg !== isbNeg)? "-" + a : a);
        }
        return ((isaNeg !== isbNeg)? "-" + a : a);
    }

    if (aDecPos > -1 || bDecPos > -1){
        aDecPos = aDecPos > -1? aDecPos : 0;
        bDecPos = bDecPos > -1? bDecPos : 0;        
        oDecPos = aDecPos + bDecPos;
    }
    
    var temp = 0,
        outposition = 0,
        alen = a.length,
        blen = b.length,
        output = "",
        bi = blen,
        posr = 0,
        posw = 0,
        digit = 5,
        prepos = digit * -1;

    while (bi > 0){
        var z = parseInt(b.substring(bi - digit, bi)),
            outlen = output.length,
            ai = alen,
            carryOverM = 0;

        if (outlen < 1){        
            while ( ai > 0){
                temp = parseInt(a.substring(ai - digit, ai), 10) * z + carryOverM;
                carryOverM = parseInt(temp.toString().slice(0, prepos)) || 0;
                output = ("0000" + temp.toString().slice(prepos)).slice(prepos) + output;
                ai = ai - 5;
            }
            output = carryOverM > 0? ("0000" + carryOverM.toString()).slice(prepos) + output : output;
        } else {
            var carryOverA = 0,
                tempadd = 0,
                loopidx = 0;
                
            while (ai > 0){
                posw = (posr * prepos) + (loopidx * prepos);
                temp = parseInt(a.substring(ai - digit, ai)) * z + carryOverM + carryOverA;
                carryOverM = parseInt(temp.toString().slice(0, prepos)) || 0;
                tempadd = parseInt(temp.toString().slice(prepos), 10) + ( parseInt(output.slice(posw + prepos,posw ),10) || 0);   
                carryOverA = tempadd > 99999? 1 : 0;
                output = output.slice(0, posw + prepos) + ("0000" + tempadd.toString().slice(prepos)).slice(prepos) + output.slice(posw);
                loopidx = loopidx + 1;
                ai = ai - 5;               
            }
            output = carryOverA + carryOverM > 0? ("0000" + (carryOverA + carryOverM).toString()).slice(prepos) + output: output;
        }
        posr = posr + 1;
        bi = bi - 5;
    }
    
    if (oDecPos > 0){
        while (output.length < oDecPos){
            output = "0" + output;
        }
        output = output.slice(0, output.length - oDecPos  ) + "." + output.slice(output.length - oDecPos);
        output = output.replace(/0+$/, "");
        output = output.replace(/[.]$/, "");
        output = output.replace(/^0+/, "");
        output = output[0] === "."? "0" + output : output;
        return (isaNeg !== isbNeg? "-" + output : output);
    }    
    output = output.replace(/^0+/, "");
    return (isaNeg !== isbNeg? "-" + output: output);
}

Digiprove sealCopyright secured by Digiprove © 2017

This post was written by Kevin and was first post @ http://kevinhng86.iblog.website.
Original Post Name: "Working With Number – Infinity Multiplication – Optimised The Code – JavaScript".
Original Post Link: http://kevinhng86.iblog.website/2017/02/19/working-with-number-infinity-multiplication-optimised-the-code-javascript/.

Advertisement


Random Article You May Like

One thought on “Working With Number – Infinity Multiplication – Optimised The Code – JavaScript

  1. Simply desire to say your article is as astounding.
    The clarity on your publish is simply excellent and
    i could think you’re a professional on this subject. Well with your
    permission allow me to take hold of your RSS feed to keep up to date with coming near
    near post. Thank you one million and please keep up the rewarding work.

Leave a Reply

Your email address will not be published. Required fields are marked *

*
*