Go Down

Topic: Found a 64bit double implementation library, but I cannot compile it (Read 1 time) previous topic - next topic

lesto

Code: [Select]
#include "BigNumber.h"

void setup(){
  Serial.begin(115200);
  delay(2000);
  BigNumber::begin ();
  BigNumber::setScale (20);
}

int i=1;
unsigned long time;
void loop()
{
  Serial.println( i );
 
  Serial.print( sin(i) );
  Serial.print(" ");
  printBignum( sine( i, precision ) );
  Serial.println();
 
  Serial.print( cos(i) );
  Serial.print(" ");
  printBignum( cosine( i, precision ) );
  Serial.println();
  Serial.println();
  delay(1000);
  i++;
}

// function to display a big number and free it afterwards
void printBignum (BigNumber n)
{
  char * s = n.toString ();
  Serial.print (s);
  free (s);
}  // end of printBignum


work until -15 <= i <= 15..

using a precision of 10 the range is -7 <= i <= 7

i tryed to change
while (p > 0)

into

while (p > 0.00001)

but nothing to do. I'm having some problem with my ADSL, so it's pretty hard to find alternative algorithm, i hope my adsl will feel better tomorrow  :smiley-mr-green:
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Nick Gammon


directly derive cosine from sine uses less steps:  cosine(x) = sine(x+PI/2); so might be faster?


You are right, but I couldn't get that to work yesterday. But this is why:

Code: [Select]
  BigNumber::begin ();  // initialize library
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
... 
  BigNumber::setScale (20);


Should have been:

Code: [Select]
  BigNumber::begin ();  // initialize library
  BigNumber::setScale (20);
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
... 


It thought pi was 3.

Now cosine can be:

Code: [Select]
BigNumber cosine (BigNumber x, BigNumber p)
{
   return sine (x + pi / BigNumber (2), p);
}  // end of cosine
http://www.gammon.com.au/electronics

Nick Gammon


work until -15 <= i <= 15..


Yes but these are radians, not degrees. You shouldn't have to work outside the range 0 to 2 * pi. After that it just repeats.

Or even the range 0 to pi/2. You just need to force your numbers into that range and swap the sign if necessary.
http://www.gammon.com.au/electronics

lesto

sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Nick Gammon

Make sure you move the definition of pi to be after where it sets the scale, as I discussed above.
http://www.gammon.com.au/electronics

lesto

Ok, my code was already right. Now it us late, tomorrow I'll test my real code, a simple bearing calcolator between two GPS point
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

lesto

thanks everybody, here the solution I'm using:

Code: [Select]
BigNumber sine (BigNumber x, BigNumber p)
{
 while (x > doublePI){//stay in range!
    x -= doublePI;
 }
 
 while (x < 0){//stay in range!
    x += doublePI;
 }
 
 BigNumber one = 1;
 BigNumber two = 2;
 BigNumber val = one;

 while (p > 0)
 {
   val = one - val * x * x / (two * p) / (two * p + one);
   p = p - one;
 }
 val = x * val;
 return val;
} // end of sine

BigNumber cosine (BigNumber x, BigNumber p)
{
 return sine(x+halfPI, p);
}  // end of cosine

BigNumber tangent (BigNumber x, BigNumber p)
{
 return (sine (x, p) / sine (x+halfPI, p));
} // end of tangent


note you will need halfPI and doublePI:

Code: [Select]
BigNumber::begin ();
 BigNumber::setScale (20);
 bigPI = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
 halfPI = bigPI;
 halfPI /= 2;
 doublePI = bigPI;
 doublePI *= 2;


now i'm going to test the real duration of my code at different precision, i'll post here the code and the results. thanks again everybody!!!

edit: it's a honour to talk with the man who wrote this lib. just a little problem (arduino IDE 1.0.1):
Quote
halfPI = PI / 2;

give some error with overloaded constructor. I've work around it because I'm not good with c++  :smiley-mr-green:
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

lesto

tried my code:

Code: [Select]
void run(){
  BigNumber lon1 = BigNumber("12.563545");
  lon1 /= RADS;
  BigNumber lon2 = BigNumber("12.561801");
  lon2 /= RADS;
  BigNumber lat1 = BigNumber("42.857818");
  lat1 /= RADS;
  BigNumber lat2 = BigNumber("42.858689");
  lat2 /= RADS;
  BigNumber a,c;
 
  time = micros();

  BigNumber sinLat1 = sine(lat1);
//  Serial.print("a ");
  BigNumber sinLat2 = sine(lat2);
//  Serial.print("b ");
  BigNumber cosLat1 = cosine(lat1); 
//  Serial.print("c ");

  BigNumber part1a = sinLat1*sinLat2;
//  Serial.print("c1 ");
  BigNumber part1b = cosLat1*cosine(lat2);
//  Serial.print("c2 ");
  BigNumber part1c = cosine(lon1-lon2);
//  Serial.print("c3 ");
  BigNumber part1d = part1a+part1b*part1c;
//  Serial.print("c4 ");
  a = acos(part1d);
 
 
//  Serial.print("d ");
  BigNumber partD1 = sinLat2 - sinLat1;
//  Serial.print("dA:");
  printBignum( a );
//  Serial.print(" ");
  BigNumber partD2 = cosine(a);
//  Serial.print("dB ");
  BigNumber part1 = partD1 * partD2;
//  Serial.print("d1 ");
  BigNumber part2 = (cosLat1 * sine(a));
//  Serial.print("d2 ");
  BigNumber part3 = part1/part2;
//  Serial.print("d3 ");
  c = acos( part3 );
//  Serial.print("e ");
  if ( sine(lon2-lon1)>=0 )
    c=2*M_PI-c;
   
  time = micros()-time;
  cAstro = c;
  dAstro = a;
  Serial.println ("test2:");
//  Serial.print ("distance:");
//  Serial.println ((c*RADS));
  Serial.print ("distance radians:");
  //Serial.println ((c));
  printBignum( c );
  Serial.print("time:");
  Serial.println (time);
}


acosine implementation (very bad precision):
Code: [Select]
BigNumber acosine(float x) {
  BigNumber negate = BigNumber(x < 0);
  if (x < 0){
     x*=-1;
  }
  BigNumber ret = -0.0187293;
  ret *= x;
  ret += 0.0742610;
  ret *= x;
  ret -= 0.2121144;
  ret *= x;
  ret += 1.5707288;
  BigNumber bigSqrt = x-1;
  ret *= bigSqrt.sqrt();
  ret -= 2 * negate * ret;
  return negate * bigPI + ret;
}


execution time (microseconds, precision of 5): 142256 vs 116(using float)
precison of 10: 474288
ram overflow with precision 20
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Nick Gammon


just a little problem (arduino IDE 1.0.1):
Code: [Select]
halfPI = PI / 2;
give some error with overloaded constructor. I've work around it because I'm not good with c++  :smiley-mr-green:


Try:

Code: [Select]
halfPI = bigPI / BigNumber (2);

You can probably cut down the precision of bigPI - that uses RAM and you are hardly going to need all those digits.

Quote
execution time (microseconds, precision of 5): 142256 vs 116(using float)


Yes, I didn't say it was fast. :)

Arbitrary precision libraries tend to be slow by their nature.

Some of your stuff is inefficient:

Code: [Select]
BigNumber negate = BigNumber(x < 0);
  if (x < 0){
     x*=-1;
  }


Why multiply when you can negate?

Code: [Select]
BigNumber acosine(BigNumber x) {
  boolean negate = false;
 
  if (x.isNegative ())
    {
    x -= x;
    negate = true;
    }

  BigNumber ret = -0.0187293;
  ret *= x;
  ret += 0.0742610;
  ret *= x;
  ret -= 0.2121144;
  ret *= x;
  ret += 1.5707288;
  BigNumber bigSqrt = x - BigNumber (1);
  ret *= bigSqrt.sqrt();
  ret -= 2 * ret;
  if (negate)
    return - bigPI - ret;
  else
    return bigPI + ret;
}


Try to keep multiplications down. Subtracting a number from 0 will be faster than multiplying by -1. Also I don't know why you were working on x as a float. Doesn't that throw away the extra precision? I haven't tested the changes, but they show what I had in mind.
http://www.gammon.com.au/electronics

lesto

thanks very much for pointing the float bug out :-)

Quote
You can probably cut down the precision of bigPI - that uses RAM and you are hardly going to need all those digits.


doesn't BigNumber::setScale (20); throw out unnecessary char for me? also static string reside in flash, at least in the newer ide.

don't trust this acos implementation, just the first thing i've found to make some test.

Quote
execution time (microseconds, precision of 5): 142256 vs 116(using float)

because GPS normally troughput is 1Hz, this library IS FAST enough  :smiley-mr-green: sadly it is too big and slow (but for slowness just divide and conquer...) to be on my quad software.

Basically this test is just to understand if arduino can plot a GPS path between 2 point... seems like he can, but sadly it won't do much more  :smiley-mr-green:

ps. now i'll try the faster implmentation c=mod(atan2(sin(lon1-lon2)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon1-lon2)), 2*M_PI);
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Nick Gammon


doesn't BigNumber::setScale (20); throw out unnecessary char for me? also static string reside in flash, at least in the newer ide.


Yes, but it (the generated code) first copies strings into RAM from flash.
http://www.gammon.com.au/electronics

el_supremo

Code: [Select]
x -= x;
This will set x to zero, not negate it??
Shouldn't it be:
Code: [Select]
x = -x;

Pete

lesto

@pete: you are right

@Nick: tomorrow i'll implement the tylor expansion of atan, so i will test the "fast" code. also with a nice app i've found that limiting the sine input form -PI to +PI i can safely use a precision of 10.
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Nick Gammon

http://www.gammon.com.au/electronics

lesto

tryed the first implementation of atan with taylor... no way, it isn't enough accurate for value over 1.0.

now i'll try the CORDIC implementation
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

Go Up