[Back to

 previous page] [Next Page

 in Series]

Ken Ward's Java Script Tutorial ...

Long Numbers - Adding

This is the start of a series that deals with doing arithmetic with big numbers. It is really about how you can do arithmetic with numbers bigger than those which, in this case, JavaScript can do, which is about 17 digits.

This study aims to add one big number to another. The script will only add two positive numbers. This is actually logical because otherwise, it would have to do subtraction, which is the subject of the next page.

I do not claim the code is well written or optimum: only that it is believed to work.

document.write(String(Math.PI).length)

//gives 17

The maximum array size is 4,294,967,295, which means that some billions of digits in base 10 can be manipulated. Of course, we aren't limited to base 10, and can use much bigger bases and therefore potentially bigger numbers. But the practicality of this depends on the browser, computer, etc.

Precision and Accuracy

These are two useful words. Precision relates to the number of digits that are shown and accuracy relates to the degree the number relates to the true value. So 1/3=0.334444 is more precise (more digits) than 1/3=0.333, but less accurate.

Example

This page is likely to be of interest to only a few people who are interested in numbers. Writing the code was somewhat difficult, and took some time.

The secret, if there is one, is that while numbers are limited in the number of digits which can be displayed, strings and arrays aren't so limited. What we need to do is to put our numbers into strings or array and do our sums on them.

This page deals with adding and the code can add very large numbers. I don't know the largest size of numbers which you can add, but it is probably limited by your computer, rather than anything else.

The following demonstrates the code on this page. Enter a number in both boxes and click on the add. You can check the accuracy using normal pencil and paper arithmetic. Or get an idea from window's calculator.

Number 1:

Number 2:


Numbers appear here


While the example numbers aren't that big, (I didn't make them too big because they become difficult to read on the page) but you can enter numbers of any size.

The first thing you may notice is that the font for the numbers is a bit funny, being "monospace". The reason for this is so the numbers can be formatted in our example. It is nearly impossible to do this with a regular font because the type characters can vary so much from font to font, and also in any practical use, our formulas would return a number and not a formatted example as above.

Another thing you might notice is that the numbers are formatted with comma separators. Of course, the Germans use commas where the English use dots, and the French use spaces where the English use commas.

Also you may notice that if you enter non-numerical characters or more than one decimal, then you get an error message. To deal with these issues properly, it would have been better to control the characters that can be typed into the boxes so the user cannot make errors. However, the main purpose of this page is to deal with long numbers and formatting and error correction are secondary.

Removing Any Spaces And Commas

Before doing anything like calculation, I first removed any spaces or commas (separators) in the original numbers. I used the following function:

function removeCommas(aNum) {

//remove any commas

aNum=aNum.replace(/,/g,"");

//remove any spaces

aNum=aNum.replace(/\s/g,"");

return aNum;

}//end of removeCommas(aNum)

The above function uses regular expressions with "replace" to clean up the numbers. It removes any spaces and commas in the original numbers.

Recording The Decimal Positions

The way I decided to add the numbers was to add zeros to the one with the least decimals and then to add them as regular numbers without any decimals. I had therefore to record the original decimal positions so I could put them back at the end.

To do this I used the following function:

function getDec(x) {

x=x+"";

//position of first decimal digit

pos=x.indexOf('.')+1;

//if 0, then no decimals (-1+1)

if (pos>0)

return x.length-pos;

else

return 0;

}//end of getDec(x)

The length of the number in the code above includes the decimal point, but when I come to put the decimal back, the length will be one less.

When we remove the decimal point, we are effectively multiplying the number by however decimal places there were in the number with the number with the most decimal places. Later of course, we will replace the decimal point in the correct position. But for now, we need to add zeros to the number with the least decimal places.

Adding Zeros

This is the code that adds the zeros:

//initialise decPlace, which is the number of decimals in

//the number with the most decimals

//First just assume x is the number with most decimal places

//We are just declaring the variable, so any number could be used.

var decPlace=decX;

//Then check which is the correct number

if (decX>decY)

{

decPlace=decX;

//add zeros to y

//the number of zeros is just the difference between the number of

//decimal places in each number.

//decYo is the number of decimals in the original y number.

for (var i=0;i<(decPlace-decYo);i++)

{

//add a zero at the end

y+="0";

//increment decY, so we keep a record of the decimal position

//in the new number. For instance

// if decYo=2, as in 112, then the number is really 112/10^2

//When we add zeros, the position becomes one more

//for each zero we add .. 1120, decimal is now 3 from the end, or

//the number is really 1120/10^3

decY+=1;

}

 

}

//add zeros to x, if y has more decimals

//repeat of the above

else

if (decY>decX)

{

decPlace=decY;

//add zeros to x

for (var i=0;i<(decPlace-decXo);i++)

{

x+="0";

decX+=1;

}

}

In this code, the variable x always contains the longer number. Therefore, if y is longer after the above process, we swap the two variables so that x is the longer number and y is the shorter number.

Swap Numbers

We use the following code to swap the numbers, if x isn't longer than y.

//find the length of the numbers, so we can put them in the right

//order for the calculation

xlen=x.length;

ylen=y.length;

//swap the numbers, if xlen isn't the longest

if (xlen<ylen)

{

//swap values

var temp=y;

y=x;

x=temp;

temp=decX;

decX=decY;

decY=temp;

 

}

//set new lengths

var xlen=x.length;

var ylen=y.length;

The Adding - Back To Junior School

This is the main code, and is what this page is really about. The algorithm is the one used in the junior school (England) or gradeschool (USA). That is, you line the numbers up according to the decimal point and, starting at the right, add the numbers, and if the answer is bigger than ten, add the carry digit to the next number. Unlike the calculators used later in school, this algorithm works for any numbers, however big.

//begin adding

//set carry to zero.

var carry=0;

//set the string, s, which will contain the answer

var s="";

//now add the two numbers:

//work from the right to the left, starting at the length of the longest string:

//which is always x in this code

var numx,numy;

//numx and numy will hold the digits in each number to add

for (var i=xlen-1;i>=0;i--)

{

//only add the y numbers, if there are any left, else we add zero

numy=0;

if ((ylen-xlen+i)>-1)

numy=parseInt(y.charAt(ylen-xlen+i));

//In the above, when ylen-xlen+i=0, we are at the end of the y numbers

//and i=xlen-ylen. For the next i, (i-1), we will be beyond the length of y, and

//so just add a possible carry in the next place, and thereafter, add only zeros

//to the longer number, x

//x is always the longest string

numx=parseInt(x.charAt(i));

//add the sum of the numbers and any carry from previously

//we add only the units bit of the number

//10 is the normal base for decimals

s=(numy+numx+carry)%10+s;

//we carry the tens bit of the new number

carry=Math.floor((numy+numx+carry)/10);

}//end of adding

if (carry>0)

s=carry+s;

/*

at the end of the first number, x, we might still have something to carry

For instance, 9+9 gives 8, plus a FINAL carry of 1 (in a new place)

 

  9+
  9=
18

But:

18+
  9
27

... has a normal carry one place from the end, but no carry at the end (1+1 (carry)=2, no carry

so we add any carry on the front of the string

*/

Essentially, that's it! We add the two numbers, however, big, and get our answer in the string, s. All that remains is to write out the number. This is only necessary because the code is a demonstration of adding long numbers, and it seems that the output should be nicely formatted. As a function to work out sums, it doesn't need such niceties. These niceties are, however, useful in other applications. Naturally, adding the decimal points is essential.

Adding Decimals and Formatting

In the code below, we add the decimal points as necessary and also comma separators for the non-decimal numbers. For this, we use functions. Lastly, we swap the numbers, if necessary to ensure x is the longest number:

//put the decimals back in the numbers

s=insertDec(s,decPlace);

//now write out the answer:

x=insertDec(x,decX);

y=insertDec(y,decY);

x=addseps(x);

y=addseps(y);

//once again check the lengths of the two numbers.

//swap numbers

//find the length of the numbers, so we can put them in the right

//order for the calculation

xlen=x.length;

ylen=y.length;

//swap the numbers, if xlen isn't the longest

if (xlen<ylen)

{

//swap values

var temp=y;

y=x;

x=temp;

temp=decX;

decX=decY;

decY=temp;

//new lengths, if x is shorter

//could have just swapped them as above!

xlen=x.length;

ylen=y.length;

}

//end of swapping

Insert The Decimal Point

The following function inserts the decimal point:

function insertDec(num,decPlace) {

var num=num;

var decPlace=decPlace;

ans="";

if (decPlace>0)

{

for (var i=0;i<num.length;i++)

{

//when we get to the position we want to

//insert the decimal point, we add the point to

//our string

//decPlace is the number of decimal digits in the original, from getDec(x)

//remember the return value of this function was return x.length-pos;

if (i==num.length-decPlace)

ans=ans+"."+num.charAt(i);

else

ans=ans+num.charAt(i);

}

return ans;

}

else

return num;

}//end of insertDec(x,decPlace)

Format the Number With Commas

Having put the decimal points back into the number, we will add commas to separate the thousands. The following function puts the commas in. (With slight modification, it could add dots or spaces to suit the Germans or the French).

function addseps(x) {

//make x a new variable

var x=x;

//make x a string

x+="";

//or x=String(x);

//iLen is the number of digits before any decimal point

// for 45.123, iLen is 2

//iLen is the length of the number, if no decimals

iLen=x.length;

pos=x.indexOf(".");

if (pos>-1) //there are decimals

{

iLen=pos;

}

//add the decimal point

temp="";

//add the decimal part to begin

// with 45.123, we add the .123

temp=x.substring(iLen,x.length);

//iLen-1 is the rightmost non-decimal digit (5 in 98745.123)

for (var i=iLen-1;i>=0;i--)

//we add a separator when the expression (iLen-i-1)%3==0 is true...

//except when i is (iLen-1), or the first digit

//eg (98745.12). i is iLen-1, and the digit pos is next the decimal,

//it is 5. From here, we decrement i...iLen-2, iLen-3, iLen-4 ... when i is a multiple of

//3, (i=iLen-iLen+4-1). This point is just before the number 7

if ((iLen-i-1)%3==0&&i!=iLen-1)

temp=x.charAt(i)+","+temp;

else

temp=x.charAt(i)+temp;

return temp;

}//end of addseps(x)

The code above is heavily commented. Even so, it might require careful study.

Aligning the Numbers

The sum is written using a monospace font, because the width of numbers in regular fonts is extremely variable. So a typerwiter font was used.

The place where the writing is done is written like this:

<span class="mon" id="s1">Numbers appear here</span>

And the class "mon" is:

<style type="text/css">

<!--

.mon{font-family:monospace}

-->

</style>

Here I used monospace, but there are many typewriter fonts which would suit.

In putting in some spaces, I first added some spaces infront of the smaller number, y, so it was the same length as the longer number x. Secondly, there was the possibility that the answer might be one longer than the number x, so this had to be allowed for.

Aligning y to x is easily achieved as below:

//align the numbers by putting a space infront of the shortest number

for (var i=0;i<(xlen-ylen);i++)

y="&nbsp;"+y;

And making the two numbers x and y align with the answer is equally easy:

//the answer string s, can only be one more longer than the x string

//but we will write general code anyway

//note, we cannot use y or ylen anymore because y contains "&nbsp;

//which is 6 characters, creating one space!

s=addseps(s);

var slen=s.length;

for (var i=0;i<(slen-xlen);i++)

{

x="&nbsp;"+x;

y="&nbsp;"+y;

}

Finally, this writes out the sum:

document.getElementById("s1").innerHTML=(x)+"+<br><u>"+(y)+"</u>=<br>"+s+"<br>Javascript calculates: <br>"+jssum+"<br>";

Checking the Numbers

The following code checks that the two numbers entered are numbers with at most one decimal point:

function checkNum(aNum) {

var isOK=0;

var aNum=aNum+"";

//if the number has one or none decimal points, lastIndexOf and indexOf

//will give the same answer

if (aNum.lastIndexOf(".")!=aNum.indexOf("."))

isOK=1;

else

//here a regular expression is used to check for numbers and decimals

if (aNum.match(/[^0-9.]/))

isOK=2;

return isOK;

}//end of checkNum(aNum)

The function is used as follows:

if (!((checkNum(x)==0)&&(checkNum(y)==0)))

{

if (checkNum(x)>0)

{

switch (checkNum(x)) {

case 1:

alert("Too many decimal points in number 1.")

break

case 2:

alert("Some characters aren't numbers in number 1");

break

}//end of switch

}//end of check number 1

if (checkNum(y)>0)

{

switch (checkNum(y)) {

case 1:

alert("Too many decimal points in number 2.")

break

case 2:

alert("Some characters aren't numbers in number 2");

break

}//end of switch

}//end of check number 1

}//end number problem

Note how we try to explain what the problem with the number is so the user has some idea what to do to correct the error.

The next page deals with subtraction.