|
Long Numbers - Subtracting
In the previous page, we did a study on adding two long
numbers. In this page, we will do the same for subtracting two long numbers. As with
addition, there is no particular limit on the size of numbers you can use, apart from the
capability of your system. This page deals with subtracting two positive
numbers.
On this page:
Subtraction is more difficult than addition. In part because the order in which the
numbers are processed is important, whereas it isn't in addition. In subtraction, if the
order is changed, the sign of the answer changes too.
In subtraction, the bigger number is always subtracted from the smaller one: the answer
is negative if we take a smaller number from a smaller one.
One problem that arose was when the two numbers were identical so far as javascript was
concerned, so finding the smaller number required special handling. This page was harder
to write than the ones on addition and long multiplication. Dividing a long number by a number
which was in javascript's range was the easiest of all!
The form below allows you to enter numbers and subtract them. The random buttons are a
means of entering longish numbers without too much trouble. The answer is checked by
casting out nines, which was useful when developing the code and made the need for various
mental checks unnecessary. So, try out the code with the form below:
One thing of interest is that javascript sometimes gives unexpected answers. For
instance:
1.0145800-
1.1058100=
-0.0912300
Ans check OK
Javascript calculates:
-0.09122999999999992
The answer given by the script is clearly accurate, but javascript's answer is very
slightly incorrect by the miniscule 8.0 x 10-17.
While developing the script, it was useful to check the answer. The code used is:
function checkAnsSub(x,y,ans) {
ok= false;
//use casting out nines
a=Number(digSum(x))-Number(digSum(y));
The function digSum
is explained below. It adds the digits and casts out the nines.
b=digSum(ans);
//these should be the same (a=b), but sometimes a zero is left after
casting out nines
//and sometimes not. Also, a negative answer needs to have a 9 added
//if negative or zero, add 9
if (a<=0)
a+=9;
a=a%9;
//if y is bigger, then the answer is negative. We take y from x and call
it negative
//the check needs to be subtracted from 9
if (Number(x)<Number(y))
//this won't work when the numbers are the same within the range of
javascript
//because they appear equal
// however, we fix this later.
{
a=9-a;
}
//cast out any remaining nines
a=a%9;
//mess+=("a="+a+"; digSum x="+digSum(x)+"; digSum
y="+digSum(y)+"; digSum ans="+b);
//now we can do our check
if (a ==b)
ok= true;
if (ok)
return true
else
return false;
} //end of checkAns(x,y,ans)
//add the digits to get the digital sum for casting out nines
function digSum(num)
{
//just make sure the number is a string and doesn't have a minus sign
num=String(num);
num.replace(/-/, "");
//mess+="num="+num+"<br>";
//sum is the sum of the digits
sum=0;
for (i=0;i<num.length;i++)
{
//if there is a decimal, we just ignore it
if (num.charAt(i)==".")
continue
else
sum+=Number(num.charAt(i));
//mess+="charAt"+i+"="+num.charAt(i)+";
sum="+sum+"<br>";
}
//cast out nines
return sum%9;
} //end of checkAns(x,y,ans)
This was just a convenience for checking the script. It saved typing numbers randomly.
//used for checking and putting a number in
at random
function myRand() {
z= "";
s= "";
//generate a random number and remove the decimals
//random numbers are between 0 and 1
a=Math.random()* Math.pow(10,16);
b=Math.random()* Math.pow(10,16);
a=String(a).replace(/\./g, "");
b=String(b).replace(/\./g, "");
//join the two strings together
z=String(a)+String(b);
//add a decimal point at random
decPoint=Math.floor(Math.random()*Number(z.length));
z=z.substring(0,decPoint)+ "."+z.substring(decPoint,z.length);
if (decPoint==0)
z= "0"+z;
return z;
} //end of myRand()
The following two functions remove commas and spaces from the numbers and check the
numbers consist of digits (and a decimal) and contain only one decimal point.
function removeCommas(aNum) {
//remove any commas
aNum=aNum.replace(/,/g, "");
//remove any spaces
aNum=aNum.replace(/\s/g, "");
return aNum;
} //end of removeCommas(aNum)
//this checks whether the number
entered does not have several decimals
//or non-numeric characters
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 subtraction is done on two integer numbers, so the decimal points are removed from
the numbers. We need to record where they were so we can correctly write out the answer.
The function, getDec(x) does this.
//find decimal point position
function getDec(x) {
var x=x;
//ensure x is a string
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 sign for the answer is determined by this function:
function signSwap(x) {
if (x=="+")
x= "-";
else
x= "+";
return x;
} //end of signSwap(x)
This long section of code, which is heavily commented, does the subtraction. A lot of
this code is related to formatting, etc. Just as error checking also forms a largish part
of the code in general. That is, ten percent of the code does the biz and the remaining
90% catches errors and formats.
function Sub(x,y) {
var x=x;
var y=y;
var x0=removeCommas(x);;
var y0=removeCommas(y);
var sign="+";
//sum used for javascript
x=removeCommas(x);
y=removeCommas(y);
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
else //numbers check out
{
//this is used as a broad check of
the answer
jssum=Number(x)-Number(y);
//decXo, and decYo are the orignal decimal positions
//as zeros are added to the numbers, the decimal position will change, so
we store the
//originals in these values
decXo=getDec(x);
decYo=getDec(y);
decX=decXo;
decY=decYo;
str= "";
//remove any decimal from x
//there will be at most one, because
we have checked for too many decimals earlier
x=x.replace( ".","");
//remove any decimal from y
y=y.replace( ".","");
//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
//If decX is longer than decY, then the following will be true
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.
//we effectively multiply by a number
big enough to remove the decimals from x
//and we add compensating zeros to y, so we have two
integers to subtract
for (var i=0;i<(decPlace-decYo);i++)
{
//add a zero at the end
y+= "0";
decY+=1;
//increment decY, so we keep a record of the decimal position
//in the new number. For instance
// if decYo=2, as in 1.12, then the number is really 112/10^2
//When we add zeros, the position becomes one more
//for each zero we add .. 1.120, decimal is now 3 from the end, or
//the number is really 1120/10^3
}
}
// if y has more decimals than x...
//add zeros to x,
//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;
}
}
//otherwise, decPlace is what we said above (x and y have the same number
of decimals)
//swap the numbers if y is bigger
than x
//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)||(Number(x)<Number(y)))
{
//sign is used in the answer
sign=signSwap(sign);
//swap values
var temp=y;
y=x;
x=temp;
//swap decimal position values
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
//begin subtracting
//set carry to zero.
var carry=0;
//set the string, s, which will contain the answer
var s="";
//now add the two numbers:
//work down from the length of the longest string:
//which is always x
var numx,numy;
for (var i=xlen-1;i>=0;i--)
{
numy=0;
if ((ylen-xlen+i)>-1)
numy=Number(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
//x is always the longest string
numx=Number(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
if (numx<(numy+carry))
{
numx+=10;
carry1=1;
}
else
carry1=0;
s=(numx-(numy+carry))%10+s;
if (carry1>0)
carry=carry1;
else
carry=0;
//we carry the tens bit of the new number
//carry=Math.floor((numy+numx+carry)/10);
if (s.length>x.length)
{
}
} //end of subtracting
//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);
//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)
{
sign=signSwap(sign);
//swap values
var temp=y;
y=x;
x=temp;
//swap decimal positions
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
// check answer
aCheck= ''
if (checkAnsSub(x0,y0,s))
aCheck= "<br>"+"Ans check
OK<br>";
else
{
//this is assumed to be when the numbers are so
//similar that javascript can't tell which is the bigger
//number. As the answer check fails, we assume
//the numbers should be the other way round.
//we work out the answer again, and put it in s2
// we compute the base 10 complement of the
//number.
sign=signSwap(sign);
s2= ""
for (i=0;i<s.length;i++) {
if (s.charAt(i)==".")
{
s2+= ".";
continue ;
}
if (i==s.length-1)
s2+=10-Number(s.charAt(i));
else
s2+=9-Number(s.charAt(i));
} //end of for statement
s=s2;
//swap x and y
temp=y;
y=x;
x=temp;
//we give up on checking and honestly say we haven't checked the answer
//checked the number.
aCheck= "<br>Answer has
not been checked<br>";
} //else number doesn't check
//end check answer
//remove leading zeros from answer:
while (s.charAt(0)=="0")
{
s=s.substring(1,s.length);
}
//we keep a zero if the number is purely decimal
if (s.charAt(0)==".")
s= "0"+s;
//align the numbers by putting a
space infront of the shortest number
for (var i=0;i<(xlen-ylen);i++)
y= " "+y;
//note, we cannot use y or ylen
anymore because y contains "
//which is 6 characters, creating one space!
//sign makes s positive or negative, as appropriate
s=sign+addseps(s);
var slen=s.length;
//pad out x and y so they line up with their decimals and the
//answer
for (var i=0;i<(slen-xlen);i++)
{
x= " "+x;
y= " "+y;
}
//finally, we put the numbers back in the right order,
//if y was bigger than x numerically, and the answer is negative
if (sign=="-")
{
temp=x;
x=y;
y=temp;
}
ans=s;
document.getElementById( "s1").innerHTML=(x)+"-<br><u>"+(y)+"</u>=<br>"+s+aCheck+"Javascript
calculates: <br>"+jssum+"<br>"+mess;
} //end of else (numCheck OK)
} //end of Sub(x,y)
Commas separators are used for the thousands in a number. It is easy to change this for
French or German systems.
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 next study is multiplication of two long numbers.
|
|