Sie sind nicht angemeldet.

  • Anmelden

1

29.06.2003, 17:18

Kleine Denkaufgabe...

...für alle die sich mit C++ oder generell Programmieren oder Logik auskennen.

Ich hab mich mal drangesetzt und mein erstes richtig schönes kleines Programm geschrieben, nen Taschenrechner. Nich son billigen sondern Quasi den Ferrari unter den billigwn Taschenrechnern :)

Kommen wir zum Punkt. Der Rechner kann unter anderem mittels einer Näherungsroutine jede ganzzahlige Wurzel einer beliebigen Zahl bis auf 6 Nachkommastellen genau ausrechnen ohne das man für sehr große Zahlen Minuten braucht. War nicht so einfach das hinzukriegen, hat allerdings nen Schönheitsfehler. Aus mir nicht ersichtlichen Gründen weicht das Ergebnis bei einigen zahlen um 0.000001 ab. Sollte nicht wirklich stören, aber ist doch irgendwie doof wenn die Quadratwurzel von 4 2.000001 ist. Bei 9 klappt es, bei 16 auch, aber die 4 geht nicht.

Wer es also schafft sich durch das Programm zu denken, den Ablauf kapiert und mir dann erklärt wie der Fehler entsteht und wie er behoben werden kann, dem geb ich auf der nächsten Masterslan ein Bier oder alternativ ne MezZo-MiX aus.

Der gesamte Quelltext ist dokumentiert und es sollte nicht so schwr sein ihn zu verstehen. Bin mal gespannt wer das hinkriegt, viel Spass.

Hier der Link zum geupten Quelltext und dem fertigen Rechner.

Rechner
May heaven be with u and faith guide ur way, Brödschn. And may ur greedients be not gen-maniplated&#33;<br><br>OredE_dA_BroEdlA aka Broetchenholer

2

29.06.2003, 17:42

Also deinen Quelltext habe ich angelesen, aber besonders gut in C++ bin ich nicht, ich habe allerdings zumindestens eine Vermutung, wo 2.000001 herkommt.

Der Rechner arbeitet intern ja nur mit 0 und 1, Dezimalzahlen sind da keine Ausnahmen. So stehen ihm für Kommazahlen nur Summen von negativen Zweiterpotenzen zur Verfügung.

Negative Zweierpotenzen heisst 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625 usw. - damit ist es aufwendig, 0.00001 aufzubauen. Versuch mal 0.1 als Summe negativer Zweierpotenzen auszudrücken, bei 0.00001 dürfte der Aufwand viel grösser sein und die Summanden müssen bis WEIT hinter den sechs gewünschten Genauigkeitsstellen berechnet werden.

Ich würde das Ergebnis ganz einfach überprüfen und gegebenenfalls kosmetisch nachbearbeiten anstatt Tonnen von Algorithmen hinein zu stecken. 8)

-=)GWC(RaMsEs

unregistriert

3

29.06.2003, 19:24

ohne den code gelesen zu haben muss ich als c+ und java coder sagen das das schäfchen da ziemlich recht hat. das problem mit wurzeln ist eben das es net genau passt. rundungsfehler und die interne andee berechnung führen zu ungeremtheiten, die sich dann eben in der 6. nachkommastelle auswirken. geh doch mal mit dem debugger durch!

hm, oder ,, hab halt net viel zeit, sag was du eingegeben hast und ich kuck mal danach k?

4

29.06.2003, 20:59

Bei C++ gibs doch schon ein vordefiniertes Mathe Paket und dessen Wurzel Funktion war net schlecht , mach einfach

if(zahl<1000)
{
ergebnis =wurzelfunktion_aus_mathepaket(zahl)
}

else
{
ergebnis=da_broedlas_wurzelfunktion(zahl)
}

cya max

-=)GWC(RaMsEs

unregistriert

5

29.06.2003, 21:28

sdas hiess sqrt ;)

6

29.06.2003, 23:07

Das weiß ich schon MaxPower, aber das wäre nicht dasselbe, der Reiz am selbst pr0-grammieren ist doch das man selbst programmiert.

Zu Sheeps und Ramses Idee kann ich nur soviel sagen.
Das ganze arbeitet mit ner Schleife die ( zur Verienfachung gehen wir mal nur von ner Quadratwurzel aus) pro Schleifendurchlauf einen wert inkrementiert und dann quadriert. Anschließend wird dann geprüft ob das Ergebnis der Quadrierung >= meiner basis ist. Durch die Routine wird gewährleistet das die Inkrementierung umso kleiner wird desto näher man an das Ergebnis kommt wodurch die letzten Inkrementierungen eben nur noch um 0.000001 sind. Bei meinem Beispiel Wurzel4 bedeutet das folgendes:
er macht einen Durchgang mit 1.999999, quadriert das und merkt das die Zahl kleiner ist. Also erhöht er meine Zahl um 0.000001. Jetzt überprüft er ob 2.000000 hoch 2 >= 4 ist. Das Programm sagt jetzt das das nicht der Fall wäre und erhöht auf 2.000001 welches er dann auch als größer 4 erkennt. Ihr meint also das er es nicht schafft die zahl 2 zu bilden so das die nachkommastellen stimmen?
Rundungsfehler scheiden ja aus, sonst würde mein Ergebnis zu klein sein.
Das mit dem Debugger musst du mir mal erklären, hab den noch nicht benutzt und hab auch keine Ahnung wie das funktioniert :)

7

29.06.2003, 23:59

Ich schlage folgende, geniale wie einfache Idee vor : du näherst dich mit deiner Schleife auf 7 Nachkommastellen genau an den Wer an, und gibst dann nur 6 Nachkommastellen aus.

Oh man, gibs zu : ich bin genial :D

cya

euer realitätsfremder, durchgedrehter MaxP0W3R

Partizan_ch

Erleuchteter

Beiträge: 3 349

Wohnort: Jugoslawien

Beruf: CH

  • Nachricht senden

8

30.06.2003, 00:17

dann kommt aber 2.000000

9

30.06.2003, 00:47

besser als wenn bei Wurzel 4 =2.0000001 kommt oder ?

10

30.06.2003, 10:44

Das könnte klappen, ist allerdings nicht die geilste aller Möglichkeiten ^^

Mal abwarten ob noch jemand ne geilere Idee hat.

DRDK_TaCtaR__

Fortgeschrittener

Beiträge: 252

Wohnort: Lustenau

Beruf: AUT

  • Nachricht senden

11

30.06.2003, 11:41

wieso nicht einfach noch ne schleife dazu, die alle am ende stehenden nullen abschneidet?

12

30.06.2003, 11:44

Hm, was würde das denn bringen? Denn theoretisch sind es ja nicht die Nullen die stören, sondern die anderen Zahlen. Das musst du nochmal erläutern, verstehe den Vorschlag nicht ganz, denke ich.

BitteLöschen!

unregistriert

13

30.06.2003, 12:29

Ich glaube er meinte das im verband mit SiA__MaxP0W3R's Idee:)
Dann machts ordentlich sinn:D

14

30.06.2003, 15:04

Du hast aber nicht noch so´n ollen Pentium I mit Rundungsfehler oder Broedla? :D ;)

15

30.06.2003, 15:24

@Broetchenholer: Probier doch mal, die Kommazahlen als ganze Zahlen in einem möglichst grossen Integer-Typ darzustellen.

Zum Beispiel deine 4 in einem 16-Bit-Integer (vorzugsweise alle Werte positiv für grössere Zahlen).

Grösster möglicher Wert bei 16 Bit ist 65536.
Wir setzen 4 als 40000 an, die neue Zahl sollte eine gerade Anzahl von angehängten Nullen haben.
Wir halbieren die Anzahl der Nullen und setzen 100*100 an, mit x=1 macht man nix verkehrt.
Wir erhöhen nach irgendeinem Algorithmus mit möglichst wenig Rechenaufwand die 100 allmählich, bis das Produkt das Ziel erreicht bzw. überschreitet. Falls es genau erreicht wurde, sind wir natürlich fertig.
Falls es überschritten wurde, in immer kleineren Schritten abwechselnd von unten und oben annähern (Multiplizieren des Änderungssummanden mit -1 erspart etwas Code).
Falls selbst +1 oder -1 das Ergebnis nicht trifft, abbrechen.

Das Ergebnis wird um die "geschenkten" Nullen nach rechts verschoben, im Beispiel wird aus 200 eine 2.

Ganzzahlige Werte haben den Vorteil, 100%ig präzise zu sein, für jeden möglichen Wert gibt es intern eine Bitkombination.

16

30.06.2003, 15:40

Wenn ich deine Argumentation recht verstehe bedeutet sie soviel: weil der Comp es nicht schafft die 6te Nachkommastelle richtig zu berechnen, macht er aus meiner 2.000000 in wirklichkeit irgendeine 1.9999996. Da ich aber nur 6 Nachkommastellen anzeige rundet er es auf zu exakt 2.000000, rechnet aber mit der genaueren Zahl weiter, richtig? Was mich in erster Linie daran stört ist die Tatsache das dieser Fehler nur manchmal und auch nur beim eigentlich richtigen Ergebnis auftritt. Man würde ja vermuten das diese Schwierigkeit bei jeder so kleinen Berechnung auftritt und umso mehr ich davon habe umso ungenauer wird das Ergebnis. Allerdings hatte ich genau das selbe Problem auch schon bei Routinen wo die Inkrementierung anders ablief, zum Beispiel die letzten 2 und nicht 0.01 unterschied von Näherung und Ergebnis mit Inkrementierungen um 0.000001 berechnet wurden. Den Fehler gab es immer und es war immer genau ein Schleifendurchganz zuviel. UND das Problem trat auch schon auf als die minimal Inkrementierung um 0.0001 oder höher war.
Allerdings rundet er tatsächlich auf wenn er nicht alle Stellen anzeigen darf....Grml...mal schauen was ich da machen kann.

@Disa...ich habe keinen qualifizierten Kommentar von dir erwartet ^^

17

30.06.2003, 15:46

Zitat

Original von OredE_Broetchenholer
@Disa...ich habe keinen qualifizierten Kommentar von dir erwartet ^^


Ich kann mir einen Taschenrechner leisten,
ich muss mir keinen basteln :D

18

30.06.2003, 16:05

Gnargh, ihr habt recht... komischerweise passiert es aber recht willkürlich, 2w100 ist 10.000001, 2w1000 ist 100.

Die Idee von sheep muss ich mir mal durch den Kopf gehen lassen.

@ Disa: Ích kann mir einen leisten und mir einen Basteln, was ist geiler? ^^

19

30.06.2003, 16:10

So... ich habe jetzt meine Abbruchbedingung leicht verändert. Er überprüft jetzt ob meine Näherung + 0.000000001 >= der zahl ist. Damit funktioniert es zumindest bis hoch zu 10 Milliarden theoretisch, die 2 und die 100 funktionieren jetzt auch, ich hoffe das damit die Zahlen dazwischen auch abgedeckt sind.

Das Bier oder was sie wünschen spendiere ich somit auf der nächsten mastersLan Sheep und Ramses, schreibt einfach mal was ich euch mitbringen darf ^^

Und danke an alle die sonst noch mitgeholfen haben, ausser disi, der is doof.

20

30.06.2003, 16:11

Uhmm

Also ich finde es geiler,
Programme zu schreiben, die es noch nicht gibt (= Individualsoftware) und dafür so viel Kohle zu kassieren, dass ich mir die Programme leisten kann, die es schon gibt ;)

Noch geiler finde ich es allerdings, andere programmieren zu lassen und nur bissl zu coachen wie jetzt gerade :D

21

30.06.2003, 16:22

Soviele wie den Rechner schon gedownt haben kann ich ihn in eBay fürn Schweinegeld verhökern, das ist doch was ^^

-=)GWC(RaMsEs

unregistriert

22

30.06.2003, 16:34

danke broetchenhola, mal kucken vielleicht komme ich ja deswegen zur lan ;)
@sheep was hälst du von martini? ;)

kömmer ja ein bisschen c++ fachsimpeln ;)

btw deine idee ist ja schon gut nen " geilen" taschenrechner zu bauen, aber ich würde da die schwerpunkte anders legen, sprich für die elemtarsten funktionen ( + - * / ) fertige funktionen nehmen ( also pwr und sqrt und so ) aber den eingabeunfang und komfort vergrössern. zum beispiel geiles menü!

deine idee nen ganzen string zu parsen und dann zu verarbeiten ist fein, geht aber auch einfacher. weiss jetzt net genau ob du das auch so egamcz hast aber ich seh es halt als etwas kompliziert an. ich würd halt deneingabestring verifizieren ( also leerzeichen raus und so mist), dann parsen nach einzelnen klammerabschnitten, dann von innen raus mit einfachsten funktionen auflösen. kannst ja zum beispiel rekursiv machen, oder wenn dir das zu unübersichtlich ist ( naja wen sich funktionen selber aufrufen ist imemr viel denkarbeite dabei) den string in kleinste teile zerlegen, variablen vergebe und dann in ner hash tabelle oder vektor oder pointerfeld die einzelnen substrings ableghen die abgearbeitet werden.

es besser zu machen indem man die basisifunktionen neu schreibt halte ich net für ne verbesserung.....

23

30.06.2003, 16:52

Mir is gerade wirklich scheiss fad ^^

Naja, für die elementarsten Funktionen benutze ich ja auch die buildinfunktionen, schließlich rechnet er ja das plus mit einem ganz normalen operator + aus :)

Aber leider gibt es halt keine Prozedur die mal kurz nen Eingabestring von hinten nach vorne nach der Addition durchsucht deshalb musste ich das selbst machen.

Ausserdem gibt es keine Funktion die die 4te Wurzel berehen kann ( ich habe nen minignu++ 3.2 compiler benutzt, der hat weder nen editor noch eine dokumentation...wordpad programmieren rockt) und mein wissen über Standartfunktionen komt im wesentlichen aus nem Taschenbuch mit 100 Seiten wo die gängigsten erklärt werden. Das erschwert das ganze halt :D

Und nen geiles Menü zu machen ist noch ein ganzer Schritt zu weit weg, dazu müsste ich nämlich mal schnell noch Windows-Programmierung können und das ist nochmal ein Kapitel für sich. Dafür müsste ich dann mein VC++ 5.0 nutzen aber da scheue ich mich etwas weil es mir mit Sachen wie Dokument-Ansicht-Struktur nich wirklich optimal zum direkten programmieren mit Windows geeignet is, die MFC ist einfach zu hoch angesiedelt.

Und im Prinzip macht er ansonsten genau das was du da beschreibst nur zerlege ich ihn nicht sondern lass ihn am Stück :)

24

30.06.2003, 17:00

Zitat

Original von OredE_Broetchenholer
Soviele wie den Rechner schon gedownt haben kann ich ihn in eBay fürn Schweinegeld verhökern, das ist doch was ^^


Viele gedownt und fürn Schweinegeld verhökern widerspricht sich aber jetzt irgendwie :D

Was heisst Dir ist fad?

Ich wäre froh, ich wär schon zu Hause, könnte Progys Progys sein lassen und einfach entspannt zocken ;)

Aber bevor ich angefangen habe zu arbeiten, habe ich auch privat vor mich hin codiert und experimentiert. Das verläuft sich dann schnell und mittlerweile habe ich nichtmal mehr den Nerv, mir in der Freizeit ne aktuelle Website zu machen ^^

-=)GWC(RaMsEs

unregistriert

25

30.06.2003, 17:13

tja ich muss für die Fh coden und nebnher lan-website aufbauen, in 3 woche nist klausur! udn ic hhab echte sorgen :(
stimmt aber. wenn du unter tags musst haste abends kein bock mehr..........

@broedle
hm das gehtabere auch einfacher, und wenn du eben die einzelnen teile abarbeitest udn ihn eben net am stück lässt gehts einfacher ;)
btw für menüs und so empfehle ich dir Borland CBuilder, etwas buggy und der anfang macht dich wahnsinnig ( kan ndir aber mal ne einführung geben da hat es nette pdfs) , zum beispiel wei les keine undo funktion gibt.
das ding ist aber objektorientiert, und duschreibst ja mit funktionen in c ( also keine OO). btw wie ich rausgelesen aheb hast du das net gelernt sonder slebst beigebracht? respekt!

26

30.06.2003, 17:49

Naja, auf diesem Niveau ist C noch nicht so schwierig, Schleifen und if-anweisungen erfordern ein gewisses verständnis für logik aber an sich ist da ja noch nix schweres dabei...sobald pointer dazu kommen wirds für mich schwer, da sitze ich erstmal ne Minute da und überlege welche adresse gerade wohin übergeben wurde und wo nur der wert....lala. Und wenns dann ins Objektorientierte geht wirds nochmal ein stück komplizierter. Und das dumme an der ganzen Sache is halt, wenn die Erfolge sehr schwer zu erzielen sind wird es für mich fast unmöglich mich zu motivieren ^^

27

30.06.2003, 21:22

Ich habe die Lösung für deinen Algorithmus gefunden und beanspruche eine Cola auf der nächsten Masterslan.

Also :

du brauchst 3Variablen vom Typ double

zahl : die Zahl aus der die Wurzel gezigen wird
wurzel : das Ergebnis, am Anfang auf 1 setzen
quotient : am anfang 1,



mach eine Schleife der Art

for ( quotient=1; quotient++; quotient < anzahlnachkommastellen;)

{
while((wurzel *wurzel) < zahl)
{
wurzel = wurzel + quotient;
// am anfang 1/1 also 1, dann 1/10, dann 1/100 usw...
} // while
if ((wurzel *wurzel) = zahl) break;

// jaja kein guter
/*programmierstil, aber so gehts am einfachsten und ganzzahlige ergebnise werden sofort ausgegeben ohne die ganzen nullen zu berechnen */

} // for


so ich muss wieder in die Kaserne, bin erst am Freitag wieder da...
EDIT : mist ist ein logikfehler drin hab jetz aber keine zeit mehr, aber das prinzip erklär ich dir am freitag
(hier wird das ergebnis "übersprungen")
cya max

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »SiA__MaxP0W3R« (30.06.2003, 21:25)


28

30.06.2003, 21:43

Hab jetzt auch keine Zeit es mir anzuschauen aber deine Cola kriegste wenn du da bist :)

29

04.07.2003, 14:39

so bin wieder hier, hier der korrekte alogrithmus für positive Quadratwurzelberechnung. Für komplizierte Sachen wie 3. Wurzel aus 17 oder negative Wurzeln ist ein komplett anderer Algorithmus notwendig, aberda müsste schon eine Grafikkarte bei rausspringen, dass ich den einfach so entwickle :D

#include <stdio.h>

int main ( int anzahl, char *argumente[])

{

long double zahl, wurzel, g;



wurzel = 1; // der kleinste mögliche wert
g=1; // die Genauigkeit

// hier kannst du anzahl der zu berechnenden
// nachkommastellen eingeben \/ ( hier 9)
while ( (wurzel*wurzel) < zahl) && (g<9))
{
wurzel = wurzel + ( 1 / g);
if ((wurzel * wurzel) > zahl)
{
wurzel = wurzel - (1/g); // aktuelle Genauigkeit erreicht
g++; // die nächste Nachkommastelle
// wird berechnet
} // if
} // while

} // main


sieht in der Eingabemaske des Forums ehr unübersichtlich aus X(


cya max

EDIT : noch ein Hinweis : bei Wurzel 4 z.B. berechnet der Algorithmus 4 und 9 nachkommastellen die alle 0 sind,

also 4.00000000

Mit den printf - Formatierungen kannst du dann je nach gewünschtem Ergebnis die zahl formatieren.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »SiA__MaxP0W3R« (04.07.2003, 14:41)