aufgabe 3b (März 2002)

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

aufgabe 3b (März 2002)
hallo…

ich wurschtel hier seit 2h an der Aufgabe 3b der Klausur März 2002 rum, und komm auf keine (fnktionierende) Lösung.

Wär kewl wenn die mal einer posten könnte!


Hallo,

ich glaube du meinst die Lösung für die Sinus-Approximation.
Meine Lösung sieht so aus, ich war auch eine halbe Ewigkeit drangesessen.

(define (sinus x)
  (define switch 1) ;switch wird für die Approximation gebraucht, 
                    ;siehe (improve ...)
  (define epsilon 0.001)
  
  (define (good-enough? oldval newval)
    (if (and (= oldval 0) (= newval 0)) #f    
        (< (abs (- newval oldval)) epsilon))) 
  
  (define (improve newval counter)
    (begin 
      (set! switch (modulo (+ switch 1) 2)) ;switch nimmt nur 0 oder 1 an und entscheidet über +/-
      (+ newval (* (expt -1 switch) (/ (expt x counter) (fac counter))))))
  
  
  (define (iter oldval newval counter)       ;oldval speichert den n-ten wert, newval den n+1-ten wert
    (if (good-enough? oldval newval) newval
        (iter newval (improve newval counter) (+ counter 2))))
  
  (iter 0 0 1))


(define (fac-mem)
  (define lastval 1) ;Speichere letztes Ergebnis in lastval (= last value)
  (define last_n 0)  ;Speichere letztes Argument des Aufrufs in last_n
  
  (lambda (n)
  
    (define (iter m acc)
   (cond ((= m 0)
          (begin 
            (set! lastval acc)
            (set! last_n n)
            acc))
         ((= m last_n) (iter 0 (* lastval acc)))
         (else (iter (- m 1) (* m acc)))))
  (iter n 1)))

(define fac (fac-mem)) ;<-- optional, sonst wirds umständlich

Anstatt in der good-enough? newval und oldval auf 0 zu prüfen, kann man auch andere Startwerte für die Iteration wählen.
Und die Sache mit dem wechselnden Vorzeichen lässt sich auch anders regeln.
Anstatt einen Switches, der nur zwischen 0 und 1 wechselt, kannst du auch den Zähler Modulo 4 teilen, dann erhälst du immer 1 und 3. Mit einer if/cond Abfrage kannst dann über das Vorzeichen entscheiden. (Idee mit dem Zähler stammt allerdings nicht von mir).

Gruß
Void


Ach du meine Scheisse, ich hoff mal des so´n Mist bei uns net dran ist, hab auch fast 2 Stunden dran gesessen aber keine Lösung gefunden, und auf die währ ich bestimmt net gekommen!!!


wieso so kompliziert?
nimm doch ein vorzeichen-counter in deine iteration. du kannst dir da naemlich einiges an arbeit sparen: Wenn der Vorzeichen counter auf ner ungeraden zahl steht, dann addiere und wenn der vorzeichencounter auf ner geraden zahl steht, dann subtrahiere. Und: nicht abschrecken lassen… wie man auf sowas kommt ist eigentlich nicht so schwer: auf der angabe ist ein Beispiel mit drauf, schau ob du irgendwelche muster findest die sich wiederholen und versuche sowas in eine Fallunterscheidung zu bringen. Auch bei mehreren variablen: das wichtige ist dass du schaust was sich veraendert. Variablen die du nur einmal brauchst, berechnest du irgendwo am anfang mal , belegst ne variable mit dem wert und setzt es ein wenn dus brauchst.

Wieso macht ihr euch eigentlich so mit dem set! verrueckt?
es geht wirklich einfacher

hier mein code

(define diff 0.01)

(define (fact x)
  (define (fac-iter prod counter)
    (if (= 0 counter)
        prod
        (fac-iter (* prod counter) (- counter 1))))
(fac-iter 1 x))



(define (sinus x)
  (define (good-enough? currentguess)
    (if (< (abs (- (sin x) currentguess)) diff) 
        #t 
        #f))
  (define (improve-guess countindex curguess vorz)
    (if (even? vorz) 
        (+ curguess (/ (expt x countindex) (fact countindex)))
        (- curguess (/ (expt x countindex) (fact countindex)))
        ))
  (define (sinus-iter x count currentguess vorzeich)
    (if (good-enough? currentguess)
        (Exact->inexact currentguess)
        (sinus-iter x (+ count 2) (improve-guess count currentguess vorzeich) (+ vorzeich 1))))
  
  (sinus-iter x 1 0 0)
  )

Des mit dem set! hat scho seinen Sinn, zB is deine Implementation von der Fakultät nach der Aufgabenstellung falsch, weil deine Fakultätsfunktion keine schonmal berechneten Fakultäten abspeichert.


oh… hm, das kleine detail hatte ich uebersehen, allerdings diese fakultaetsfunktion war eigentlich auch nur dazu da um zu sehen ob der rest geht (die hatte ich irgendwann frueher mal geschrieben).


Für die Fakultät verwendet man am besten auch eine Akkumulatorvariable:

[CODE](define epsilon 0.001)

(define (sinus x)
(define (loop sign e fak akk last-value)
(let ((value (/ (* sign (expt x e))
fak)))
(if (< (abs (- value last-value)) epsilon)
akk
(loop (* sign -1)
(+ e 2)
(* fak (+ e 1) (+ e 2))
(+ akk value)
value))))
(loop 1 1 1 0 0))

(exact->inexact (sinus -2))[/CODE]


und jetzt wieder eine folge aus :
“unser uebungsleiter hat aber gesagt …”
dass die bei solchen approximationsaufgaben immer eine dreiteilung des ganzen in ein praedikat, eine verbesserung des schaetzwerts und einen loop der das ganze steuert, haben wollen. nur so am rande. koennte sich aber als wichtig erweisen.


Danke für den Hinweis - muß ich irgendwie verpaßt haben :zzz:

Übrigens: die Verwendung der Standardfunktion sin ist nach Aufgabenstellung explizit verboten…


hat jmd ein ergebnis für die (a) der aufgabe ?
also die listentiefe.


mag schon sein, aber das ist auch nicht die loesung zu der aufgabe gewesen sondern zu einer anderen sinus approximationsaufgabe 3b/ 3.4.97 . und es ging mir bei diesem posting nicht darum wie ich meinen vergleichswert erhalte sonder lediglich um

  1. die 3teilung
  2. die unterscheidung der Vorzeichen bei jedem schritt der berechnung

Listentiefe
Meine Lösung der Listentiefe:

(define (list-depth liste)
  (cond ((null? liste) 1)
        ((list? (car liste)) (max (+ 1 (list-depth (car liste))) (list-depth (cdr liste))))
        (else (list-depth (cdr liste)))))

Hab’s so ähnlich gemacht:

(define (list-depth liste)
    (cond ((not (list? liste)) 0)
          ((null? liste) 1)
          (else (max (+ 1 (list-depth (car liste))) (list-depth (cdr liste))))))

Bei der Sinusapproximation darf man bei der good-enough doch die sin-Funktion aus Scheme nicht verwenden oder?
Mein Versuch:

(define epsilon 0.00000001)
(define (sinus x)
  (define (sinus-iter summe k fac)
    (if (good-enough? summe k fac) (improve summe k fac) (sinus-iter (improve summe k fac) (+ 1 k) (newfac k fac))))
  (define (good-enough? summe k fac)
    (< (abs (- (improve summe k fac) summe)) epsilon))
  (define (improve summe k fac)
    (+ summe (* (expt -1 k) (/ (expt x (+ 1 (* 2 k))) (newfac k fac)))))
  (define (newfac k fac)
    (if (or (zero? k) (zero? fac)) 1 (* fac (* 2 k) (+ 1 (* 2 k)))))
    
  (sinus-iter 0 0 1)
)

Hab beide Funktionen mit einigen Beispielen probiert und sie haben bisher immer funktioniert. In meinem nächsten Leben werde ich deren Korrektheit vielleicht mal formal nachweisen :wink:

Bei der Gelegenheit: Hat jemand schon die 4. Aufgabe versucht von dieser Klausur (03.2002) versucht?


max natürlich ! ich hab den ganz vergessen


aha, auf die max-funktion bin ich bis jetzt auch noch net gekommen…
hier die lösung unseres üb-leiters:

[code]; 2002-03/3a)

(define (list-depth ls)
(define max 1)
(define (iter depth ls2)
(cond ((null? ls2) (if (> depth max) (set! max depth) max))
((list? (car ls2)) (iter (+ depth 1) (car ls2))
(iter depth (cdr ls2)))
(else (iter depth (cdr ls2)))))
(iter max ls))

; Beispiel
(list-depth '(1 2 (3 (4 5)) (5 6 (7) 8)))

; → 3
[/code]

is mehr c-style, aber (IMO) einfacher zu verstehen… naja egal
und hier ist z.b. so eine funktion, die sich mehrfach iterativ aufruft (siehe thread “O-Notation”)