Wurzel ziehen asm

Gast #111328
Lesenswert?

hi !
ich moechte (muss)messwerte auswerten.
hab max, min und mittelwert geschaft, brauche aber noch ne
standardabweichung (sigma) fuer die ich aber ne wurzel ziehen muss
(quadratwurzel)das ganze in asm.
hat jemand ne funktion oder ein tut wo ich das lernen kann??
gruss juergen
Gast #111331
Lesenswert?

das sind mir schon die richtigen Assemblerprogrammierer :-).
Wenns schwierig wird, einen Compiler die Arbeit machen lassen, sich das
Ergebnis reinkopieren und sich dann stolz auf Brust klopfen: das ganze
Programm reine Assemblerprogrammierung.
Gast #111333
Lesenswert?

ich habs früher auch gemacht, zu 51er-Zeiten. Hatte nur den
Keil-Compiler in der Uni zur Verfügung. Beispielprogramme geschrieben,
compilieren lassen und aus den Listings dann meine Assembler-libarys
gebastelt...
Wir hattens hier schon öfter: schreib doch gleich das ganze Programm in
einer Hochsprache.
Gast #111334
Lesenswert?

Hab das spasseshalber mal ausprobiert und folgendes Programm eingegeben
und für einen ATmega8 compiliert:

#include <math.h>

void main(void)
{
    float result, arg;

    arg = 2.;
    result = sqrt(arg);
}

Das Listing ist im Anhang, diese Zeilen verbrauchen 29% des Flash.
Hmmm....

Thorsten
Angehängte Dateien:
Gast #111335
Lesenswert?

ui ui jui !!!
da werd ich wohl nen problem bekommen aber besten dank thorsten!
muss jetzt aber leiden feierabend machen ;-}}}}}
ich werd mal ne nacht drueber schlafen......
vieleicht trifft man sich ja morgen hier wieder ....
thx
Gast #111336
Lesenswert?

google mal, irgenwo gibt es einen einfachen Algorithmus wie man eine
Wurzel zieht (hatte ich mir auch schonmal angeschaut, finde aber den
Links nichtmehr). Diese müsste kürzer sein und sich auch in Assembler
leicht implementieren lassen.
Gast #111340
Lesenswert?

Hallo,
es gibt das Heron verfahren. Dies geht als anäherung an die ganze
Sache. Leider weiß ich nicht mehr genau wie das geht. Aber es war
meines wissens mit den Grundrechenarten nicht sonderlich aufwendig.
Gruß
Peter
Gast #111341
Lesenswert?

http://www.avrfreaks.net/Freaks/freakshow.php?projectid=218&sid=c7bb4521aeb60002002e555444ca2b0e&offset=10&limit=1

; Very SMALL AVR code sqrt(num)
; adopted by Jack Tidwell
.def sqrt  = r0
.def numlo = r16
.def numhi = r17
.def subber = r24
.def subberh= r25

; Enter w/the 16bit number to take the sqrt of in r16,r17 (low/high)
Sqrt:
  clr  sqrt
  ldi  suber,1  ; initialize the seed to 1
  clr  suberh
loop:
  sub  numlo,subber
  sbc  numhi,subberh
  brlo  exit
  inc  sqrt
  adiw  subber,2  ; keep our "subber" ODD
  rjmp  loop
exit:
  ret             ; the sqrt(num) is in sqrt (r0), always an 8bit max


Nicht weiter von mir getestet.

Gruß hagen
Gast #111342
Lesenswert?

"Das Listing ist im Anhang, diese Zeilen verbrauchen 29% des Flash.
Hmmm...."


@Thorsten
Vielen Dank .

Ich mach seit 2 Jahren in assembler.
Und wollte eigentlich immer schon C können .
( alles nur für Privatgebrauch , nichts gewerbliches )

Bleibe wohl doch bei asm ...
Gast #111343
Lesenswert?

Naja, es macht schon einen gewissen Unterschied, ob man die Wurzel aus
einer 16bit-Variablen zieht und als Ergebnis eine 8bit-Ganzzahl-Nummer
bekommt oder ob es eine float-Zahl ist. Wenn die Genauigkeit reicht,
warum nicht? Meist wird es aber nicht genügen. Und bei obigem Beispiel
sind es nicht mal 7% des flashs. Dazu kommt: es zwingt dich ja niemand,
die Routinen des Compilers zu benutzen, gilt genauso für die
vielgescholtene printf(), einfach zu benutzen, leider relativ viel
Code. Wenn er reinpasst, schön, habe ich nur gewonnen. Kann aber
genausogut die Ausgaben "zu Fuss" machen (mach ich auch manchmal wenn
es knapp wird).
Gast #111344
Lesenswert?

Hm wo ist der Unterschied, die Fließkommazahl vorher zu scalieren ?
Ist im Grunde sogar noch "einfacher" da die Mantisse meisten kleiner
als der entsprechende Integer Bereich ist, somit wird die Sqrt() aus
der Manitisse gezogen mit obiger Routine, ist auch nur eine Binärzahl,
und der Exponent wird halbiert.

Gruß Hagen
Gast #791585
Lesenswert?

"
; Very SMALL AVR code sqrt(num)
; adopted by Jack Tidwell
.def sqrt  = r0
.def numlo = r16
.def numhi = r17
.def subber = r24
.def subberh= r25

; Enter w/the 16bit number to take the sqrt of in r16,r17 (low/high)
Sqrt:
  clr  sqrt
  ldi  suber,1  ; initialize the seed to 1
  clr  suberh
loop:
  sub  numlo,subber
  sbc  numhi,subberh
  brlo  exit
  inc  sqrt
  adiw  subber,2  ; keep our "subber" ODD
  rjmp  loop
exit:
  ret             ; the sqrt(num) is in sqrt (r0), always an 8bit max


"
kann mir jemand mal dieses Verfahren für das Wurzel ziehen schritt für 
schritt erklären.
#791615
Lesenswert?

Es wird von der ursprünglichen Zahl jeweils eine
andere Zahl, die die Folge 1; 3; 5; 7; 9; ... (ungeraden Zahlen)
durchläuft abgezogen. Und zwar solange, wie das Ergebnis
der Subtraktion größer als 0 ist. Dabei wird mitgezählt,
wie oft subtrahiert werden kann und diese Anzahl ist dann das
Ergebnis

Hmm. Ob das tatsächlich eine Wurzel ausrechnet?

sqrt(78)

78 - 1   -> 77                1 mal
77 - 3   -> 74                2 mal
74 - 5   -> 69                3 mal
69 - 7   -> 62                4 mal
62 - 9   -> 53                5 mal
53 - 11  -> 42                6 mal
42 - 13  -> 29                7 mal
29 - 15  -> 14                8 mal
14 - 17  -> kleiner 0

Das Ergebnis ist also 8

Ineressant. Zumindest bei diesem Beispiel scheint es zu
funktionieren.
Gast #791662
Lesenswert?

John Carmack in der ersten Doom Engine.:

__inline int Sqrt(float number)
{
    long i;
    float x2, y;
    const float threehalfs = 1.5f;

    x2 = number * 0.5f;
    y  = number;
    i  = * (long *) &y;      // evil floating point bit level hacking
    i  = 0x5f3759df - (i >> 1);             // what the fu**?
    y  = * (float *) &i;
    y  = y * (threehalfs - (x2  y  y));   // 1st iteration
    //y  = y * ( threehalfs - ( x2  y  y ) );   // 2nd iteration, this 
can be removed

    return (int) (1/y);
}
#791684
Lesenswert?

Kif wrote:
> Sollte es nicht
>
>    n-1
>   ----
>   \                         2
>   /     ( 2 * i ) + 1   =  n
>   ----
>   i = 0
>
> sein?

Ja.
Bin beim Versuch eines vollständigen Induktionsbeweises auch
darüber gestolpert.


Trivialfall, n = 1

                 2
      2*0 + 1 = 1

            1 = 1

Annahme: n stimmt, Rückführung auf n-1

                          2
   Annahme: S(i,0,n-1) = n

                         2
    S(i,0,n-2) = ( n - 1)
                                      2
    S(i,0,n-1) - ( 2 (n-1) + 1 ) = (n - 1)

     2                     2
    n  - 2 (n - 1 ) - 1 = n - 2n + 1

    2
   n   kürzt sich weg

   -2n + 2 - 1 = -2n + 1

       -2n + 1 = -2n + 1


qed
Gast #792187
Lesenswert?

sqrt(78)

78 - 1   -> 77                1 mal
77 - 3   -> 74                2 mal
74 - 5   -> 69                3 mal
69 - 7   -> 62                4 mal
62 - 9   -> 53                5 mal
53 - 11  -> 42                6 mal
42 - 13  -> 29                7 mal
29 - 15  -> 14                8 mal
14 - 17  -> kleiner 0

Das Ergebnis ist also 8

ist ja ein ganzen netter und relativ schneller allgotrithmus aber das 
ergebnis ist ja nicht 8 sonder in wirklichkeit 8,8 wie könnte man den 
code jetzt erweitern das man den rest auch noch berechnen kann
Gast #792199
Lesenswert?

Man könnte zB die Zahl um 100 skalieren, und anschließend das Ergebnis 
durch 10 teilen.
1  7799  >  1  mal
3  7796  >  2  mal
5  7791  >  3  mal
7  7784  >  4  mal
9  7775  >  5  mal
11  7764  >  6  mal
13  7751  >  7  mal
15  7736  >  8  mal
17  7719  >  9  mal
19  7700  >  10  mal
21  7679  >  11  mal
23  7656  >  12  mal
25  7631  >  13  mal
27  7604  >  14  mal
29  7575  >  15  mal
31  7544  >  16  mal
33  7511  >  17  mal
35  7476  >  18  mal
37  7439  >  19  mal
39  7400  >  20  mal
41  7359  >  21  mal
43  7316  >  22  mal
45  7271  >  23  mal
47  7224  >  24  mal
49  7175  >  25  mal
51  7124  >  26  mal
53  7071  >  27  mal
55  7016  >  28  mal
57  6959  >  29  mal
59  6900  >  30  mal
61  6839  >  31  mal
63  6776  >  32  mal
65  6711  >  33  mal
67  6644  >  34  mal
69  6575  >  35  mal
71  6504  >  36  mal
73  6431  >  37  mal
75  6356  >  38  mal
77  6279  >  39  mal
79  6200  >  40  mal
81  6119  >  41  mal
83  6036  >  42  mal
85  5951  >  43  mal
87  5864  >  44  mal
89  5775  >  45  mal
91  5684  >  46  mal
93  5591  >  47  mal
95  5496  >  48  mal
97  5399  >  49  mal
99  5300  >  50  mal
101  5199  >  51  mal
103  5096  >  52  mal
105  4991  >  53  mal
107  4884  >  54  mal
109  4775  >  55  mal
111  4664  >  56  mal
113  4551  >  57  mal
115  4436  >  58  mal
117  4319  >  59  mal
119  4200  >  60  mal
121  4079  >  61  mal
123  3956  >  62  mal
125  3831  >  63  mal
127  3704  >  64  mal
129  3575  >  65  mal
131  3444  >  66  mal
133  3311  >  67  mal
135  3176  >  68  mal
137  3039  >  69  mal
139  2900  >  70  mal
141  2759  >  71  mal
143  2616  >  72  mal
145  2471  >  73  mal
147  2324  >  74  mal
149  2175  >  75  mal
151  2024  >  76  mal
153  1871  >  77  mal
155  1716  >  78  mal
157  1559  >  79  mal
159  1400  >  80  mal
161  1239  >  81  mal
163  1076  >  82  mal
165  911  >  83  mal
167  744  >  84  mal
169  575  >  85  mal
171  404  >  86  mal
173  231  >  87  mal
175  56  >  88  mal
177  -121  >  Ergebnis negativ
#792235
Lesenswert?

weiterhin fällt folgende Gesetzmäßigkeit auf:

die Zahl x, die abgezogen wird, um eins addiert,
gebrochen 2 ist das Ergebnis:

>
>sqrt(78)

>78 - 1   -> 77                1 mal
>77 - 3   -> 74                2 mal
>74 - 5   -> 69                3 mal
>69 - 7   -> 62                4 mal
>62 - 9   -> 53                5 mal
>53 - 11  -> 42                6 mal
>42 - 13  -> 29                7 mal
>29 - 15  -> 14                8 mal
>14 - 17  -> kleiner 0

 erste Zeile: (1+1)/2=1
 zweite Zeile: (3+1)/2=2
 ...
 (vor)letzteZeile: (15+1)/2=8

Gruss
Stefan
Gast #792342
Lesenswert?

Hallo,
ich habe einmal eine Wurzelfunktion in AVR-Assembler geschrieben.
Allerdings für 64bit-Double.


http://www.martin-cibulski.de/atm/mount_controller_4/mc_4_asm_main/float_sqrt.asm

Die Funktion arbeitet mit einer Iteration. Vorlage war die Routine aus 
der 'Cephes'-Library von Steve Moshier.

http://www.moshier.net/doubldoc.html#sqrt

Gesucht sei: wurzel = SQRT(zahl)

Zuerst wird ein Näherungswert durch Halbieren des Exponenten gewonnen.
-> naeherung

ITERATION (
Dividieren: ergebnis = zahl / naeherung
Neue Näherung: naeherung = 0.5 * (ergebnis + naeherung)
)

Diese Interation konvergiert in 4 Durchgängen auf 16 Dezimalstellen.

Gruß,
Martin

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren