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

11

26.07.2015, 14:28

Mein Wert ist aber jetzt jedes mal 808.f / 10.f gewesen. Das hat 9 mal geklappt und beim 10 mal liefert es einen falschen Wert.

Das ist nicht möglich. 808 / 10 liefert immer diesen krummen Wert.

Nur einmal als Verdeutlichung:
Bestimmte Zahlen lassen sich im Dezimalsystem nicht genau darstellen, z. B. §\frac{1}{3} = 0.\overline{3}§.
Das selbe gilt für das Binärsystem: §\frac{1}{10} = (0.1)_{10} = (0.0\overline{0011})_2§. Damit lässt sich diese Zahl nicht genau darstellen.
Auch für deinen Wert ist nur eine periodische Darstellung möglich §(80.8)_{10}=(101000.\overline{1100})_2§.

Bei einem float wird die Periode ab einem bestimmten Punkt abgeschnitten (24 Bit für die gesamte Nummer). Dadurch kommt es zu dieser Ungenauigkeit.
"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

12

26.07.2015, 15:24

Stimmt kann eigentlich nicht anders sein, danke für die schöne Erklärung. Mir gaukelt nur das Spiel was anderes vor.

Für die Darstellung mache ich das da:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
float hp_data = 919.20001f

std::string foo;
std::ostringstream ss;

ss << hp_data;

foo = ss.str();


Das ss verschluckt den minimalen Fehler ( k.A. was da intern passiert ) und schreibt dann in den foo string "919.2" rein. Irgendwann wird er Fehler dann wohl groß genug und er erscheint auch auf den Bildschirm. Was mich annehmen lies, er macht das doch x mal richtig, warum jetzt aufeinmal nicht mehr. Beim durchsteppen hatte ich leider nur das angeschaut wo der Fehler auftritt und nicht die vorigen male. Deswegen erschien er auch immer an der selben Stelle, sobald die Abweichung dann mal zu groß war, wird er durch den ostringstream erst übernommen.

13

26.07.2015, 15:44

Wenn du mit exakt 2 Nachkommastellen rechnen willst, dann multipliziere die Werte allesamt mit 100 und speichere sie als Ganzzahlen (int). So wird 23,57 zum Beispiel zu 2357. Darstellen kannst du es dann natürlich als 23,57, aber intern rechnest du mit 2357. So geht dir nie Genauigkeit verloren. So macht es WoW zum Beispiel auch bei der Goldmenge: Man hat eigentlich nicht 123 G 77 S 31 K, sondern 1237731 Kupfer, was dann allerdings als Gold, Silber und Kupfer dargestellt wird. Die maximale Goldmenge war dadurch auf rund 214748 Gold beschränkt, inzwischen hat Blizzard das aber wohl auf 64 Bit int umgestellt.

Bei float oder double könnte es hingegen sein, dass du ein Kupfer hinzubekommst, es aber durch Rundungsfehler nicht hinzugefügt wird. Oder du bekommst 52 Silber, hast aber 51 S 99 K oder 52 S 01 K oder so hinzubekommen.
Cube Universe
Entdecke fremde Welten auf deiner epischen Reise durchs Universum.

14

26.07.2015, 15:48

Nun bei dem Code wird intern einfach std::defaultfloat benutzt.
Das heißt ja offensichtlicher Weise, dass die Instanz des jeweiligem Streams einfach die Standardwerte nimmt. Soweit ich weiß ist die Präzision damit auf 3 gesetzt. Aus 919.0004543 wird also 919 und aus 919.20001 eben 919.2.

MfG
Check

15

26.07.2015, 16:30

@Magogan

Ich zögere da immer noch, weil ich mir nicht sicher bin wie ich das dann für die Anzeige trenne. Gehe ich da richtig in der Annahme das man es in einen string speichert und dann diesen aufsplittert? Oder sollte man das schon vorher machen, hab mich damit nie wirklich befasst muss ich sagen. Über einen string würde ich es schaffen, sie zu trennen. Ob man den int jetzt schon dann für die Anzeige auftrennen kann, weiß ich jetzt garnicht ob das möglich ist und wenn ja wie es gehen könnte.

Ich wüsste grad nicht mal, wie ich der setprecision() den richtigen Wert übergebe. Ich hatte es mir schon gedacht, den Wert den ich Übergebe zählt auch die Werte vor dem Komma mit und die können ja unterschiedlich sein. Für 1000.0 müsste ich also 5 übergeben, der Wert kann aber später auch 6.0 sein womit es nur 2 wären. Zum testen habe ich jetzt einfach 4 eingegeben und das funktioniert für meine Tests soweit. Ich müsste aber eigentlich ermitteln wieviele Stellen vor den Komma stehen und davon hab ich momentan gerade, absolut keine Ahnung, wie man das macht.

Denke mal ich muss mir das mal genauer anschauen, was man mit int und float da alles anstellen kann. Das hatte mich als ich Angefangen hab mit Programmieren nicht so interessiert und habs eher übersprungen.


Edit:

So für beides eine Lösung gefunden. Falls das hier mal jemand liest und sich dann auch fragt wie man das herausfindet. Hoffe nur ich schreibe jetzt keinen Unsinn, das im Code Tag hab ich aber wenigstens getestet. :D

Für die Anzahl der Bits in einem Int oder die Anzal der Bits vor dem Komma. Einfach solange /10 bis der Wert bei int 0 oder bei float kleiner als 1 ist und das mitzählen.

Um einen Int aufzusplitten kann man sich die einzelnen Werte auch mit Modulo rausholen.

C-/C++-Quelltext

1
2
3
4
5
int a = 213;

int b = a % 10;           // ergibt 3
int c = a / 10 % 10;    // ergibt 1
int d = a / 100 % 10;  // ergibt 2

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Shorkan« (26.07.2015, 17:26)


16

26.07.2015, 18:37

Also... Dein Problem hat nicht mit den Nachkommastellen zu tun, sondern eher damit, dass automatisch irgendwann das ganze in das 'wissenschaftliche Format' umgewandelt wird, sprich Gleitkommadarstellung.
Diese kannst du auch deaktivieren mithilfe von std::fixed.
Schaus dir einfach mal online an. :)

MfG
Check

17

26.07.2015, 20:32

Das ist deutlich schöner als das was ich mir jetzt gebastelt hab. Hab jetzt im Code eine Schleife die Zählt wieviele Zahlen vor den Komma kommen und übergebe dann diesen Wert + 1 damit er mir das richtig anzeigt. Hab es auch extra mal mit +2 und +3 probiert und mein Programm hat mir dann 2 oder 3 Nachkomma stellen erstellt.

Ich leite mir das deswegen Laienhaft so ab, wenn ich bei 1364.952 std::precision(2) schreibe nimmt er die 13 vorne. Da ich aber ja trotzdem wissen muss, wie weit es bis 0 ist, schreibt er das dann im Wissenschaftlichen Format. Mache ich aber ein std::precision(5) daraus nimmt er 1364.9. Std::fixed scheint dann dafür zu sorgen das die 4 Zahlen vorne zu einer werden und jede weitere Zahl dann eine Komma Stelle bedeutet für die precision Funktion.

Werd jetzt aber gleich mal meine Schleife löschen und das std::fixed einfügen. ^^ Danke für den Tipp.


Hier noch das was ich mir gebastelt hatte:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
float hp_data = 919.2341f

std::string foo;
std::ostringstream ss;

int num = 1;
float temp_data = hp_data;

if ( temp_data >= 1 )
{
     while ( temp_data >= 1 )
     {
          temp_data /= 10.f;
          num += 1;
     }
}
else
{
     num += 1;
}

ss << std::set_precision(num) << hp_data;

foo = ss.str();

18

26.07.2015, 20:41

Das wird so nicht kompiliert haben. ;)

MfG
Check

19

26.07.2015, 20:49

Warum eigentlich was eigenes?

C-/C++-Quelltext

1
std::cout << std::fixed << std::setprecision(2) << 123.4567f;
"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

20

26.07.2015, 20:50

Hast du seinen Beitrag eigentlich gelesen?

MfG
Check

Werbeanzeige