hallo, ich habe mal wieder ein noob problem:
ich wollte eigentlich bloß eine Wurzelfunktion erstellen:
Jedoch wenn ich ich im Prog dann 4 eingebe kommt am Ende 2.001 raus, könnte das tzwar umgehen, aber wo liegt der Fehler?![]()
hallo, ich habe mal wieder ein noob problem:
ich wollte eigentlich bloß eine Wurzelfunktion erstellen:
Jedoch wenn ich ich im Prog dann 4 eingebe kommt am Ende 2.001 raus, könnte das tzwar umgehen, aber wo liegt der Fehler?![]()
Wieso benutzt du nicht einfach die eingebaute Wurzel-Funktion? Oder wenigstens einen vernuenftigen Algorithmus, und nicht Bruteforce?
wusste zwar nicht das es eine Wurzel Funktiojn ist, aber ich wollte esja eh als Übung machen und was Bruteforce ist weiß ich noch nicht, bin noch Anfänger, aber uhrsprünglich war das Programm so, also ohne die Verschönerung, wenn du das meinst:
Was da passiert?
Ich gebe eine 4 ein und als Wurzel bekomme ich 2.001 zurück.
Das was ich in dem anderem eingegeben habe sollte nur zeigen das bei b*b 4 am Ende rauskommt und a 4ist aber dass b*b kleiner als a scheint, was nach meiner Logik sehr seltsam ist oder?
Dachte eigentlich auch du hättest recht, aber:
Anderer Code, gleiches Ergebnis
Euch ist schon klar, das man so etwas normalerweise über Lookuptables und Interpolieren rechnet, oder?
Nun, mir nicht bin aber auch noch Anfänger,aber es ist eh nur eine Übung, bei der ich aber nicht versteh weshalb das falsch läuft!
Okay, ich hab' mich gerade hingesetzt und ein klein wenig gerechnet: Die Quadratwurzel sollte sich über das newtonsche Näherungsverfahren ermitteln lassen. Ich habe das ganze jetzt für den speziellen Fall aufgelöst und bin auf folgende Funktion gekommen:
x_{n+1} = (x_{n} + z/x_{n})/2
In dem Fall näherst du dich an die Wurzel von z an, wobei du mit n immer durch iterierst. Soll heißen: Du rechnest dir erst immer x_{0} aus, dann x_{1}, usw. Bis das Ergebnis deiner Meinung nach genau genug ist.
Warum das nicht verwendet wird, siehst du hier auch recht gut: Das ganze ist eine Reihe und somit wird immer wieder das Selbe neu ermittelt. Je nach Zahl und Fall muss auch immer besser angenähert werden. Dadurch braucht das ganze erstens immer recht viel Zeit, und zweitens auch immer je nach Genauigkeit wieder länger, oder eben nich.
Darum löst man das normalerweise eben über eine Lookup-Table: Hier habe ich schlichtweg eine Liste, die vom kleinstmöglichen Wert, bis zum größtmöglichen Wert in vielen Unterschritten die Wurzel bereits ausgerechnet. Wenn ich jetzt zum Beispiel die Wurzel von 1 wissen will, dann suche ich in der Liste das passende Ergebnis. Wenn ich jetzt aber die Wurzel aus 1.2 haben will, und dieser Wert ist nicht in der Liste, dann suche ich mir die beiden Werte heraus,z wischen denen diese Zahl steht. Sagen wir einmal, es sind 1 und 2.
Laut unserer Liste wissen wir also, das unser Ergebnis zwischen 1 und 1.41421 liegen muss. Darum interpolieren wir zwischen den beiden Werten. Um an ein möglichst genaues Ergebnis finden zu können, überlegen wir uns einmal, wie eine Wurzel-Funktion aussieht:
http://www.mathematik.net/wurzel-fkt/WF1S10P4.gif
Jetzt suchen wir uns also eine Funktion, die dieser Kurve recht nahe kommt. Wir machen es uns einfach und interpolieren einfach linear: Wir rechnen uns also die Steigung aus, verlagern geistig die Axen und ermitteln den Punkt auf dem ca die gewollte Wurzel liegt. Und schon haben wir es geschafft.
Da du programmieren lernen willst, gebe ich dir noch einen Tipp:
#define BR cout<<'\n';
Verwende so etwas niemals. Verwende den Praeprozessor nur dann, wenn es sein muss. Also, wenn du zum Beispiel zwischen Versionen unterscheiden willst, oder etwas dergleichen. Wenn deine Projekte einen gewissen Umfang übersteigen, dann wirst du bemerken, das ein großer Teil der Compile-Time vom Praeprozessor verbraucht wird.
Außerdem macht das den ganzen Source unübersichtlich. Verwende lieber Konstante Werte, inline-Funktionen, etc.
ok, dein Vortrag, klang ziemlich wissenschaftlich, x_{n+1} = (x_{n} + z/x_{n})/2, habe ich ehrlich gesagt nicht verstanden, weil x_{n+1} mir nicht sagt was das x ist und was das{}ist, aber ich denke ich habe verstanden was du mit der schnelleren Wurzelfunktion meinst, nämlich das die groben Werte schon vorgegeben sind.
Auch das mit define habe ich eingesehen, aber jetzt noch zwei Fragen:
1. Wie benutzt man dann diese schon vorgegebene Wurzelfunktion?
2. Weshalb wird dann der Code von mir( auch wenn er nur bei kleineren Zahlen geeignet ist ) falsch gewertet, also dass bei Wurzel aus 4 2.001 rauskommt? Anscheinend scheint er ja b*b=4 und a=4 ja nicht als gleich anzusehen.
@Mog:
Sry, das ich deine x_{n+1} = (x_{n} + z/x_{n})/2
Funktion nicht verstandfen habe, aber eigentlich habe ich ne 2+ in Matte![]()
1)
C: #include <math.h>, bzw. cmath in Cpp.
double sqrt(double x)
2) && @:
Siehe was ich geschrieben habe, das ist eine ganz einfache Formel.
X_{b} bedeutet eigentlich nur, das ein b nach dem X tief gestellt steht. Schau dir mal den Anhang an, so angeschrieben verstehst du es sicher.
ok, deine Funktion habe ich jetzt auch verstanden, aber immer noch mein Hauptproblem:
Warum kommt eine höhere Zahl raus,(immer um 0.001)?
Der code ist doch richtig, oder?
Versucht doch sonstmal das Programm selbst zu compilieren.
Seltsam, bei mir gibt er jetzt bei einer 1 1.00 zurück, also den richtigen Wert.
Aber gib mal 4 ein oder 100 und es kommt 2.001 oder 10.001 raus!
Ich empfehle dir noch, b als Parameter herauszunehmen und innerhalb der Wurzelfunktion erst zu initialisieren, denn so wie es da steht macht es etwas wenig Sinn.
Zu deinem Problem kann ich gar nichts sagen, da bei diesem Programm mein Compiler nur Fehlermeldungen ausspuckt.![]()
--Electrodynamics:
Könnte noch am ehesten an der internen Darstellung der Zahl liegen. Da die Zahlenspeicherung ja zu Basis zwei funktioniert, kann das 0.001, das du bei jeder Schleife dazuzählst, nicht ganz genau gespeichert werden. Bei einem Mal würde man das nicht merken, aber da bei der Berechnung der Wurzel aus 2 der Wert ja 2000 Mal addiert wird, ist die Iteration vor 2.001 wahrscheinlich nicht genau 2, sondern ganz knapp darunter. Dadurch wäre b² natürlich auch unter 4, und die Schleife würde erst bei der nächsten Iteration abbrechen.
Das eheste, was du dagegen tun könntest, wäre, 0.001 z.B. durch 0,0009765625 zu ersetzen, das ist 1/1024 und sollte dadurch, glaube ich, genau darstellbar sein.Allerdings würde es dann bei nicht-ganzen Wurzeln natürlich weiterhin zu Fehlern kommen.
@drunken monkey:
![]()
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Es geht tatsächlich!!!!
ok, dann nehme ich ab nun nur noch durch 2^x teilbare Zahlen für so was!
Hier noch mal was am Ende dabei rauskommt:
@TheBiber:
Das müsste aber eigentlich gehen, ist ein C++ Projekt
Mfg Tridestaros
Daß C++ theoretisch portabel ist bedeutet nicht, daß auch beliebiger Code überall läuft. Besonders von Windows-Usern geschriebene Tutorials und Bücher verweisen gerne auf Windows-spezifische Header wie <conio.h> und selbst harmlos erscheinende Ausdrücke erweisen sich als fast(!) überall gebräuchliche aber letztendlich nicht ISO-konforme Erweiterungen.
Dazu kommen noch unterschiedliche Compiler... Was dir der Visual C++-Compiler durchgehen läßt kann GCC 3.3 unter Cygwin dazu bringen, dich mit Warnungen zu überfluten - und GCC 4 für Linux bricht gleich mit einer Fehlermeldung ab, von Apples GCC-Version für OS X ganz zu schweigen. Oder von --pedantic.
Wenn du willst, daß dein Code überall läuft, mußt du schon aufpassen, was du schreibst und möglichst portable Bibliotheken verwenden (und im Idealfall auf mehreren Plattformen testen). C++ ist in dieser Hinsicht nicht gerade die einfachste Sprache, dafür hat man extrem viele Möglichkeiten.
BTW, deine BR()-Funktion ist ziemlich häßlich. Du wirst weit besser damit fahren, wenn du stattdessen einfach an das letzte cout ein << endl anhängst. Das ist nicht nur lesbarer sondern auch schneller, da der Compiler solche Funktionen nicht immer wegoptimiert und jeder einzelne Funktionsaufruf Zeit kostet.
Na ja, kann ja sein das Compiler das verschieden sehen, aber so falsch kann dieser Code doch nicht sein, das mann ihn nicht compilieren kann![]()
Außerdem funktioniert end1 bei mir nicht, was ich zwar schon versucht habe allerdings nicht geklappt hat.