Realtime 16 Bit unsigned int Sin schneller als 8 Bit lookup table?!

Die Funktionen sin16 und cos16 von der FastLED library sind schneller als meine geliebte vordefinierte 8 Bit Wertetabelle. Die Funktionen rechnen in Echtzeit schneller, als ich ins Array greife! Wie kann das sein?

Ich konnte dieses Ergebnis qualitativ bestätigen:

  • using sin16 takes 4-6ms
  • using sin takes 10-14ms
  • using a precalculated lookup table in ram (256 bytes) takes 6-8ms

"instead of taking an argument in degrees (0-359) or radians (0-2pi aka 0-6.283), these functions take the input angle as a 16-bit unsigned integer (0-65535). Zero is same as zero degrees, 16384=90°, 32768=180°, etc.

The output is not a floating point number from -1.0...1.0, but rather a 16-but signed integer from -32768 to 32767.

These are (briefly) described on this page" https://github.com/FastLED/FastLED/wiki/High-performance-math#sin

Helmuth: Ich konnte dieses Ergebnis qualitativ bestätigen:

  • using sin16 takes 4-6ms
  • using sin takes 10-14ms
  • using a precalculated lookup table in ram (256 bytes) takes 6-8ms

Bist Du Dir absolut sicher, dass Dir keine Compiler-Optimierungen die Messung verfälschen? Code?

Meiner Erfahrung nach hat der AVR GCC Compiler ganz nette Tricks zur Optimierung auf Lager, und wenn man bei Benchmarkroutinen nicht aufpasst, führen eigene Benchmarks ganz schnell dazu, dass Code entweder wegoptimiert wird oder bereits zur Compilezeit ausgewertet wird, so dass im Programm gar nicht mehr die eigentliche Berechnungsfunktion, sondern entweder gar nichts oder nur das während der Kompilierung ermittelte Ergebnis steht und angezeigt wird.

Hallo jurs,

nein, ich bin mir nicht sicher. Habe nochmal einen anderen Benchmark geschrieben, wo ich die herausgegriffenen/berechneten Werte auch tatsächlich verwende. Da sind die Ergebinsse wieder so, wie ich sie erwartet hätte.

Ergebnisse für 240 LEDs einmal tatsächlich in den Speicher schreiben

Lookup table: 228 - 236 µs
Sin16: 724 - 730 µs

Danke für den Hinweis und beste Grüße.

Code:

#include <FastLED.h>

#define LED_PIN     23
#define COLOR_ORDER GRB
#define CHIPSET     WS2811

#define BRIGHTNESS  150

const uint8_t WIDTH  = 20;
const uint8_t HEIGHT = 12;

#define NUM_LEDS (WIDTH * HEIGHT)
CRGB leds[NUM_LEDS];

uint8_t const cos_wave[256]   
{0,0,0,0,1,1,1,2,2,3,4,5,6,6,8,9,10,11,12,14,15,17,18,20,22,23,25,27,29,31,33,35,38,40,42,
45,47,49,52,54,57,60,62,65,68,71,73,76,79,82,85,88,91,94,97,100,103,106,109,113,116,119,
122,125,128,131,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,
189,191,194,197,199,202,204,207,209,212,214,216,218,221,223,225,227,229,231,232,234,236,
238,239,241,242,243,245,246,247,248,249,250,251,252,252,253,253,254,254,255,255,255,255,
255,255,255,255,254,254,253,253,252,252,251,250,249,248,247,246,245,243,242,241,239,238,
236,234,232,231,229,227,225,223,221,218,216,214,212,209,207,204,202,199,197,194,191,189,
186,183,180,177,174,171,168,165,162,159,156,153,150,147,144,141,138,135,131,128,125,122,
119,116,113,109,106,103,100,97,94,91,88,85,82,79,76,73,71,68,65,62,60,57,54,52,49,47,45,
42,40,38,35,33,31,29,27,25,23,22,20,18,17,15,14,12,11,10,9,8,6,6,5,4,3,2,2,1,1,1,0,0,0,0
};

unsigned long timestamp[4];

void setup() {
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
  FastLED.setBrightness( BRIGHTNESS );
  Serial.begin(9600);
}

void loop () {
  timestamp[0] = micros();
  
  for (int i=0; i < NUM_LEDS; i++) {
    leds[i] = cos_wave[i];}
  timestamp[1] = micros();  
  FastLED.show();
  delay(1000);
  
  timestamp[2] = micros();
  for (int i=0; i < NUM_LEDS; i++) {
     leds[i] = sin16(i);}
  timestamp[3] = micros();  
  FastLED.show();
  delay(1000);
  
  showResults();
}


void showResults()  
{
  Serial.print(timestamp[1]-timestamp[0]);  //lookup table
  Serial.print('\t');
  Serial.print(timestamp[3]-timestamp[2]);  //sin16
  Serial.print('\t');
  Serial.println();
}