2016-07-31 3 views
2

Im Wesentlichen versuche ich, die im folgenden Code berechneten Werte zu verwenden, aber wenn ich die Werte in allen Objekten mit eigenen Raten speichere, füge gerade genug Bytes hinzu einen Cache-Fehler verursachen. Und die Verwendung einer Nachschlagetabelle hilft offensichtlich nicht.Schnelle Zweierpotenzen mit schwebendem Exponenten [C]

Also bin ich auf der Suche nach einem Weg, um diese Werte schneller als mit den Standard-Power-Funktionen zu bekommen, gibt es irgendwelche Tricks, die ich wegen der möglichen Eingaben sehr eingeschränkt verwenden kann?

static inline 
double __attribute((pure)) get_decay_rate(uint8_t rate) 
{ 
    if(rate >= 128) 
    { 
      return 65535.0/65536.0; 
    } 

    double k = pow(2, rate/8.0); 
    return (k - 1.0)/k; 
} 


/* pseudocode: 
    double k = (int) pow(2, k/8.0); 
    k = (k - 1)/k; 
    return log(65535/65536)/log(k); 
*/ 
static inline 
uint16_t __attribute((pure)) get_decay_modulus(uint8_t rate) 
{ 
    if(rate <= 128) 
    { 
      return 1; 
    } 
//turns out to be the same as the above pseudocode, for some reason. 
    return pow(2, (rate - 128)/8.0); 
} 
+0

Und Sie haben auch versucht, in jeder Funktion ein statisches 256-langes Array zu setzen? Oder ein statisches 128-langes Array? – Hurkyl

+0

meinst du 'rate/8.0' in' int k = pow (2, k/8.0); '? Ähnlich wie in 'get_decay_modulus' verweisen Sie auf' k', ohne es zu deklarieren. – oldrinb

+0

@Hurkyl Da das Problem Cache-Misses ist, bedeutet das, dass weniger Code in den Cache passen kann, also verschiebt es das Problem, anstatt es zu lösen. –

Antwort

2

Nehmen Sie diese Zeile:

double k = pow(2, rate/8.0); 

Im Grunde, was Sie hier tun, ist 2 auf die Leistung einer Festpunktzahl zu erhöhen.

Sie können die Tatsache nutzen, dass pow (a, b + c) = pow (a, b) * pow (a, c) und eine nicht ganzzahlige Zahl = ganzzahliger Teil + Bruchteil. Sie berechnen also pow mit dem ganzzahligen Teil Ihrer Festkommazahl und multiplizieren diesen mit pow des Bruchteils.

Speichern Sie die 8 gebrochenen Exponenten in einer Lookup-Tabelle:

double fractionalPowersOf2[8]; 

for(int i = 0; i < 8; i++) 
    fractionalPowersOf2[i] = pow(2.0, i/8.0); 

Dann können Sie Ihre Berechnung wie folgt tun:

double k = (double)(1 << (rate >> 3)) * fractionalPowersOf2[rate & 7]; 

Diese Masken aus dem Bruchteil und verwendet sie für eine Lookup-Tabelle , dann multipliziert diese um 2 erhöht auf die Leistung des integralen Teils mit Bitshift. Wenn die Besetzung zu verdoppeln zu langsam ist, können Sie auch eine Nachschlagetabelle verwenden.

Sie könnten auch in der Lage sein, einige phantastische bitmagic-Ansatz verwenden, wo Sie Ihren Wert als Exponent eines Doppelpunkts verwenden, indem Sie Zeiger usw., aber dies wird nicht tragbar sein.

Edit: wie user3386109 in einem Kommentar darauf hingewiesen, wenn Sie auf Optimierungen drehen optimieren kann der Compiler für Sie 2 auf die Leistung eines Integer-Wert erhöht, so kann dieser Code schneller sein:

double k = pow(2,rate>>3) * table[rate&7]; 
+0

Danke, mein Herr, das ist perfekt! –

+1

@samgak Gegeben 'double k = pow (2, Rate >> 3) * Tabelle [Rate &7];' 'mit Optimierungen aktiviert, wird der Compiler die Phantasie Bit Magie auf den Exponenten für Sie tun. – user3386109

+1

@ user3386109: Ich würde mir Sorgen machen, ob die Semantik * wirklich die Zauberei-Magie erlaubt - und skeptisch, dass sie bei der ganzzahligen Berechnung keine Magie vollbringen wird. In jedem Fall ist 'ldexp' wahrscheinlich die bessere Funktion, wenn Sie darauf bestehen, eine Gleitkommafunktion aufzurufen. (Profiling benötigt!) – Hurkyl