Pages: 1 [2]   Go Down
Author Topic: Found a 64bit double implementation library, but I cannot compile it  (Read 1581 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
#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
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
  BigNumber::begin ();  // initialize library
  pi = BigNumber ("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706");
... 
  BigNumber::setScale (20);

Should have been:

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

It thought pi was 3.

Now cosine can be:

Code:
BigNumber cosine (BigNumber x, BigNumber p)
{
   return sine (x + pi / BigNumber (2), p);
}  // end of cosine
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I understand, now I'll try again.
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Make sure you move the definition of pi to be after where it sets the scale, as I discussed above.
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

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

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thanks everybody, here the solution I'm using:

Code:
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:
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
« Last Edit: May 23, 2012, 01:47:51 pm by lesto » Logged

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

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

tried my code:

Code:
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:
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
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

just a little problem (arduino IDE 1.0.1):
Code:
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:
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. smiley

Arbitrary precision libraries tend to be slow by their nature.

Some of your stuff is inefficient:

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

Why multiply when you can negate?

Code:
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.
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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);
« Last Edit: May 23, 2012, 04:52:29 pm by lesto » Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Edison Member
*
Karma: 43
Posts: 1556
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Pete
Logged

Where are the Nick Gammons of yesteryear?

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@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.
Logged

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

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Shouldn't it be:
Code:
x = -x;


Yes. Shows what happens when you don't test. smiley
Logged

0
Offline Offline
Shannon Member
****
Karma: 130
Posts: 10449
:(){:|:&};:
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

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

Pages: 1 [2]   Go Up
Jump to: