Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Lexington

Frischling

  • »Lexington« ist der Autor dieses Themas

Beiträge: 17

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

1

02.08.2012, 09:33

[gelöst] Long zu kurz für Zahl?

Hallo liebes Forum,

ich bin noch recht neu in der Welt der Programmierung und habe deshalb eine (für euch bestimmt :D) simple Frage:

Ich habe einige Übungen für C++ auf diversen Internetseiten durchgeführt und
Ziel dieser Aufgabe war die eingabe einer Zahl, deren Zahlenfolge durch eine Funktion invertiert werden soll.
(aus 1234 wird 4321).

Dazu habe ich zunächst die Stellen der Zahl ermittelt - was auch fehlerfrei funktioniert -
und danach die Zahl über den Modulo-Operator niedergebrochen.
Die somit ermittelten Einzelzahlen habe ich mit 10 und der Stelle in der Zahl als Exponent multipliziert und in einer temporären Variablen gespeichert.

Hier die Funktion:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void turn(unsigned long &tu_zahl, int tu_stellen)
{
     if(tu_zahl > 0)
     {
        l_TempErgebnis += tu_zahl%10 * pow(10, (tu_stellen) - 1);
        cout << "Ergebnis der Potenzrechnung: " << pow(10, (tu_stellen) - 1) << endl;
        tu_zahl /= 10;
        tu_stellen--;
        cout << "Ergebnis: " << l_TempErgebnis << "| Zahl: " << tu_zahl << "| Stellen: " << tu_stellen << endl << endl;;
        turn(tu_zahl, tu_stellen);           
     }
     else
     {
     tu_zahl = l_TempErgebnis;
     cout << "Endergebnis: " << tu_zahl << endl;
     }
}




Dieser Code funktioniert auch wunderbar. Auf der 32-Bit Maschine bis zu 7 Stellen und auf der 64-Bit Maschine bis zu 9 Stellen (hängt wahrscheinlich mit der unterschiedlichen Länge von long zusammen).

32-Bit:
Nun ja, am Anfang kam mir der Fehler, dass z.B. 123456789 zu 987654319 wird noch recht Spanisch vor, daher habe ich pro Durchgang eine Testausgabe erstellt. Und siehe da, der Fehler passiert schon beim ersten Durchgang der Funktion: Es wird in der Zahl 899999999 anstatt 900000000 in l_TempErgebnis gespeichert.
Das war schon nach der ersten Verbesserung auf long (vorher hatte ich noch int benutzt, was natürlich einen noch kleineren Definitionsbereich hat).

Nun ja, nun dachte ich mir, dass vielleicht ein unsigned long helfen würde - Fehlanzeige. Auf der 32-Bit Maschine erzeugt einfach alles über 7 Stellen eine falsche Ausgabe.

Natürlich habe ich mir schon gedanken gemacht...hatte vielleicht auf einen Rundungsfehler bei der Funktion pow getippt, da diese ja mit doubles und floats arbeitet.
Aber da verlief sich mein Gedankengang.


Nun ist mir heute morgen beim Träumen in der S-Bahn die Idee gekommen, die Zahl in einem int-Array zu speichern, also jede Ziffer an einer Stelle im Array, möglicherweise auch char, da
es ja quatsch ist ein int für eine einzige Ziffer zu benutzen. Danach könnte man die einzelnen Positionen ja auch vertauschen und so die Zahl invertieren.
Nur leider habe ich keine Ahnung wie man eine Eingabe in ein Array speichert, sodass für jede Ziffer der Zahl eine neue Arrayposition gewählt wird.
Für int habe ich das schon probiert, ging natürlich nicht so einfach. Aber wie sieht es mit char aus? (in C werden ja Strings auch in char-Arrays gespeichert, wenn ich mich nicht irre).
Wenn man Char benutzt, wird das auch aufwändiger die Stellen zu ermitteln. Oder irre ich mich da wiederrum gänzlich? :hmm:

Ein ziemlich langer Beitrag, aber ich würde mich über jedes Kommentar zu meinem Gedankengang und dem Long-Mysterium freuen und begrüße die Community hiermit noch einmal recht
herzlich :)

Gruß
Lexington

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Lexington« (02.08.2012, 12:08)


David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

02.08.2012, 09:37

Welchen Compiler benutzt du?

"Normalerweise" sind int und long gleich groß.
Probier's mal mit long long oder unter Visual C++ mit __int64.

Lexington

Frischling

  • »Lexington« ist der Autor dieses Themas

Beiträge: 17

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

3

02.08.2012, 09:47

Wenn ich nicht Zuhause bin, wie jetzt, Dev-C++ Portable unter 32-Bit.
Zuhause Visual Studio Express C++ unter 64-Bit.

Vielen Dank für die schnelle Antwort, hab auch gleich long long ausprobiert, scheint aber nicht zu funktionieren.
Vielleicht liegt der Fehler auch nicht direkt bei der Zahl oder beim temporären Ergebnis?
Ich werde nachher mal deinen Ratschlag beherzigen und Zuhause __int64 ausprobieren.

Laut Berechnung rechnet er bei der ersten Stelle 9*10^8 = 899999999, was ja offensichtlich falsch ist.
Eine Idee woran das liegen könnte?

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

4

02.08.2012, 09:55

Da hast Du Dich ja schön in die Ecke gebastelt :-) Mir gefällt, dass Du Deine Probleme selbst zu lösen versuchst. Aber die Sache mit den Zahlen in Rechnern ist etwas komplizierter.

32Bit:
Ich geh jetzt mal von einem gängigen Compiler auf Windows oder Linux aus. Da ist sowohl int als auch long 32Bit. Mit Vorzeichen geht der Zahlenbereich von -2 Milliarden bis plus 2 Milliarden - lass Dir da mal sowas hier ausgeben:

Quellcode

1
std::cout << std::numeric_limits<unsigned int>::max() << std::endl;


Vorzeichenlose Zahlen gehen von 0 bis 4 Milliarden und ein bisschen was. Du bekommst also in jedem Fall 8 Stellen raus, und eine neunte Stelle bis zu einem gewissen Bereich.

Die Tatsache, dass Du schon ab 7 Stellen Ärger bekommst, liegt wahrscheinlich eher daran, welche Überladung von pow() der Compiler nimmt. Wenn er die für floats nimmt, hört es bereits bei 7 Stellen auf, denn floats funktionieren nunmal völlig anders.

64Bit:
Beim Visual Studio-C++-Compiler sind long immernoch 32Bit und erst long long ist 64Bit. Beim GCC ist dagegen schon long 64 Bit. Das ist der Grund, warum man long einfach nicht benutzen sollte. Entweder int oder gleich einen der Typedefs aus stdint.h, z.B. uint32_t oder int64_t - da weißt Du immer genau, was Du bekommst. Für Schleifenzähler, Array-Indizes und sowas gibt es dagegen size_t - der ist immer vorzeichenlos und immer genau so groß wie die Zielarchitektur, also 32Bit oder 64Bit. Wenn Du mal schaust - new[] nimmt genauso size_t wie jede Funktion von std::vector. Für sowas ist der auch gedacht, und ich würde ihn auch für sowas empfehlen.

Zum Verrechnen nun: nimm mal einen Debugger und steppe durch. Für Visual Studio einfach mit F9 irgendwo am Anfang einen Breakpoint setzen und dann mit F5 das Programm loslaufen lassen. Der Debugger hält dann automatisch an dieser Stelle und Du kannst Dir den Inhalt jeder Variable anschauen, und mit F10 in Einzelschritten weiterlaufen und schauen, wie es sich entwickelt. Der Debugger ist ein enorm wertvoller Helfer! Lerne so früh wie möglich, mit ihm umzugehen.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

Lexington

Frischling

  • »Lexington« ist der Autor dieses Themas

Beiträge: 17

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

5

02.08.2012, 10:16

Ich hatte mich vor ein paar Monaten über die Definitionsbereiche informiert, daher ist wohle einiges in Vergessenheit geraten. :S

Ich werde nachher mal versuchen mir das auszugeben, was du dort angesprochen hast. Muss ich dafür eine bestimmte Headerdatei einbinden?

Also der Compiler, den ich hier zu Verfügung habe, meckert bei pow() nicht einmal über int-Werte, bei Visual C++ sieht das schon anders aus. Ich glaube da habe ich floats benutzt, was sich ja mit deiner Erläuterung deckt.
Gibt es da eine möglichkeit diese Problem zu lösen? Bin mir leider über das genaue Prinzip von floats und doubles nicht sicher, d.h. wie diese in Bitschreibweise ausgedrückt werden.

Oh vielen Dank, ich wusste nicht, dass man lieber komplett auf long verzichten sollte. Darüber habe ich auch nocht nichts gelesen, aber danke für den Tipp, werde ihn in Zukunft beherzigen. Size_t habe ich auch schonmal aufgeschnappt, klingt nach einem interessanten Prinzip.

Ebenso war mir diese Einsatzmöglichkeit des Debuggers nicht bewusst und ich werde es nachher gleich ausprobieren, klingt hilfreich!

Ich melde mich nochmal, wenn es Neuigkeiten gibt und bis dahin vielen Dank für die schnellen Antworten :)


Lex

6

02.08.2012, 10:53

Ich gehe auch davon aus, dass dir der float Probleme macht. Diese Funktion kommt aber auch komplett ohne pow aus.

Schau dir mal an, in welcher Reihenfolge du zum Beispiel 1234 invertierst:
(zahl/ergebnis): (1234/0) -> (123/4000) -> (12/4300) -> (1/4320) -> (0/4321)

Pro Schleifendurchlauf kommt also immer eine Stelle hinzu. Wieso also die erste Zahl (hier die 4) auf die richtige Stelle setzen, wenn du im nächsten Durchlauf nur eine Stelle mehr brauchst?
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

02.08.2012, 11:34

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
unsigned long invert ( unsigned long number ) {
    unsigned long newNumber = 0;
    while ( number > 0 ) {
        newNumber *= 10;
        newNumber += number % 10;
        number /= 10
    }
    return newNumber;
}


Ohne Pow, ganz ersichtlich, ganz trivial.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Lexington

Frischling

  • »Lexington« ist der Autor dieses Themas

Beiträge: 17

Wohnort: Berlin

Beruf: Student

  • Private Nachricht senden

8

02.08.2012, 12:08

@Steef
@BlueCobold

Super Lösung. Funktioniert genau für 9 Stellen, also mehr als genug.

Da hab ich wohl ein wenig zu kompliziert gedacht.
Aber trotzdem noch ein paar Sachen über die Datentypen gelernt und die Funktionen des Debuggers.
Werde noch das Angesprochene von Schrompf ausprobieren.

In diesem Sinne.

Danke,
Lex

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

9

02.08.2012, 12:21

Hey, Deine Arbeitsweise gefällt mir immer mehr! Speziell der Debugger - dessen Wichtigkeit kann man nicht überbewerten. Bleib dran! Das wird mal was!
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

10

02.08.2012, 12:27

Jo, so macht es Spaß zu helfen! :thumbup:

Werbeanzeige