Math operators, decimals and float

Hello,

I made a sketch that needs to calculate a logarithm for integer numbers taken from and array. It works very well.

My problem is that I have to calculate a logarithm for numbers like 27.6 and fractions. I did that using float and it worked but float takes up a lot of memory and slows the sketch down. Is there any way to do this without using float?

I need to figure out the math steps in order to write the sketch.

The software floating point functions aren't so bad. They are small and quick.
Do you need the memory for something else ? and why does it slow down the sketch ? Perhaps other things are going on that can be optimized.

Where do the numbers come from, from an array of constant numbers ?
What is the base of the log ? 10, or 2, or natural logaritme ?

Hello,

Thank you for the reply.

The numbers come from and array.

The log is base 2. Because I have to calculate the logarithm I don't think I can do the simple trick of multiplying by 10 and using the values like that.

I need the memory for other parts of the code. I use an Atmega8 so every byte matters.

What range of values and how much precision do you need?

You can write your own function but I don't know how fast it will be.

To what precision do you want the logarithms?

My problem is that I have to calculate a logarithm for numbers like 27.6 and fractions.

fractions are quite easy as log (a/b) = log(a) - log(b) so log(27.6) = log (276) - log(10);

e.g.for 2 log
2log(276) = 8.1085
2log(10) = 3.3219
2log(27.6) = 4.7866
2log(2.76) = 4.7866 - 3.3219 = 1.4647

you should not interpolate between log(27) and log(28) to get log(27.6) - ok it is better than not interpolating :wink:

Can you answer markT's question?

MarkT:
What range of values and how much precision do you need?

I'm still not certain where those numbers come from. From a device outside the ATmega ? which device ? via serial ? how ? Does the ATmega caculate them itself ? why ? are they constants in an array ? how did they get there ?

The binary bits inside a float number is already '2'-based. Perhaps there is some kind of trick for faster log2 caculcation.

A quick test

//
//    FILE: .ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: 
//    DATE: 
//     URL:
//
// Released to the public domain
//
float val[300];
uint32_t start, stop;
uint32_t duration[3];
volatile float x;
volatile float y;
volatile float z;

void setup() 
{
  Serial.begin(115200);
  Serial.println("Start ");

  // fill array
  for (int i=1; i< 300; i++) val[i] = log(i);

  start = micros();
  for (int i=0; i< 300; i++)
  {
    x = log(i);
  }
  stop = micros();
  duration[0] = stop - start;

  start = micros();
  for (int i=0; i< 300; i++)
  {
    y = val[i];
  }
  stop = micros();
  duration[1] = stop - start;

  start = micros();
  for (int i=0; i< 300; i++)
  {
    z = val[i] - val[10];
  }
  stop = micros();
  duration[2] = stop - start;

  Serial.println(duration[0]/300.0); 
  Serial.println(duration[1]/300.0); 
  Serial.println(duration[2]/300.0); 
}

void loop() 
{
}/code]

output
150.11   // calc whole value 
1.33      // lookup whole value e.g. 276 
7.53      // lookup & calc e.g. 27.6

so a lookup table is approx.
- 100 x faster than calculating for whole values.
- 20 x faster than calculating for fractional values.
These values are optimistic as the tables should be in progmem, and you probably need some additional logic** to determine the right subtraction.

But even the 150 micros of log() means you can do ~6000 of them every second. That is a lot
log10() is slighty slower 158 micros()

The price for faster performance is a big lookup table e.g for 3 digits precision => 1..1000 takes 4K of your progmem!
And a rounding error as a lookup table has only limited precision

[hr]
**
some variations, note they have rounding errors

myLog() using 3 digit numbers between 0.001 .. 999 ==> takes about 22usec  (7x faster)
[code]float mylog(float a)
{
  if (a <10) return val[int(a*100)] - val[100];
  if (a <100) return val[int(a*10)] - val[10];
  return val[int(a)];
}

an interpolatingLog(float a) between 1 .. 999 ==> takes about 35usec (4x faster))

float interpolatingLog(float a)
{
  int x = int(a);
  float b = (a - int(a));
  return val[x] + b* (val[x] + val[x+1]);
}

in short unless really needed - use the log() function.
[/code]