Hallo! Angenommen ich möchte mit einer UND-Maske die n untersten bits maskieren. n ist aber variabel und nicht fest. Wie mache ich das effektiv? Wege die mir einfallene Weg 1) Ich definiere mir die Masken als lookup table, also so uint8_t masken[] = {0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; n = (...) //Aus irgendeiner Berechnung auszumaskieren &= masken[n]; das wäre eigentlich doch recht schnell, aber bei größeren Wortbreiten geht das durch den lookup table irgendwie in den Speicher finde ich. Weg 2) Ausrechnen: auszumaskieren &= ( 2**n ) - 1; Da habe ich nur keine Ahnung, wie lange die Berechnung 2**n eigenltich dauert. Und da man nun eigentlich immer so schnell wie es geht bits maskieren möchte verunsichert mich das. Weg 3) Was würdet ihr machen bzw. welche Tips mir geben?
John Doe schrieb: > Weg 2) > Ausrechnen: > > auszumaskieren &= ( 2**n ) - 1; Das kommt drauf an, ob die fragliche CPU einen Barrelshifter hat oder nicht. Hat sie einen, dann ist das eine schnelle Operation. Hat sie keinen, dann ist das eher langsam, weil der Compiler die Operation als Schleife implementieren muss. > Weg 3) > > Was würdet ihr machen Ich würds als Lookup-Tabelle machen.
John Doe schrieb: > das wäre eigentlich doch recht schnell, aber bei größeren Wortbreiten > geht das durch den lookup table irgendwie in den Speicher finde ich. Wieso? Die Werte die n maximal annehmen kann sind je nach Prozessor 8, 16, 32, 64 und vielleicht maximal 128 oder 256. Das sind kleine Tabellen.
Klaus Falser schrieb: > Das sind kleine Tabellen. auf einen Atmel mit 512byte ram, kann das schon zu viel sein. aber eigentlich braucht man ja nur 8 werte in der Tabelle, denn die kleinere bits sind ja dann alle 1
mir gefällt die Methode mit dem Lookup Table und die Größe der Tables steigt eh nur linear mit der Bitbreite, also werden die auch nicht schnell groß. Allerdings sollte auch: auszumaskieren &= ( 2**n ) - 1 sehr schnell gehen, wie schon oben erwähnt, wenn der Controller einen Barrel Shifter hat, denn daraus macht der Compiler dann: auszumaskieren &= (1<<n) - 1 Wär interessant was der Compiler daraus macht.
Peter schrieb: > Klaus Falser schrieb: >> Das sind kleine Tabellen. > > auf einen Atmel mit 512byte ram, kann das schon zu viel sein. > > > aber eigentlich braucht man ja nur 8 werte in der Tabelle, denn die > kleinere bits sind ja dann alle 1 Außerdem müssen die nicht im RAM stehen.
angenommen, du hast maximal 8 bit (ansonsten einfach die Konstanten anpassen):
1 | 0xFF >> (8-n) |
Sind genau so viele shift- und subtraktions-Operationen wie
1 | (1<<n) - 1 |
aber vieleicht kannst du ja schon von vornherein mit 8-n statt n rechnen. Vielleicht kannst du auch die negierung davon
1 | ~(0xFF << n) |
wegoptimieren (weil du das Ergebnis sowieso negiert brauchst).
was spricht gegen:
1 | #include <avr/pgmspace.h> |
2 | |
3 | const uint8_t masks[] PROGMEM = { |
4 | 0b00000001, |
5 | 0b00000011, |
6 | 0b00000111, |
7 | 0b00001111, |
8 | 0b00011111, |
9 | 0b00111111, |
10 | 0b01111111, |
11 | 0b11111111 |
12 | };
|
13 | |
14 | main() |
15 | {
|
16 | // volatile damit WinAVR das nicht gänzlich wegoptimiert
|
17 | static volatile uint8_t auszumaskieren = 42; |
18 | static volatile uint8_t n = 4; |
19 | |
20 | // n = (...) //Aus irgendeiner Berechnung
|
21 | |
22 | auszumaskieren &= pgm_read_byte( masks + n ); |
23 | }
|
übersetzt: ... 0000008c <masks>: 8c: 01 03 07 0f 1f 3f 7f ff .....?.. ... 000000c6 <main>: auszumaskieren &= pgm_read_byte( masks + n ); c6: 90 91 01 01 lds r25, 0x0101 ca: 80 91 00 01 lds r24, 0x0100 ce: ec e8 ldi r30, 0x8C ; 140 d0: f0 e0 ldi r31, 0x00 ; 0 d2: e8 0f add r30, r24 d4: f1 1d adc r31, r1 d6: e4 91 lpm r30, Z+ d8: e9 23 and r30, r25 da: e0 93 01 01 sts 0x0101, r30 } de: 80 e0 ldi r24, 0x00 ; 0 e0: 90 e0 ldi r25, 0x00 ; 0 e2: 08 95 ret das sind 10 bytes code + 8 bytes masken im Flash und 7 Takte um von N auf die Maske zu kommen (Sorry schon mal imk Voraus, falls ich mich bei Bytes/Takten verrechnet haben sollte ;-)
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.