Assembler- wie geht das am schlausten?
Ich habe als Input eine Zahl x und eine Zahl n die jeweils 8 Bit haben.
Ich will folgende Funktion implemntieren f(x) = (x * 2^-n) aufgerundet
Ich weiß das (x/2) abgerundet einfach einen schift nach rechts bedeutet. Aber über das aufrunden frage ich mich wie es am schlausten geht. Mir vielen 2 Möglichkeiten ein
- Ich runde zunächst einfach das Ergebniss ab in dem ich x, n mal nach rechts schifte. Wenn ich einmal ein Carry hatte muss ich 1 addieren und ansonsten nicht, dann wäre es doch aufgerundet ?
- Wenn x zu beginn ungerade ist addiere ich 1 dadurch wird es gerade. und dann rechne ich einfach durch n rechts shifts das Ergebnis aus.
Machen die Möglichkeiten Sinn ? gibt es bessere ?
3 Antworten
ähm...
wenn du 0b1001 (x=9) durch 4 (n=2) teilen willst, dann soll also 3 herauskommen... oder? denn: 9/4=2,25 aufgerundet 3
Methode 2:
0b1001 ist ungerade...und 0b1010/4=2,5 also 2... ==> falsch... oder?
Methode 1:
du brauchst also ein Flag (z. B.: GF0 general purpose flag#0 bei 8051), das dir sagt, ob du eine 1 rausgeshiftet hast:
mov R2, [n]
mov A, R2
jz done
mov A, [x]
clr GF0
loop:
clr C
rrc ; rotate right through carry
orl C, GF0
mov GF0, C
djnz R2, loop
jnb GF0, noceil
inc A
noceil:
mov [x], A
done:
Setze x=33, setze n=7.
Bei Methode 2 dürfte das schiefgehen.
Auf- und abrunden kannst du mit integer math, auch in assembly, indem du x vor dem teilen durch 2 inkrementierst.
Das ergibt dann für verschiedene x:
x x+1 (x+1)/2
0 1 0
1 2 1
2 3 1
3 4 2
...
Geht auch mit anderen Divisoren: Dividend erst linksschieben, dann Integerdivision durch beliebigen Divisor, Integerquotient inkrementieren und dann rechtsschieben. Läßt sich so auch in eine generische Integerdivsionsfunktion mit Ergebnisrundung einbringen.