Floating point math

Hi All...

I'm working on an application that requires a lot of floating point math, in particular the use of trig functions like sin(), cos(), tan() and so on. The Arduino Duemilanove seems to meet my requiremens from some other perspectives. For example, it runs on a 12VDC battery and I can get one with a DB9 connector and RS232 serial.

I see it has either an ATmega168 or ATmega328 CPU. I don't need to do my caculations super fast. I'll be reading a serial data stream at 4800 baud. Will these CPUs be able to handle something like this? Iys a lot of math, but I have a lot of time to do it.

Thanks...

The Arduinos are capable of both floating point math and trig functions. They are relatively slow, but if you have the time, they will work.

That's great news, thanks! I need to do several dozen caculations in a second, so I probably have the time, and lots more to spare.

skyjumper:
That's great news, thanks! I need to do several dozen caculations in a second, so I probably have the time, and lots more to spare.

You could easily do several thousand calculations per second more than likely.

Even when programming far more powerful processors, I bend over backwards to arrange my algorithms to minimize floating point due to it's relative impact on speed, especially trig and log functions. It's an old school habit. Heck, you'll even see division involving two long integers minimized in much of my code.

Several dozen per second ? 14 milliseconds each. I could see the Arduino handling that. I could also see the Arduino struggling to handle any other tasks being performed at the same time.

Several thousand per second ? 170 microseconds each. I'm from Missouri. Show me.

I, for one, hope SJ posts his results. They could come in very handy for one of my upcoming projects. If the floating point division doesn't carry as much of a penalty as I'm suspecting, I won't have to resort to clever tactics to reduce a near real time speed measurement problem to long integer division.

I think people underestimate the speed of Arduino. At 16Mhz and mostly one instruction per cycle, Arduino will run rings around an old Apple 2 or CPM box or even a PDP-11 that folks did all kinds of significant work on. The limits of Arduino as a compute platform are mainly due to the amount of RAM available, which is puny in the extreme.

The good folks who built AVR-GCC and AVR-LIBC didn't bother to give us long floats though, so you have to make do with single floats. If you are REALLY in a hurry, it's possible to do a lot with fixed point, and I have seen some nice work on fixed point libraries for AVR. AVRfix download | SourceForge.net

Enough philosophy. There are a thousands of people with Arduino reading these postings; give us a better idea what your calculations need to be, and someone will try it out.

I get about 2300 "cos()" and associated operations with the following example:

volatile float d;
void loop (void)
{
  unsigned long opcount = 0;
  unsigned long starttime = millis();

  while (millis() - starttime < 1000) {
    float b,c; 

    b = (float) random(100);
    c = (float) random(72);
    d = cos(b/c);
    opcount++;
  }
  Serial.println(opcount);
}

give us a better idea what your calculations need to be, and someone will try it out.

The baud rate mentioned (4800) is typical for a GPS. Looks to me like OP is trying to read from a GPS and determine direction and distance to a target with some degree of speed.

Think similar similar order of magnitude power to what put man on the moon in 1969...... (Primitive and slow in other words.)

westfw:
I get about 2300 "cos()" and associated operations with the following example: ...

That's fast! Thanks for the info. I was personally expecting something around 500.

Still, 2300/several dozen operations = about a 30ms floor for the loop execution speed. Add some string processing, serial communications, or an LCD display could easily slow things up quite a bit more.

My upcoming project will require an overall loop speed below 10ms, a little interrupt driven pulse timing accurate to within 250µs, and just a few floating point operations to calculate results for the display. I think this puts that well within reach.

gardner:
Arduino will run rings around an old Apple 2 or CPM box or even a PDP-11 that folks did all kinds of significant work on.

Hehe, I cut my teeth programming on the successor to the PDP-11. XD

For the benefit of us noobulars, what are some techniques for converting floating point calculations into integer? Simply multiply the floats by 10^(number of decimal places desired), truncate them, and then go to town with integer math?

What about avoiding trig functions? I know that for many tasks, you can use the small angle approximation, and you can also break the trig function into its series and use the first couple terms.

I'm just confused about arranging algorithms to avoid using floats because it seems like if you are using floats, you need them.

Hi

For raw cos(x) I get around 8900 loops/sec preformance.

Code:

float a=0.5; 
long bigNumber = 100000;
unsigned long time1, time2, diff;

void setup(){
  Serial.begin(9600);
  time1 = millis();
  for (int i=0; i<bigNumber;i++){
    a = cos(a);
  }
  time2 = millis();
  diff = time2-time1;
  Serial.print(diff);Serial.print(" millisec for numbers of loops: ");Serial.println(bigNumber);
  a = 1.0*bigNumber/diff*1000;
  Serial.print(a); Serial.println(" loops/sec");
}

void loop(){
}

Output:

11229 millisec for numbers of loops: 100000
8905.51 loops/sec

I guess there is a convagens to a=0.739... but the cos() calculation is still forced at every loop.

-Fletcher

Fletcher_Chr:
Hi

For raw cos(x) I get around 8900 loops/sec preformance.

Code:

float a=0.5; 

long bigNumber = 100000;
unsigned long time1, time2, diff;

void setup(){
 Serial.begin(9600);
 time1 = millis();
 for (int i=0; i<bigNumber;i++){
   a = cos(a);
 }
 time2 = millis();
 diff = time2-time1;
 Serial.print(diff);Serial.print(" millisec for numbers of loops: ");Serial.println(bigNumber);
 a = 1.0bigNumber/diff1000;
 Serial.print(a); Serial.println(" loops/sec");
}

void loop(){
}




Output:


11229 millisec for numbers of loops: 100000
8905.51 loops/sec




I guess there is a convagens to a=0.739... but the cos() calculation is still forced at every loop.

-Fletcher

Years ago this post comes back to life, but, I don't trust compilers, mostly when the 'a = cos(a)' becomes repetitive and the same number [a == cos(a)] = 0.739084823, after only 33 loops. The compiler CAN observe certain possibilities and include a few cache for repetitive operations, mostly considering a==cos(a) as 0.739084823. it could be an expected testing situation, so the compiler takes advantage of that and make 8+ thousand operations (without doing it) per second. You never know, only by observing the disassembled code.

To make sure about this your measurement, I would change the testing routine to make

for (int i=0; i<bigNumber;i++){
a = cos(a);
a = sin(a);
}

and then double bignumber in the accounts, just to make sure the compiler is not playing tricks.

Anyway, I just finished a sin(x) routine in assembly, ~210 AVR instructions, it calculates sin(x) based on the input angles in degrees, two bytes, from zero to 900 (90.0°), the result is ±1 bit of error in 3 bytes, so 23 bits of precision along all the first quadrant angles. The AVR running a 16MHz can do it in 211us for 0.01° to 213us for 89.9°, so it can do a bit more than 4700 calculations per second. It is based on Taylor series, so there is a lot of calculations, no floating point, and it runs all in the registers, no data segment used.

Of course CORDIAC would be faster, and perhaps your test was done in a compiler using CORDIAC, built in assembly code for speed.