Forum: Mikrocontroller und Digitale Elektronik integer durch 10 teilen


von Vlad T. (vlad_tepesch)


Lesenswert?

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)

von Harald aus Erlangen (Gast)


Lesenswert?

einfach mit 12,8 multiplizieren und 7 bits weglassen.

12 ist einfach: x2 x2 x(2+1)

0,8 sind 4/5

von Ladde (Gast)


Lesenswert?

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.

von Mark B. (markbrandis)


Lesenswert?

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...

von Vlad T. (vlad_tepesch)


Angehängte Dateien:

Lesenswert?

@ 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

von (prx) A. K. (prx)


Lesenswert?


von Magnus Müller (Gast)


Lesenswert?

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)

von Vlad T. (vlad_tepesch)


Lesenswert?

@A. K.
danke, sieht nett aus

von Anon Y. (avion23)


Lesenswert?

Schöner Link, ist jetzt in den bookmarks. Danke.

von Ladde (Gast)


Lesenswert?

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

von Vlad T. (vlad_tepesch)


Lesenswert?

ü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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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
}

von Alexander S. (esko) Benutzerseite


Lesenswert?

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
Noch kein Account? Hier anmelden.