Post Reply 
Arduino BigNumber library port and ATAN
03-06-2016, 04:25 PM (This post was last modified: 03-06-2016 07:01 PM by Chasfield.)
Post: #1
Arduino BigNumber library port and ATAN
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:

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.
Find all posts by this user
Quote this message in a reply
03-06-2016, 10:17 PM
Post: #2
RE: Arduino BigNumber library port and ATAN
The 34S uses a different approach.

Reduce range to 0 <= a < 1, using:
atan(x) = pi/2 - atan(1/x)

Then repeatedly apply:
tan(x/2) = tan(x)/(1+sqrt(1+tan(x)^2))
to get the argument under 0.1, this takes at most three iterations.

Apply the Taylor series expansion:
tan(x) = x(1-x^2/3+x^4/5-x^6/7...)
convergence is very rapid due to the small x.

Undo the halving and the range reduction steps.


- Pauli
Find all posts by this user
Quote this message in a reply
03-07-2016, 07:40 AM (This post was last modified: 03-07-2016 07:42 AM by Chasfield.)
Post: #3
RE: Arduino BigNumber library port and ATAN
Thank you for the range scaling tip. That should speed things up for inverse trig.

I tested my guess refinement ATAN approach for x < 0.1. That too is highly convergent in that range, requiring only a handful of iterations when ATAN (x) = x is used as the first guess.

The best option for the Arduino Uno will be whichever is the most stable. I think that will be the one which stacks the least function calls on top of each other. So I will dust off my Taylor series code and make comparisons.
Find all posts by this user
Quote this message in a reply
03-09-2016, 04:01 PM (This post was last modified: 03-09-2016 04:05 PM by Chasfield.)
Post: #4
RE: Arduino BigNumber library port and ATAN
I applied Paul's range reduction and scaling tips to my Taylor series and guess refinement versions of the ATAN function. Taylor wins - ATAN response time is almost instantaneous using 12 terms in the series, though the guess refinement approach was much improved, with only 7 iterations required for good accuracy.

Attached is an RPN-duino screen grab showing the calculator forensic test result in the Y reg and ATAN (1) in the X.

Cheers, Paul


Attached File(s) Thumbnail(s)
   
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: