+ fix for negative values bug - beta version to be verified

+ separate field neg to indicate sign
+ rewrote several fuctions (partly)
+ made sign() public
+ extended tests to test negative values more explicit
This commit is contained in:
rob tillaart 2015-10-19 20:15:06 +02:00
parent e6ddd651eb
commit 563d99193d
4 changed files with 407 additions and 90 deletions

View File

@ -1,13 +1,14 @@
//
// FILE: Angle.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.05
// VERSION: 0.1.06
// PURPOSE: library for Angle math for Arduino
// URL: http://forum.arduino.cc/index.php?topic=339402
//
// Released to the public domain
//
// 0.1.06 - fixed bug negative values.
// 0.1.05 - added AngleFormat proxy added 03/03/15 by Christoper Andrews.
// 0.1.04 - changed thousands in tenthousands, string constructor
// 0.1.03 - added URL, fromRadians [TEST]
@ -25,10 +26,30 @@ size_t AngleFormat::printTo(Print& p) const
return angle.printTo( p, mode );
}
Angle::Angle(int dd, int mm, int ss, int tt) // todo optimize
{
neg = false;
d = dd;
m = mm;
s = ss;
t = tt;
// TODO
// normalize();
// assume only one param is neg at most...
if (d < 0) { d = -d; neg = true; }
if (m < 0) { m = -m; neg = true; }
if (s < 0) { s = -s; neg = true; }
if (t < 0) { t = -t; neg = true; }
while (t >= 10000) { s++; t -= 10000; }
while (s >= 60) { m++; s -= 60; }
while (m >= 60) { d++; m -= 60; }
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
}
Angle::Angle(const double alpha)
{
double a = alpha;
bool neg = (alpha < 0);
neg = (alpha < 0);
if (neg) a = -a;
d = int(a);
@ -45,32 +66,32 @@ Angle::Angle(const double alpha)
p = p / 10000UL;
s = p % 60UL;
m = p / 60UL;
if (neg) d = -d;
}
Angle::Angle(char * str)
{
uint32_t yy = 0;
uint8_t d_cnt = 0;
bool neg = false;
neg = false;
// parse whole degrees
char *p = str;
d = 0;
// skip crap
while (!isdigit(*p) && (*p != '-')) p++;
// process sign
if (*p == '-')
{
neg = true;
p++;
}
// parse whole part into degrees; assume +
if (*p == '+') p++;
// parse whole part into degrees;
while (isdigit(*p))
{
d *= 10;
d += (*p - '0');
p++;
}
if (neg) d = -d;
// parse decimal part into an uint32_t
if (*p != '\0')
{
@ -100,7 +121,6 @@ Angle::Angle(char * str)
m = yy / 60;
}
// PRINTING
size_t Angle::printTo(Print& p, AngleFormatMode mode) const
{
@ -108,6 +128,7 @@ size_t Angle::printTo(Print& p, AngleFormatMode mode) const
char separator[4] = ".\'\""; // "..."; // ALT-0176 = ° 179.59.59.9999
size_t n = 0;
if (neg) n += p.print('-');
n += p.print(d);
n += p.print(separator[0]);
if( --c )
@ -134,35 +155,43 @@ size_t Angle::printTo(Print& p, AngleFormatMode mode) const
double Angle::toDouble(void)
{
bool neg = false;
if (d < 0)
{
neg = true;
d = -d;
}
long v = t + s * 10000UL + m * 600000UL;
double val = ((1.0 / 140625.0) / 256) * v + d;
if (neg) val = -val;
return val;
}
// NEGATE
Angle Angle::operator - ()
{
Angle temp = *this;
if (temp.d == 0 && temp.m == 0 && temp.s == 0 && temp.t == 0)
{
temp.neg = false;
}
else
{
temp.neg = !neg;
}
return temp;
};
// BASIC MATH
Angle Angle::operator + (const Angle &a)
Angle Angle::operator + (const Angle &a) // TOCHECK
{
return addHelper(a);
}
Angle& Angle::operator += (const Angle &a)
Angle& Angle::operator += (const Angle &a) // TOCHECK
{
*this = addHelper(a);
return *this;
}
Angle Angle::addHelper(const Angle &a)
Angle Angle::addHelper(const Angle &a) // TOCHECK
{
Angle temp = *this;
if (sign(temp.d) == sign(a.d))
if (temp.neg == a.neg)
{
temp.d += a.d;
temp.m += a.m;
@ -171,30 +200,31 @@ Angle Angle::addHelper(const Angle &a)
}
else
{
temp.d = sign(temp.d) * (abs(temp.d) - abs(a.d));
temp.d -= a.d;
temp.m -= a.m;
temp.s -= a.s;
temp.t -= a.t;
}
temp.normalize();
return temp;
}
Angle Angle::operator - (const Angle &a)
Angle Angle::operator - (const Angle &a) // TOCHECK
{
return subHelper(a);
}
Angle& Angle::operator -= (const Angle &a)
Angle& Angle::operator -= (const Angle &a) // TOCHECK
{
*this = subHelper(a);
return *this;
}
Angle Angle::subHelper(const Angle &a)
Angle Angle::subHelper(const Angle &a) // TOCHECK
{
Angle temp = *this;
if (sign(temp.d) == sign(a.d))
if (temp.neg == a.neg)
{
temp.d -= a.d;
temp.m -= a.m;
@ -203,7 +233,7 @@ Angle Angle::subHelper(const Angle &a)
}
else
{
temp.d = sign(temp.d) * (abs(temp.d) + abs(a.d));
temp.d += a.d;
temp.m += a.m;
temp.s += a.s;
temp.t += a.t;
@ -248,33 +278,55 @@ double Angle::operator / (Angle& a)
//
int Angle::compare(const Angle &a, const Angle &b)
{
if (a.d > b.d) return 1;
if (a.d < b.d) return -1;
if (a.m > b.m) return 1;
if (a.m < b.m) return -1;
if (a.s > b.s) return 1;
if (a.s < b.s) return -1;
if (a.t > b.t) return 1;
if (a.t < b.t) return -1;
return 0;
// check sign first
if (!a.neg && b.neg) return 1;
if (a.neg && !b.neg) return -1;
// check abs value
int rv = 0;
if (a.d > b.d) rv = 1;
else if (a.d < b.d) rv = -1;
else if (a.m > b.m) rv = 1;
else if (a.m < b.m) rv = -1;
else if (a.s > b.s) rv = 1;
else if (a.s < b.s) rv = -1;
else if (a.t > b.t) rv = 1;
else if (a.t < b.t) rv = -1;
if (rv != 0 && a.neg) rv = -rv;
return rv;
}
void Angle::normalize()
void Angle::normalize() // TOCHECK
{
bool neg = (d < 0);
if (neg) d = -d;
while (t < 0) { s--; t += 10000; }
while (t >= 10000) { s++; t -= 10000; }
while (s < 0) { m--; s += 60; }
while (s >= 60) { m++; s -= 60; }
while (m < 0) { d--; m += 60; }
while (m >= 60) { d++; m -= 60; }
if (neg) d = -d;
}
int Angle::sign(int d)
{
return (d < 0?-1:1);
if (d < 0)
{
if (t != 0)
{
t = 10000 - t;
s++;
}
if (s != 0)
{
s = (60 - s) % 60;
m++;
}
if (m != 0)
{
m = (60 - m) % 60;
d++;
}
d = -d;
neg = !neg;
}
if (d == 0 && m == 0 && s == 0 && t == 0) neg = false;
}
// --- END OF FILE ---

View File

@ -3,7 +3,7 @@
//
// FILE: Angle.h
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: 0.1.05
// VERSION: 0.1.06
// PURPOSE: angle library for Arduino
// HISTORY: See angle.cpp
//
@ -22,7 +22,7 @@
#include "Printable.h"
#define ANGLE_LIB_VERSION "0.1.05"
#define ANGLE_LIB_VERSION "0.1.06"
class Angle;
@ -42,15 +42,11 @@ struct AngleFormat : Printable{
class Angle: public Printable
{
public:
Angle(int dd=0, int mm=0, int ss=0, int tt =0) :
d(dd), m(mm), s(ss), t(tt)
{
normalize();
}
Angle(int dd=0, int mm=0, int ss=0, int tt=0);
Angle(double alpha);
Angle(char * str);
int sign() { return neg?-1:1; };
int degree() { return d; };
int minute() { return m; };
int second() { return s; };
@ -74,7 +70,7 @@ public:
bool operator >= (const Angle& a) { return compare(*this, a) >= 0; };
// NEGATE
Angle operator - () { return Angle(-d, m, s, t); };
Angle operator - ();
Angle operator + (const Angle&);
Angle& operator += (const Angle&);
@ -90,15 +86,14 @@ public:
double operator / (Angle&); // ratio
private:
void normalize();
int compare(const Angle&, const Angle&);
int sign(int);
Angle addHelper(const Angle &a);
Angle subHelper(const Angle &a);
bool neg; // angle is negative
int d; // whole degrees
int m; // minutes
int s; // seconds

View File

@ -1,5 +1,8 @@
2015-10-18:
2015-10-19: version 0.1.06
ug has been fixed but needs to be verified
2015-10-18: version 0.1.05
A serious bug has been found for negative angles.
Do not use this lib until an update is available.
(use at own risk)

View File

@ -1,7 +1,7 @@
//
// FILE: test_angle01.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.02
// VERSION: 0.1.03
// PURPOSE: demo sketch to test angle class
// DATE: 2015-07-30
// URL:
@ -17,13 +17,13 @@ Angle c(2, 3, 4, 5);
Angle n(0);
Angle z(5.5);
void setup()
{
Serial.begin(115200);
Serial.println("Start test_angle01");
Serial.print("lib version: ");
Serial.println(ANGLE_LIB_VERSION);
Angle aa(-1, 2, 3, 45);
Angle bb(0, -2, 3, 45);
Angle cc(0, 0, -3, 45);
Angle dd(0, 0, 0, -45);
void testConstructors()
{
Serial.println("\n1. print -- Angle(d, m, s, t)");
Serial.println(a);
Serial.println(b);
@ -31,7 +31,42 @@ void setup()
Serial.println(n);
Serial.println(z);
Serial.println("\n2. toDouble -- Angle(double) toRadians()");
Serial.println("\n1. print -- negative angles");
Serial.println(aa);
Serial.println(bb);
Serial.println(cc);
Serial.println(dd);
Serial.println("\n1. Constructor(char *)");
char str1[] = "179.999999999";
Angle s(str1);
Angle t = str1;
Serial.println(str1);
Serial.println(s);
Serial.println(s.toDouble(), 9);
Serial.println(t);
t = s.toDouble();
Serial.println(t);
char str2[] = "-45.987654321";
Angle u(str2);
Angle v = str2;
Serial.println(u);
Serial.println(u.toDouble(), 9);
Serial.println(v);
char str3[] = "-0.987654321";
Angle uu(str3);
Angle vv = str2;
Serial.println(uu);
Serial.println(uu.toDouble(), 9);
Serial.println(vv);
}
void testToDouble()
{
Serial.println("\n2.1 toDouble -- Angle(double) toRadians()");
Serial.println(a.toDouble(), 7);
Serial.println(b.toDouble(), 7);
Serial.println(c.toDouble(), 7);
@ -45,14 +80,65 @@ void setup()
d = 180;
Serial.println(d.toRadians(), 7);
Serial.println("\n2.2 toDouble -- negative angles");
Serial.println(aa);
Serial.println(aa.toDouble(), 7);
Serial.println(bb);
Serial.println(bb.toDouble(), 7);
Serial.println(cc);
Serial.println(cc.toDouble(), 7);
Serial.println(dd);
Serial.println(dd.toDouble(), 7);
Serial.println();
Serial.println("\n2.3 toDouble - fromRadians");
aa.fromRadians(2 * PI);
Serial.println(aa);
aa.fromRadians(PI);
Serial.println(aa);
aa.fromRadians(PI / 2);
Serial.println(aa);
aa.fromRadians(PI / 3);
Serial.println(aa);
aa.fromRadians(PI / 4);
Serial.println(aa);
aa.fromRadians(PI / 6);
Serial.println(aa);
aa.fromRadians(PI / 12);
Serial.println(aa);
aa.fromRadians(PI / 18);
Serial.println(aa);
aa.fromRadians(PI / 36);
Serial.println(aa);
aa.fromRadians(PI / 180);
Serial.println(aa);
Serial.println();
}
void testParts()
{
Serial.println("\n3. degrees, minutes, seconds, thousands");
Serial.println(c);
Serial.println(c.sign());
Serial.println(c.degree());
Serial.println(c.minute());
Serial.println(c.second());
Serial.println(c.tenthousand());
Serial.println("\n4. Compare: a op a op : == != < <= > >= ");
Serial.println(cc);
Serial.println(cc.sign());
Serial.println(cc.degree());
Serial.println(cc.minute());
Serial.println(cc.second());
Serial.println(cc.tenthousand());
}
void testCompare()
{
Serial.println("\n4. Compare: a op a op: == != < <= > >=");
Serial.println(" should be 100101");
Serial.println(a);
Serial.print(a == a);
Serial.print(a != a);
Serial.print(a < a);
@ -61,7 +147,10 @@ void setup()
Serial.print(a >= a);
Serial.println();
Serial.println("\n5. Compare: a op c op : == != < <= > >= ");
Serial.println("\n4. Compare: a op c op: == != < <= > >=");
Serial.println(" should be 011100"); // A < C
Serial.println(a);
Serial.println(c);
Serial.print(a == c);
Serial.print(a != c);
Serial.print(a < c);
@ -70,20 +159,60 @@ void setup()
Serial.print(a >= c);
Serial.println();
Serial.println("\n4. Compare: -a op c op: == != < <= > >=");
Serial.println(" should be 011100"); // A < C
a = -a;
Serial.println(a);
Serial.println(c);
Serial.print(a == c);
Serial.print(a != c);
Serial.print(a < c);
Serial.print(a <= c);
Serial.print(a > c);
Serial.print(a >= c);
Serial.println();
Serial.println("\n4. Compare: -a op -c op: == != < <= > >=");
Serial.println(" should be 010011"); // C < A
c = -c;
Serial.println(a);
Serial.println(c);
Serial.print(a == c);
Serial.print(a != c);
Serial.print(a < c);
Serial.print(a <= c);
Serial.print(a > c);
Serial.print(a >= c);
Serial.println();
}
void testNegate()
{
Serial.println("\n6. negate ");
Serial.println(a);
a = -a;
Serial.println(a);
a = -a;
Serial.println(a);
Angle tt(0, 1, 2, 3);
Serial.println(-tt);
Angle uu(0, 0, 2, 3);
Serial.println(-uu);
Angle vv(0, 0, 0, 3);
Serial.println(-vv);
Angle ww(0, 0, 0, 0);
Serial.println(-ww);
}
void testAdd()
{
Serial.println("\n7.1 Add +");
for (int x = -1; x < 2; x++)
for (int y = -1; y < 2; y++)
{
a = x;
b = y;
d = a + b;
Angle d = a + b;
Serial.print(a);
Serial.print("\t+\t");
Serial.print(b);
@ -105,13 +234,90 @@ void setup()
Serial.println(a);
}
Serial.println("\n7.3 Add - 1000 random tests - no output is ok");
for (int i = 0; i < 1000; i++)
{
double x = random(36000) / 100.0 - 180;
double y = random(36000) / 100.0 - 180;
double z = x + y;
a = x;
b = y;
Angle d = a + b;
if ( abs(d.toDouble() - z) > 0.001)
{
Serial.print(i);
Serial.print("\t");
Serial.print(Angle(x));
Serial.print("\t");
Serial.print(Angle(y));
Serial.print("\t");
Serial.print(z);
Serial.print("\t");
Serial.print(Angle(z));
Serial.print("\t");
Serial.print(d.toDouble());
Serial.print("\t");
Serial.print(d);
Serial.println();
}
}
Serial.println("\n7.4 Add - 1000 random tests - no output is ok");
for (int i = 0; i < 1000; i++)
{
double x = random(200) / 100.0 - 1;
double y = random(200) / 100.0 - 1;
double z = x + y;
a = x;
b = y;
Angle d = a + b;
if ( abs(d.toDouble() - z) > 0.00001)
{
Serial.print(i);
Serial.print("\t");
Serial.print(Angle(x));
Serial.print("\t");
Serial.print(Angle(y));
Serial.print("\t");
Serial.print(z);
Serial.print("\t");
Serial.print(Angle(z));
Serial.print("\t");
Serial.print(d.toDouble());
Serial.print("\t");
Serial.print(d);
Serial.println();
}
}
Serial.println("\n7.5 Add a double to an angle ");
for (int i = 0; i < 10; i++)
{
double x = random(36000) / 100.0 - 180;
double y = random(36000) / 100.0 - 180;
a = x;
b = y;
Angle d = a + y;
Serial.print(i);
Serial.print("\t");
Serial.print(x);
Serial.print("\t");
Serial.print(y);
Serial.print("\t");
Serial.print(d);
Serial.println();
}
}
void testSubtract()
{
Serial.println("\n8.1 Subtract -");
for (int x = -1; x < 2; x++)
for (int y = -1; y < 2; y++)
{
a = x;
b = y;
d = a - b;
Angle d = a - b;
Serial.print(a);
Serial.print("\t-\t");
Serial.print(b);
@ -133,6 +339,66 @@ void setup()
Serial.println(a);
}
Serial.println("\n8.3 Sub - 1000 random tests - no output is ok");
for (int i = 0; i < 1000; i++)
{
double x = random(36000) / 100.0 - 180;
double y = random(36000) / 100.0 - 180;
double z = x - y;
a = x;
b = y;
Angle d = a - b;
if ( abs(d.toDouble() - z) > 0.001)
{
Serial.print(i);
Serial.print("\t");
Serial.print(Angle(x));
Serial.print("\t");
Serial.print(Angle(y));
Serial.print("\t");
Serial.print(z);
Serial.print("\t");
Serial.print(Angle(z));
Serial.print("\t");
Serial.print(d.toDouble());
Serial.print("\t");
Serial.print(d);
Serial.println();
}
}
Serial.println("\n8.4 Sub - 1000 random tests - no output is ok");
for (int i = 0; i < 1000; i++)
{
double x = random(200) / 100.0 - 1;
double y = random(200) / 100.0 - 1;
double z = x - y;
a = x;
b = y;
Angle d = a - b;
if ( abs(d.toDouble() - z) > 0.00001)
{
Serial.print(i);
Serial.print("\t");
Serial.print(Angle(x));
Serial.print("\t");
Serial.print(Angle(y));
Serial.print("\t");
Serial.print(z);
Serial.print("\t");
Serial.print(Angle(z));
Serial.print("\t");
Serial.print(d.toDouble());
Serial.print("\t");
Serial.print(d);
Serial.println();
}
}
}
void testMultiply()
{
Serial.println("\n9. Multiply * *=");
a = 5.25;
Serial.println(a);
@ -140,17 +406,22 @@ void setup()
Serial.println(a);
a *= 3.1;
Serial.println(a);
}
void testDivide()
{
Serial.println("\n10. Divide / /=");
Serial.println(a);
d = a / 3.1;
Angle d = a / 3.1;
Serial.println(d);
d /= 5.5;
Serial.println(d);
d /= PI;
Serial.println(d);
}
void testRatio()
{
Serial.println("\n11. Ratio");
a = 7.50;
b = 57.456789;
@ -162,32 +433,28 @@ void setup()
Serial.println(a);
Serial.println(b);
Serial.println(a / b, 7); // should be PI
}
Serial.println("\n12. Constructor(char *)");
char str1[] = "179.999999999";
Angle s(str1);
Angle t = str1;
Serial.println(str1);
Serial.println(s);
Serial.println(s.toDouble(), 9);
Serial.println(t);
t = s.toDouble();
Serial.println(t);
char str2[] = "-45.987654321";
Angle u(str2);
Angle v = str2;
Serial.println(u);
Serial.println(u.toDouble(), 9);
Serial.println(v);
void setup()
{
Serial.begin(115200);
Serial.println("Start test_angle01");
Serial.print("lib version: ");
Serial.println(ANGLE_LIB_VERSION);
testConstructors();
testToDouble();
testParts();
testNegate();
testCompare();
testAdd();
testSubtract();
testMultiply();
testDivide();
testRatio();
Serial.println("\nDone...");
//
//
// start = micros();
//
// stop = micros();
// Serial.println(stop - start);
}
void loop()