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
thanks everybody, here the solution I'm using:
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:
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):
halfPI = PI / 2;
give some error with overloaded constructor. I've work around it because I'm not good with c++ ![]()
tried my 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):
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
lesto:
just a little problem (arduino IDE 1.0.1):halfPI = PI / 2;give some error with overloaded constructor. I've work around it because I'm not good with c++
Try:
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.
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:
BigNumber negate = BigNumber(x < 0);
if (x < 0){
x*=-1;
}
Why multiply when you can negate?
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.
thanks very much for pointing the float bug out ![]()
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.
execution time (microseconds, precision of 5): 142256 vs 116(using float)
because GPS normally troughput is 1Hz, this library IS FAST enough
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 ![]()
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)), 2M_PI);
lesto:
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.
x -= x;
This will set x to zero, not negate it??
Shouldn't it be:
x = -x;
Pete
@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.
el_supremo:
Shouldn't it be:x = -x;
Yes. Shows what happens when you don't test. ![]()
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