; Dieses Programm berechnet die Wurzel eines
; 32-Bit-Unsigned-Integer-Ausdrucks (d.h. bis
; max. 4.294.967.295) per Intervallhalbierung.
; Ergebnis=SQRT(n) aufgerundet.
; Ein- und Ausgabe:
; d0    Eingabe, bleibt erhalten
; d1    obere Grenze des Intervalls = Ergebnis
; d2    untere Grenze des Intervalls
; d3,d4 Rechenregister
; a0    Zeiger auf Wertetabelle

exakt equ 1   ; Genauigkeit (zwischen 1 und 8)

SQRT:
  movem.l d2-d4/a0,-(sp)  ; Register sichern
  moveq   #0,d2   ; untere Grenze löschen
  moveq   #0,d1   ; obere Grenze löschen
  moveq   #30,d3  ; Bit-Zähler setzen
  move.l  d0,d4   ; Wert in Rechenregister
  beq.s   sqrt_6  ; n=0 -> keine Rechnung !
  swap    d4      ; oberes Wort
  tst.w   d4      ;  testen
  bne.s   sqrt_11 ; Sprung, wenn <> 0
  moveq   #14,d3  ; nur noch unteres Wort
  move.w  d0,d4   ; untersuchen
sqrt_11:
  move.w  d4,d2   ; zu untersuchendes Wort merken
  and.w   #$ff00,d4 ; oberen 8 Bit untersuchen
  bne.s   sqrt_12   ; sind gesetzt -> Sprung
  subq.w  #8,d3   ; 8 Bit weiter
  move.w  d2,d4   ; Wort nochmal holen
  lsl.w   #8,d4   ; unteren 8 Bit untersuchen
sqrt_12:
  asl.w   #1,d4   ; oberstes Bit suchen
  dbcs    d3,sqrt_12  ; wenn CarrySet := gefunden

  add.w   d3,d3   ; * 2 := auf Wortgrenze legen
                  ; Zeiger auf Werte berechnen
  lea     sqrt_tab(pc,d3.w),a0
  move.w  (a0)+,d2  ; untere Grenze holen
  move.w  (a0),d1   ; obere Grenze holen
  bra.s   sqrt_5    ; Ende erreicht?
sqrt_2:
  move.l  d2,d4   ; obere Grenze und
  add.l   d1,d4   ; untere Grenze addieren
  lsr.l   #1,d4   ; Mittelwert bilden: m=(og+ug)/2
  move.l  d4,d3   ; m merken
  mulu    d4,d4   ; m quadrieren
  cmp.l   d0,d4   ; Test: Ist m*m > n ?
  bgt.s   sqrt_4  ; ja -> springen
sqrt_3:           ; obere Hälfte enthält
                  ; gesuchten Wert
  move.l  d3,d2   ; untere Grenze = m
  bra.s   sqrt_5
sqrt_4:           ; untere Hälfte enthält Wert
  move.l  d3,d1   ; obere Grenze = m
sqrt_5:
  move.l  d1,d4   ; Differenz bestimmen
  sub.l   d2,d4   ; delta = obere - untere Grenze
  subq.w  #exakt,d4 ; delta = < exakt ? , Konstante
                    ; bestimmt die Genauigkeit
                  ; Differenz zu groß, weiterrechnen
  bgt.s   sqrt_2
  move.l  d2,d4
  mulu    d4,d4   ; untere Grenze quadrieren
  cmp.l   d4,d0   ; Vergleich mit n
  bgt.s   sqrt_6  ; Test, ob untere Grenze das
  move.l  d2,d1   ; Ergebnis ist
sqrt_6:
  movem.l (sp)+,d2-d4/a0  ; Register restaurieren
  rts

  dc.w  0
sqrt_tab:         ; Wurzel-Intervall-Grenzen | Bit
 dc.w 1,2,3,4,6,8,12,16                      ; 0-7
 dc.w 23,32,46,64,91,128,182,256             ; 8-15
 dc.w 363,512,725,1024,1449,2048,2897,4096   ; 16-23
                                             ; 24-31
 dc.w 5793,8192,11586,16384,23171,32768,46341,65535

