Working With Number – Infinity Multiplication – Decimal, Precise Float Calculation – R

** This chapter is being re-worked on wording and grammar. Also, there are two changes in the source code, the variable that named leftover is changed to carryOverM and the variable that named remainder is changed to carryOverA **

In the previous chapter of Infinity Multiplication, the chapter mainly concentrated onto the subject of storing two integer numbers in string format and how to apply a mathematical multiplication equation on the two numbers at the rate of one digit at a time. The previous chapter mainly discussed in regard to whole numbers, numbers that do not contain a decimal placement. For this chapter, the subject is about how to apply a multiplication equation on large numbers that do contain a decimal placement.

When computers store a number as an integer value. The value is stored in binary bits block that only store a binary value that represents the actual value of the number. Besides the value of the number, the binary bits block that is used to store the integer number may utilize one leftmost bit to defined if the value is a negative or a positive value, nevertheless, the bits block that store the integer value does not store a decimal placement. The reason of why computers can not store a decimal placement when a decimal value is stored as a binary value is because of the differential between the two numbering system. Nevertheless, when it come to programming, a majority of programming languages if not all do have a data type that can store numbers with a decimal value. The most basic and most likely to be a built-in data type that is used by programming languages that can store a decimal value is usually called “float”.

When it comes to utilizing mathematical equations on float values, there are many method of how to calculate a floating point value. There are floating point calculation formulas that do offer very precise answers. Nonetheless, there are circumstances where some floating point calculation formula does round off some of the digits that are on the right side of the decimal of the result value to get a near precision result value for the equation. These type of rounding can be very minor and would most likely have little affection.

Nonetheless, if we truly wanted to calculate a precise decimal value that is longer than thousand of digits, is there a solution to that? This is the second chapter of “Infinity Multiplication”, “Decimal, Precise Float Calculation”.

For a preview on the infinity subject, most of my readers ask me if this is truly an infinity library and is this truly an infinity subject? In my answer, Infinity is a subject that is very hard to explain in words. Since the values of infinity is endless and since it is endless, can we really calculate it? This is my formula for calculating an infinity value “infC = infA = infAL”, of which can also be describe as “Infinity Calculation equal to Infinity Assumption and is equal to Infinity Alteration”. I will discuss in regard to the infinity formula and how to apply the formula in a programming perspective in chapter five of the Infinity Multiplication, Division, Adding and Subtraction subject. Chapter five of the infinity subject will only be available in full at http://kevinhng86.iblog.website, Programming World, and sites that are allowed to posts the articles in full.

For the next chapter of Infinity Multiplication, which is chapter three and that is scheduled to be released this week. The chapter will contain the optimized source code of infiX, which can be used for a production environment. With the source code, I will also release the tester code of which I used for testing hundreds of thousand of test cases against the infiX program. The only code that I do not release with the article is the benchmark testing source code, of which tests how fast the program run versus 100,000 or 1,000,000 cases.

This is the R Programming Language version of “Infinity Multiplication – Decimal, Precise Float Calculation”.
***

Previous Chapter: Beyond IntegerNext Chapter: Optimised The Code

How To Multiply Two String Of Digits Together With Precise Decimal Calculation

To simplify the explanation for this article, we are assuming that we are multiplying a string full of digits which name A to another string that is full of digits which name B. When multiplying two string of digits together to get a result value, the first challenge we face for applying the mathematical equation on the string is the decimal value or the digits behind the decimal. For addition and subtracting we can split the digit in A string into two parts. One part can contain the digits before the decimal and the other part can contain the digits behind the decimal. However, this technique will be very complicated when applying to multiplication. This is because of, every digit, whether if before or after the decimal in string A has to be multiplied to every digit in string B.

If we split A string into two parts, it’s can get very complicated to manipulate each part of A string to properly multiply to each part of B string, consider that they are both carry a decimal value. It’s doable, however complicated. We can have another simple solution, of which we can remove the decimal from both A and B string and treat the string as if the string does not contain the decimal. After we finished with the mathematical multiplication procedure we can inject the decimal into the correct position for our answer string.

In my opinion, the method of injecting the decimal into the correct position is highly efficient, is error proof and is simpler for loop controlling. This method is doable for multiplication due to how the decimal is placed in a multiplication procedure. Nevertheless, let first inspect the formula for calculating a decimal value in a mathematical multiplication procedure.

Formula: Calculating the decimal value for multiplication.
Step 1: Count the amount of digit behind the decimal in A string that is not a trailing zero. Remove trailing zero. 
Step 2: Count the amount of digit behind the decimal in B string that is not a trailing zero. Remove trailing zero.
Step 3: Add the number of digits that are behind the decimal for both A and B string together.
        In my description, this value is called the total amount of digits that need to be behind the decimal in our answer string.
Step 4: Remove the decimal from both A and B string, then apply the multiplication procedure on A and B string.
Step 5: Once the answer string is ready, count from right to left of the answer string.
        Using the value from step three and place the decimal in front of the total amount of digits that need to be behind the decimal in our answer string.
        If the answer string contains fewer digits than the count of step three, add a zero to the beginning of the answer string.
Answer: After placing the decimal, we can remove leading and trailing zeroes. 
        Trailing zeroes in decimal value do not alter the value of the number.
        Leading zeroes in a whole number do not alter the value of the number.

Example: 0.1 x 0.1
Step 1:   (1 digits behind the decimal in A) + (1 digits behind the decimal in B) = (2 digits behind the decimal needed in the answer string)
Step 2:   1 x 1 = 1   |  Answer string:    1  
Step 3:   Answer string has only 1 digit, there need to be 2 digits behind the decimal. Add zero to beginning of the answer string 
          Answer string: 01
Step 4.        .01      | add zero in front of the decimal for formatting | answer string = 0.01
Answer:  0.1 * 0.1 = 0.01

Example: 9.125 x 33.100
Step 1:   (3 digits behind the decimal in A) + (1 digits behind the decimal in B) = (4 digits behind the decimal needed in the answer string)
Step 2:   9125 x 331 = 3020375 |  Answer string:    3023075  
Step 3:   Answer string has more digits than the total digits needed to be behind the decimal. No need to modify. 
          Answer string: 3020375
Step 4.        302.0375    
Answer:  9.125 * 33.100 = 302.0375

Example: 152 x 239.55
Step 1:   (0 digits behind the decimal in A) + (2 digits behind the decimal in B) = (2 digits behind the decimal needed in the answer string)
Step 2:   152 x 23955 = 3641160  |  Answer string:    3023075  
Step 3:   Answer string has more digits than the total digits needed to be behind the decimal. No need to modify. 
          Answer string: 3641160
Step 4.        36411.60 | remove trailing zero for formatting | answer string is 36411.6   
Answer:  152 * 239.55 = 36411.6

With the formula above put in perspective, calculating the decimal values in a multiplication procedure can be done through indexing the decimal. This method is more of a string manipulating method. The placement for the decimal is calculated before calculating any actual value. In my opinion, this method is the simplest method for calculating the decimal for any multiplication procedure, and this method offers the best precision placement for the decimal value as this method calculates the exact spot the decimal have to be placed at in the answer string.

Besides the formula, we still have shortcuts. Any numbers multiply by one will return itself as the value and any numbers that multiply by zero will always be zero. There is another shortcut that I do not apply to this formula and that is any number that multiplied to a .1 or .01 and so on will only need the decimal placement to be moved over to the left.

Nevertheless, let us look at some code block that we would need for our multiplication procedures with decimal supported. In R Programming language I couldn’t find a suitable function that can search for the index of the decimal. Therefore I wrote my own function. We do have the grepexpr() function in R to search for an index. However, when tested the grepexpr() function, the function will produce “1” as the placement if the match string is found at both the first and second position on the left side of the string.

This code block below is my function for searching the index of the decimal. For every while loop, I read both sides of the string, if the position within the string is found with a match the while loop will not execute in the next loop. This function will only look for one index and will exit. If a match is found on both side of the string in the same loop, the function will return the position on the left side of the string.

searchPos <- function(match, string){
     i <- 1
     len <- nchar(string) + 1
     halflen <- len / 2 + 1
     while (i < halflen && substr(string,i,i) != match && substr(string, len - i, len - i) != match){
          i <- i + 1
     }
     return(ifelse(substr(string, i, i) == match, i ,
            ifelse(substr(string, len - i,len-i) == match, len - i, -1)))
}

For the first procedure, we will need to search for the decimal in both our A string and B string. If the decimal is found, we need the position of the decimal. If the decimal is not found within the string, it is preferable that we will get a “-1” as the value for our variable. We are also declaring a position variable to later calculate the decimal position for our answer string.

aDecPos <- searchPos(".",a)
bDecPos <- searchPos(".",b)
oDecPos <- 0

To calculate how many digits behind the decimal in either our A or B string, we are subtracting the total length of the string to the decimal position in the string. Before getting the decimal position we have to remove any trailing zero in the string. This is why it is important that this code block below only executed if a decimal is found. Since we are removing trailing zeroes, we can have issues with strings that contains only zero digits behind the decimal. Thus if the total length of the string minus the decimal position go into the negative we have to set the value to zero. Zero also mean, there is not a digit behind the decimal.

After we calculated the number of digits that are behind the decimal in the string, we are also removing the decimal. This code block below is demonstrating the previous procedures.

if (aDecPos > -1){
     a <- gsub("0+$", "", a)
     aDecPos <- ifelse( ((nchar(a) - aDecPos) > 0), (nchar(a) - aDecPos) , 0)
     a <- gsub("[.]", "", a)
}

Since we removed the decimal and any trailing zero, if we want to use the shortcut of anything multiply by one will return itself as an answer, we would have to modify our code block for the shortcut procedure. This code block below will only execute if A string contained only a digit one and A string does not contain any digits behind the decimal. If we found that B string does, in fact, contained a decimal before this loop started, we placed the decimal back into B string at the correct position before we return B as the result.

To put the decimal into the correct position for B string, we get the digits from the zero position to the digit where the decimal is going to be placed. To calculate where the decimal is going to be placed, we get the total length of string B and subtract the value to the amount of digit B has after the decimal. We then add the decimal into the string and then we add the digits from where the decimal is placed to the end of the string. After placing the decimal and if the first character in B string is only the decimal, we can place a zero in front of the decimal. This is to correct input format such as “.123” or “.5774” or “.1111”.

After that, we check if A and B are different in positive and negative value. If they are, we can place a negative sign in front of B string and then we return B as our result. If B does not contain a decimal value, we simply return B. We also have to check for differences in negative and positive values in both A and B string. This code block below demonstrated the above procedures.

if (grepl(a, "1") && aDecPos < 1 ){
     if (bDecPos > 0 ){
          b <- paste(substr(b, 0,nchar(b) - bDecPos), "." ,substr(b, nchar(b) - bDecPos + 1, nchar(b)), sep="")
          b <- ifelse(substr(b,1,1) == ".", paste("0", b, sep="") , b)
          return(ifelse((isaNeg != isbNeg), paste("-", b, sep="") , b))
     }	      
     return(ifelse((isaNeg != isbNeg), paste("-", b, sep="") , b))
}

After evaluating all the shortcuts for a multiplication procedure, we can then calculate the amount of digit we need to have behind the decimal in our answer string. This code block will only execute if either A or B was found with a decimal. If A is found with a decimal and B did not contain a decimal, the value for variable bDecPos would be a -1. Therefore if there was not a decimal in B we can set bDecPos as zero value. It’s would also mean, there is not a single digit behind the decimal in B string. We can then add up the total amount of digits behind the decimal in both A and B string together to get the total amount of digits that would need to be behind the decimal in our answer string. This code block below demonstrates the above procedures.

if (aDecPos > -1 || bDecPos > -1){
     aDecPos <- ifelse(aDecPos > -1 , aDecPos , 0)
     bDecPos <- ifelse(bDecPos > -1 , bDecPos , 0)        
     oDecPos <- aDecPos + bDecPos
} 

After the multiplication procedure and when we have an answer string, we can evaluate and place the decimal at the correct position in our answer string. We first check to see whether if our answer string contained fewer digits than the amount of digit that would need to be behind the decimal. This scenario occurs in events where “0.01 x 0.01” or “0.3 x 0.3” and so on.

To produce a new answer string with a decimal placement, we would grab the digits from the first position from the left side of our answer string to where the decimal is going to be placed. We then add the decimal behind these digits. After adding the decimal into the correct position, we add the rest of the digits in our answer string to the right side of the decimal. This new string’s value is now assigned as our answer string. To calculate where the decimal is going to be placed, we would need to subtract the length of our answer string to the amount of digit needed to be behind the decimal.

We then trim off any leading and trailing zero in our answer string. If the decimal is the last character in the string and there is not a digit behind the decimal, we would also remove the decimal. If the decimal is the first character in our answer string, we would place a zero in front of the decimal.

This code block below demonstrates the previously mentioned procedure in R Programming Language.

if ( oDecPos > 0 ){
     output <- ifelse((nchar(output) < oDecPos), paste("0", output, sep=""), output);
     output <- paste(substr(output, 0, nchar(output) - oDecPos), "." ,substr(output, nchar(output) - oDecPos + 1, nchar(output)), sep="")
     output <- gsub("^0+", "", output)
     output <- gsub("0+$", "", output)
     output <- gsub("[.]+$", "", output) 
     output <- ifelse( substr(output,1,1) == '.' , paste("0", output, sep="") , output)
} 

This below is the fully functional code for this article which written for R Programming language. The code is capable of calculating numbers which can contain more than thousand of digits with precise decimal calculation.

Advertisement

# Written by Kevin Ng
# The full tutorial on this subject can be found @ http://kevinhng86.iblog.website 
# This source code file is a part of Kevin Ng Z library.
# To use this source code in your project please give the copyright credit.
# This function only multiply and does not check to see if it is only number in the string, you must build a checker around it.
# Notice: Version one and two of any infinity code from the libZ library are prototype.
#         They are not meant for production environment due to efficentcy.
#         Although are prototype these script were tested and ran through 300,000+ test cases without producing any errors.
#         This is version two of infinity multiplication for R, with precise decimal calculation.


infiX <- function (a, b){     
    # This function is to be use until R platform have a search POS that is not grepexpr.
    # If grepexpr found a match on the first position of the string or the second on the left side, it will treat both position as position one.
    searchPos <- function(match, string){
        i <- 1;
        len <- nchar(string) + 1;
        halflen <- len / 2 + 1;
        while (i < halflen && substr(string,i,i) != match && substr(string, len - i, len - i) != match){
            i <- i + 1;
        }
        return(ifelse(substr(string, i, i) == match, i ,
                 ifelse(substr(string, len - i,len-i) == match, len - i, -1)));
    }
    
    
    isaNeg <- ifelse(substr(a,1,1) == "-", 1 , 0);
    isbNeg <- ifelse(substr(b,1,1) == "-" , 1 , 0);       
    a <- gsub("^[+-]+", "" , a);
    b <- gsub("^[+-]+", "" , b);   
    a <- gsub("^0+", "", a);
    b <- gsub("^0+", "", b); 
   
    aDecPos <- searchPos(".",a);
    bDecPos <- searchPos(".",b);
    oDecPos <- 0;
    
    if (aDecPos > -1){
        a <- gsub("0+$", "", a);
        aDecPos <- ifelse( ((nchar(a) - aDecPos) > 0), (nchar(a) - aDecPos) , 0);
        a <- gsub("[.]", "", a); 

    }
    
    if (bDecPos > -1){
        b <- gsub("0+$", "", b);
        bDecPos <- ifelse( ((nchar(b) - bDecPos) > 0), (nchar(b) - bDecPos) , 0);
        b <- gsub("[.]", "", b); 
    }  
   
    if ( (nchar(a) < 1 || nchar(b) < 1 ) ){
        return("0");    
    }
    
    if ( grepl(a, "1") && aDecPos < 1 ){
        if ( bDecPos > 0 ){
            b <- paste(substr(b, 0,nchar(b) - bDecPos), "." ,substr(b, nchar(b) - bDecPos + 1, nchar(b)), sep="");
            b <- ifelse(substr(b,1,1) == ".", paste("0", b, sep="") , b);
            return(ifelse((isaNeg != isbNeg), paste("-", b, sep="") , b));
        }          
        return(ifelse((isaNeg != isbNeg), paste("-", b, sep="") , b));
    }
    
    if (grepl(b, "1") && bDecPos < 1){
        if (aDecPos > 0){
            a <- paste(substr(a, 0,nchar(a) - aDecPos), "." ,substr(a, nchar(a) - aDecPos + 1, nchar(a)), sep="");
            a <- ifelse(substr(a,1,1) == ".", paste("0", a, sep="") , a);
            return(ifelse((isaNeg != isbNeg), paste("-", a, sep="") , a));
        }          
        return(ifelse((isaNeg != isbNeg), paste("-", a, sep="") , a));
    }

    if (aDecPos > -1 || bDecPos > -1){
        aDecPos <- ifelse(aDecPos > -1 , aDecPos , 0);
        bDecPos <- ifelse(bDecPos > -1 , bDecPos , 0);        
        oDecPos <- aDecPos + bDecPos;
    }
    
    temp <- 0;
    outposition = 0;
    alen <- nchar(a);
    blen <- nchar(b);
    output <- "";

    for ( i in blen:1){
        y <- strtoi(substr(b,i,i));
        carryOverM <- 0;
        outtemp <- "";
        aidx = alen;

        while (aidx > 0){
            temp <- strtoi(substr(a,aidx,aidx)) * y + carryOverM;
            carryOverM <- ifelse(temp > 9 , strtoi(gsub("\\d{1}$", "" , toString(temp)))  , 0);
            outtemp <- paste(toString( substr(toString(temp), nchar(toString(temp)), nchar(toString(temp))) ), outtemp , sep="");
            aidx <- aidx - 1;
        }       

        outtemp <- ifelse(carryOverM > 0, paste(toString(carryOverM) , outtemp, sep="") , outtemp);
    
        if (nchar(output) < 1){
            output <- outtemp;
            outtemp <- "";
            outposition <- outposition + 1;
        } else {
            tempadd <- 0;
            carryOverA <- 0;
            outlen <- nchar(output);
            outidx <- 0;
            cposition <- 0;
            tempaddstr <- "";

            for (idx in nchar(outtemp):1){
                cposition <- (outlen - outidx - outposition);
                x <- strtoi(substr(outtemp,idx,idx));
                y <- ifelse(cposition > 0 , strtoi(substr(output,cposition,cposition)) , 0);
                tempadd <- x + y + carryOverA;
                carryOverA <- ifelse(tempadd > 9, 1 , 0);
                tempaddstr <- paste(  toString( substr(toString(tempadd), nchar(toString(tempadd)), nchar(toString(tempadd))) ) , tempaddstr, sep="");
                outidx <- outidx + 1;

            }

            tempaddstr <- ifelse(carryOverA > 0, paste(toString(carryOverA) , tempaddstr, sep="") , tempaddstr);
            output <- paste(tempaddstr, substr(output,  nchar(output) - outposition + 1 , nchar(output) ), sep="");
            outtemp <- "";
            outposition <- outposition + 1;
        }        
    }
    
    if (oDecPos > 0){
        output <- ifelse((nchar(output) < oDecPos), paste("0", output, sep=""), output);
        output <- paste(substr(output, 0, nchar(output) - oDecPos), "." ,substr(output, nchar(output) - oDecPos + 1, nchar(output)), sep="");
        output <- gsub("^0+", "", output);
        output <- gsub("0+$", "", output);
        output <- gsub("[.]+$", "", output); 
        output <- ifelse( substr(output,1,1) == '.' , paste("0", output, sep="") , output);
    } 
    
    if (isaNeg != isbNeg){
        output <- paste("-", output, sep="");
    }

    return(output);
}

x = ".99999999999999999999999999";
y = "-.99999999999999999999999";

c = infiX(x,y);
print(c);

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 – Decimal, Precise Float Calculation – R".
Original Post Link: http://kevinhng86.iblog.website/2017/02/14/working-with-number-infinity-multiplication-decimal-precise-float-calculation-r/.

Advertisement


Random Article You May Like

Leave a Reply

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

*
*