03-06-2016, 04:25 PM

I have been playing around with the Arduino port of the BigNumber library with a view to improving the accuracy of my RPN-duino calculator project. Forum member, Securd, flagged up the usefulness of this arbitary precision number handling tool in his write-up of his Spikenzielabs calculator kit based project.

The BigNumber library comes with some example code, so right away you are up and running with LNx, EXPx and SINx. COSx and TANx functions are then a cinch to code. An efficient ARCTAN is the next crucial issue as it is a simple step to produce ARCSIN and ARCCOS functions from the relevant inverse trig identities.

My first shot at ARCTAN was via a straightforward implementation of the Taylor series for this function. The problem with this technique is, that for x values close to 1, the series is very weakly convergent, requiring a huge number of terms for decent accuracy. Remembering an iterative approach to calculating square roots by repeated refinement of a first guess, I wondered if the same could be done with ATAN, given an available fast and accurate TAN function for guess refinement. The answer to this is yes:

Note the through the looking-glass world of BigNumber handling!

The basic concept:

the next guess at ATAN (x) improves if the last guess is multiplied by x / TAN(last guess)

For lower values of x, the convergence of p to ATAN(x) is very fast, regardless of first guess used. A guess of 0.8 is a good starting point for values of x closer to 1. The 30 iterations give at least a 1 part in 10^9 ish kind of accuracy for all values of x.

With a complete set of basic scientific functions coded, I was able to run the calculator forensics test on my hack RPN-duino, which produced 8.999999999115. It also gives ATAN(1) as 45.000000041756 degrees.

There are a couple of downsides. Inverse trig is a bit slow, given the need to call TAN 30 times (think Sinclair Scientific). Also, the Arduino Uno is clearly at the limit of stack space (or something) for the layers of function calling required - there have been a few lock ups. That said, the results obtained so far indicate at least a two or three significant figures improvement over the standard c Math function library when it is limited to the 32 bit float type.

The calculator forensic for that case shows as 8.9999876 on my Sunday best RPN-duino.

BTW, I tried the same iterative dodge for a direct implementation of ASIN (x) but it just doesn't perform well enough for values of x close to 1.

The BigNumber library comes with some example code, so right away you are up and running with LNx, EXPx and SINx. COSx and TANx functions are then a cinch to code. An efficient ARCTAN is the next crucial issue as it is a simple step to produce ARCSIN and ARCCOS functions from the relevant inverse trig identities.

My first shot at ARCTAN was via a straightforward implementation of the Taylor series for this function. The problem with this technique is, that for x values close to 1, the series is very weakly convergent, requiring a huge number of terms for decent accuracy. Remembering an iterative approach to calculating square roots by repeated refinement of a first guess, I wondered if the same could be done with ATAN, given an available fast and accurate TAN function for guess refinement. The answer to this is yes:

Code:

BigNumber two = 2; // global declarations: not enough stack headroom for these to live inside the function

BigNumber one = 1;

BigNumber atan(BigNumber x)

{ byte m = 0;

BigNumber p = 0;

p = BigNumber("0.8"); //optimal first guess

BigNumber pi = "3.14159265359";

if (x > one)

{

x = one / x;

while (m < 30)

{

m++;

p = p * x / tan(p);

}

p =pi / two - p;

}

else

{

while (m < 30)

{

m++;

p = p * x / tan(p);

}

}

return p;

}

Note the through the looking-glass world of BigNumber handling!

The basic concept:

the next guess at ATAN (x) improves if the last guess is multiplied by x / TAN(last guess)

For lower values of x, the convergence of p to ATAN(x) is very fast, regardless of first guess used. A guess of 0.8 is a good starting point for values of x closer to 1. The 30 iterations give at least a 1 part in 10^9 ish kind of accuracy for all values of x.

With a complete set of basic scientific functions coded, I was able to run the calculator forensics test on my hack RPN-duino, which produced 8.999999999115. It also gives ATAN(1) as 45.000000041756 degrees.

There are a couple of downsides. Inverse trig is a bit slow, given the need to call TAN 30 times (think Sinclair Scientific). Also, the Arduino Uno is clearly at the limit of stack space (or something) for the layers of function calling required - there have been a few lock ups. That said, the results obtained so far indicate at least a two or three significant figures improvement over the standard c Math function library when it is limited to the 32 bit float type.

The calculator forensic for that case shows as 8.9999876 on my Sunday best RPN-duino.

BTW, I tried the same iterative dodge for a direct implementation of ASIN (x) but it just doesn't perform well enough for values of x close to 1.