Speed of Sin(x)

I created a sketch to generate code for an array of all of the values of sin(x) from 0 to 90 (for a future project). I know calculating sin(x) takes more time than cycling through an array of pre-calculated values. But how much faster is it? I tried to measure the speed with the serial monitor but I am not sure I am doing it right. This is my first sketch with an array by the way! I am a little confused on why the compiler complained when I used 90 instead of 91, I thought arrays are 0 indexed? (it is late at night...) Anyways..I used micros to measure it and the numbers seem about right, 1208 manually and 344 with an array. I am still a little new at programming but would appreciate any help from the guru's. If you guys have any suggestions or pointers, it would help a lot. I really want to learn this stuff. Man, you know it is late at night when you press CTRL + U to upload a post. :astonished:

// this sketch takes  1208 microseconds to find all of the sin values manually

float x = 0.00;
int count = 0;
unsigned long start = 0;
void setup(){
  Serial.begin(115200);
}

void loop(){
   
  while(count < 1){
    start = micros();
    Serial.println(start);
    for( x = 0; x <= 90; x += 1){ 
     sin(x);
     x++;
     }
     Serial.println(micros());
     count++;
   }
  }
// this sketch gives me 344 micro seconds to completely cycle the array


float sine2[91] = {0.00,  0.84,  0.91,  0.14, -0.76, -0.96, -0.28,  0.66,  0.99, 
                   0.41, -0.54, -1.00, -0.54,  0.42,  0.99,  0.65, -0.29, -0.96,
                  -0.75,  0.15,  0.91,  0.84, -0.01, -0.85, -0.91, -0.13, -0.76, 
                   0.96,  0.27, -0.66, -0.99, -0.40,  0.55,  1.00,  0.53, -0.43,
                  -0.99, -0.64,  0.30,  0.96,  0.75, -0.16, -0.92, -0.83, -0.02,
                   0.85,  0.90,  0.12, -0.77, -0.95, -0.26,  0.67,  0.99,  0.39,
                  -0.56, -1.00, -0.52,  0.44,  0.99,  0.64, -0.30, -0.97, -0.74,
                   0.17,  0.92,  0.83, -0.03, -0.86, -0.90, -0.11,  0.77,  0.95, 
                   0.25, -0.68, -0.99, -0.39,  0.57,  1.00,  0.51, -0.44, -0.99,
                  -0.63,  0.31,  0.97,  0.73, -0.18, -0.92, -0.82,  0.04,  0.86, 0.89 };

 unsigned long start = 0;
int count = 0;
void setup(){

Serial.begin(115200);


}

void loop(){
  
  while(count<1){
    
   start = micros();
 
    Serial.println(micros());
    
    
    for(int array = 0; array <= 90; array++){
   
     sine2[array];
      
    }
   
    Serial.println(micros()); 
    count++;
  }
}

For those interested, this sketch has a few tiny bugs but it works. Just verify the values are right. The idea was to use the serial monitor to print out pre-formatted code I could copy and paste it into a sketch. I tried to comment the bugs, but hopefully you guys like the concept.

// this sketch takes 77ms to print all of the sin values

float x = 0.00;
int count = 0;
void setup(){
  Serial.begin(115200);
  Serial.println("Sine value generator");
  delay(100);
}

void loop(){
   
  while(count < 1){
    int total = 0;
    
    Serial.println("Starting. Just copy and paste the array into your code. \nArray's are zero indexed and I have 90 values. Just add 1 from your index to get the right value");
    Serial.println("");
    unsigned long start = millis();
    Serial.print("Time = ");
    Serial.print(start);
    Serial.println("ms");
    Serial.println("  ");
    Serial.print("float sine[91] = {");
    
   
       
    for( x = 0; x <= 84; x += 1){              // 84 + 8 = 92. If you use 90, it makes 98 values.. needs to be fixed
     int wait = 0;

     for(wait = 0; wait <= 8; wait++){   // I wanted the values to come out as an 8 x something block instead of a long line
     Serial.print(sin(x)); //sine is in radians!
     Serial.print(", ");
     x++;
      }
     x = x-1;    // if you do not subtract 1 from x, you will loose a sin value every 8 cycles.
      Serial.println("");                    // this is to preformat the text block for you but it is a little buggy
      Serial.print("                 ");
    }
     
     Serial.println("};");
     Serial.println("Just remove the last comma from the array");
     Serial.println("Self assembling code");
    total = millis() - start;
    Serial.print("Total time = ");
    Serial.print(total);
    Serial.println("ms");
    Serial.println(millis());
     count++;
   }
   
  }

You always think of something after hitting reply. I think my next time around the sin array, I will multiply every value of sin(x) by 100 or 1000 even to preserve the decimal points and get rid of the floating point math. (since arduino rounds to 2 decimal points of precision and floating point math takes longer) When I get to the point where I need to use the sin function to solve for something, I can divide by 100 or 1000 to get a more precise number faster with less memory usage. ...I think...

I used 0 - 90 because sin is a wave, 90-180 is just the opposite. I also just realized I used sin(degrees) to get a radian value. I probably should have converted the degrees to radians before taking the sin of it. (I might be over thinking right now)

If you really want to know the difference in time between sin() and use of an array, you should remove the rest of the code during the period you are measuring.

    double dummy;
    unsigned int start;
    unsigned int stop;

    start = micros();
    for( x = 0; x <= 90; x++)
        dummy = sin(x);
    stop = micros();

    Serial.println(start);
    Serial.println(stop);
    float dummy;
    unsigned int start;
    unsigned int stop;

    start = micros();
    for( x = 0; x <= 90; x++) 
        dummy = sin2[x];
    stop = micros();

    Serial.println(start);
    Serial.println(stop);

Why do you use a count<1? If you want this code only executes once, you should move it to setup()

whiteglint143:
This is my first sketch with an array by the way! I am a little confused on why the compiler complained when I used 90 instead of 91, I thought arrays are 0 indexed?

When you declare an array, you have to indicate the size of it. If you count from 0 to 90 (included), there are 91 values, so...array has to be sine[91].

In other words, you are counting the time it takes to print. When you exclude that, the difference will be much greater.

sin() uses radians, not degrees. PI radians = 180 degrees.

    for( x = 0; x <= 90; x += 1){ 
     sin(x);
     x++;

Forgive me if I'm wrong, but wouldn't putting the x++ within the array make x increase by 2 each time it loops. Because you also have the x += 1 when you setup the for loop which should add 1 each time the loop increments. Also it might be better and more accurate like Sbright33 mentioned, Takes a lot of time to print. Perhaps make it go through and find all the values, then print them all at once. Then compare that to having the array and then just printing it all at once.

PS Armored Core kicked ass

A few things:

As others have pointed out, the input to sin, cos, etc. is in radians, not degrees. To convert from degrees to radians, you need to multiply by 180/3.1415926535 (or whatever approximation of pi you want to use).

The trig functions generally involve quite a few floating point multiplies and adds. The AVR is an 8 bit microprocessor that does not support floating point in the native instruction set. The software library provides emulation of floating point. Which means the sin function, takes thousands of instructions, if not tens of thousands. However, whether or not that matters depends on your timing constraints elsewhere.

The compiler gave you an error on the array initialization because you gave it 91 elements. When you initialize an array such as: static int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; you are initializing a[0] through a[9]. The array element a[10] is outside of the array.

Please check out my sin() lookup experiment here - http://arduino.cc/forum/index.php/topic,69723.0.html -

first test was 6x faster but had a relative large error margin.
final version is factor 2.6 faster than sine and has a a far smaller error margin.

Hi Rob, I haven't done the math since 1992 so don't ask just how; there are finite series equations that you only use as many steps as you need precision to get your answer. You could as it were fold/unfold any angle. There should be books showing how to code trig and log functions.

As an old grayhair, all this talk of pre-calculating sin/cos tables reminds me of the CRC (Chemical Rubber Company) tables that were quite common in my youth. I see that Amazon still sells the dead tree version, and in fact a new edition was printed in June 2011. Just for fun, I also noticed some of the advanced slide rules from the day, also had a rule for helping you to calculate sin/cos. Of course these days, when somebody needs a sin, they hit the button on their scientific calculator or use sin within their spreadsheet.
8) :cold_sweat: :sleeping:

@GoforSmoke
The equations are Taylor series and these are in fact often the base for the "normal" library implementation of sin / cos functions. Point is these use floating point operations and as the Arduino do not do floating point operations in HW these are "slower" than table lookups.

I recall that Nick Gammon has experimented with a hardware FP-unit that could be connected to Arduino over SPI IIRC.

Space or speed, them's the tradeoffs!

Google "CORDIC"