hi, gibts nen trick, wie man ohne division (durch bitmanipulation) integervariablen schnell durch 10 teilen kann? (AVR atmega) ich meine so wie man mit 10 multiplizieren kann mit (x<<3) + (x<<1)
einfach mit 12,8 multiplizieren und 7 bits weglassen. 12 ist einfach: x2 x2 x(2+1) 0,8 sind 4/5
Wenns nicht hunderprozentig genau sein muss könnt man z.B. mit 51 multiplizieren ((x<<5)+(x<<4)+(x<<1)+x) und anschließend um 9 bits schieben (also durch 512 teilen). Wäre dann ne Division durch ca. 10,04.
Neulich gab's hier mal einen Link, den ich leider grad nicht finde. Da war ein Xtreme Assembler Frickler ;-) am Werk der an der Division so lange geschraubt hat bis sie beinah mit einem halben Assembler-Befehl erledigt war...
@ Harald aus Erlangen du bist lustig. wenn ich durch 5 teilen könnte, könnt ich auch durch 10 teilen @Ladde: as ganze sollte schon genau sein. für die mult-shift-variante hatte ich mir mal ein script geschrieben (anhang, falls es interessiert), dass spuckt folgendes aus: ( x * 1 ) >> 3 = x * 0.125 ( x * 1 ) >> 4 = x * 0.0625 ( x * 3 ) >> 5 = x * 0.09375 ( x * 7 ) >> 6 = x * 0.109375 ( x * 13 ) >> 7 = x * 0.1015625 ( x * 25 ) >> 8 = x * 0.09765625 ( x * 51 ) >> 9 = x * 0.099609375 ( x * 103 ) >> 10 = x * 0.1005859375 ( x * 205 ) >> 11 = x * 0.10009765625 ( x * 409 ) >> 12 = x * 0.099853515625 ( x * 819 ) >> 13 = x * 0.0999755859375 ( x * 1639 ) >> 14 = x * 0.10003662109375 ( x * 3277 ) >> 15 = x * 0.100006103515625 ( x * 6553 ) >> 16 = x * 0.09999084472 ... Auf dem weg gibts also nix, was so richtig passt. bzw, die die genau genug sind, brauchen sehr große Zahlen (->Bibliotheksfunktionen), das heißt es führt das ganze schon ad absurdum, da man dann auch gleich ein /10 machen kann
Mark Brandis schrieb: > lange geschraubt hat bis sie beinah mit einem halben Assembler-Befehl > erledigt war... Alles wird gut... Hat dein Pfleger gerade Pause? ;o)
Für 8-bit Integer-Zahlen bekommt man mit folgenden Formeln exakte Ergebnisse: ((x+1)*51)>>9 (immer abgerundet) ((x+6)*51)>>9 (ab 0,5 aufgerundet) Gruß, Ladde
üblicherweise wird bei integer division abgerundet. Das ist essentiell, wenn man zahlen dezimal anzeigen will, da man den rest darstellt und mit der übrigen zahl die operation wiederholt, um die höheren Dezimalstellen anzuzeigen. das ist wohl der resultierende code der für 8bit richig rechnet.
1 | ;-----------------------------------; |
2 | ; RETRO (SYNTHETIC) DIVISION BY 10 ; |
3 | ; ANSWER IN R1, R0=REM, A:PRESERVED ; |
4 | ;-----------------------------------; |
5 | DIV10: PUSH B |
6 | LDI B,26 ;MUL BY 26 |
7 | MUL A,B ;R1=A/10 |
8 | PUSH R1 ;BRUTE-FORCE CALC OF REMAINDER |
9 | LDI B,10 ;CALC REM |
10 | MUL R1,B ;R0=10xR1(QUOT) |
11 | POP R1 ;RESTORE QUOT |
12 | SUB R0,A ;SUBTRACT REMx10 |
13 | NODJST: NEG R0 ;MAKE POSITIVE |
14 | BRPL NONEG ;STILL NEG? |
15 | ADD R0,B ;OOPS MAKE |
16 | DEC R1 ;ADJUSTMENTS |
17 | NONEG: RET |
habs noch nich nicht verifiziert. sieht aber erst mal logisch aus
Mein Vorschlag für 8-Bit unsigned Division durch 10 für Assembler bzw avr-gcc Inline-Assembler:
1 | uint8_t div10 (uint8_t x) |
2 | {
|
3 | uint8_t y; |
4 | asm("mul %1, %2" "\n\t" |
5 | "lsr %1" "\n\t" |
6 | "add %1, R0" "\n\t" |
7 | "mov %0, R1" "\n\t" |
8 | "clr __zero_reg__" "\n\t" |
9 | "adc %0, __zero_reg__" "\n\t" |
10 | "subi %1, lo8(-25)" "\n\t" |
11 | "sbci %0, hi8(-25)" "\n\t" |
12 | : "=d" (y), "+d" (x) |
13 | : "d" ((unsigned char) 25)); |
14 | return y; |
15 | }
|
Ladde schrieb: > Wenns nicht hunderprozentig genau sein muss könnt man z.B. mit 51 > multiplizieren und anschließend um 9 bits schieben Vlad Tepesch schrieb: > @A. K. > danke, sieht nett aus > @Ladde: > as ganze sollte schon genau sein. Der Link von A.K. Beschreibt die Methode von Ladde.
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.