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

1

26.07.2015, 10:35

[C++] Float auf x Nachkommastellen begrenzen

Ich will meine Lebenspunkte, Schaden, Rüstung etc. auf 1 Nachkommastelle begrenzen. Ich hab das auch schon mal gegoogelt und dabei die FLOOR Funktion gefunden. Die Macht das auch richtig gut, aber dabei passiert manchmal ein Fehler.

C-/C++-Quelltext

1
2
3
float foo1 = 80.833333f

float foo2 = floor( foo1 * 10.f + 0.5f ) / 10.f;


Das Problem dabei ist, das das " / 10.f " am Schluss dann manchmal wieder weitere Nachkommastellen produziert. So hat mein Programm nach einer Weile ein 80.800003f in "foo2" gespeichert. Da das der Schaden ist der dann bei den Lebenspunkten abgezogen wird, wird mir im Spiel dann bei den Lebenspunkten auch eine sehr lange Nachkommastelle angezeigt.

Das Problem ist sogar reproduzierbar, es tritt solange ich alles gleich mache zum selben Zeitpunkt im Programm auf. Z.B. 9 mal lang geht es gut und beim 10 mal liefert es den Fehler. Benütze ich dabei 1x eine Fertigkeit die mehr Schaden austeilt ändert es sich z.B. zu 8 mal und dann beim 9 mal kommt der Fehler. Danach läuft es aber wieder normal weiter.

Kann man das irgendwie verhindern? Oder gibt es da eine bessere Möglichkeit die Werte auf eine Nachkommastelle zu begrenzen?

Arbeite mit Visual Studio 2010.

2

26.07.2015, 11:45

Ich würde jetzt einfach mal vermuten, das es sich dabei nicht um einen Fehler von FLOOR handelt, sondern um die nicht genau Darstellung von float.

Alternativ zu double wechseln oder komplet auf ganz Zahl runden.

Edit: Es ist definitiv dem Zahlentype float geschuldet, leider wird das umstellen auf double auch keine Verbesserung bringen.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Koschi« (26.07.2015, 11:59)


TrommlBomml

Community-Fossil

Beiträge: 2 117

Wohnort: Berlin

Beruf: Software-Entwickler

  • Private Nachricht senden

3

26.07.2015, 12:04

Lass mal das 0.5f weg, dann sollte es gehen denke ich.

Nox

Supermoderator

Beiträge: 5 272

Beruf: Student

  • Private Nachricht senden

4

26.07.2015, 12:05

Das ist wie Koschi bereits anmerkte, ein intrinsisches Problem von floats. Idealerweise vermeidet man floats wann immer es geht. Wenn du z.B. nur eine Nachkommastelle haben willst, nutz doch einfach Ganzzahlen (Integer) indem du alle "internen" Werte mit 10 multiplizierst. Für die Darstellung teilst du einfach durch 10.
PRO Lernkurs "Wie benutze ich eine Doku richtig"!
CONTRA lasst mal die anderen machen!
networklibbenc - Netzwerklibs im Vergleich | syncsys - Netzwerk lib (MMO-ready) | Schleichfahrt Remake | Firegalaxy | Sammelsurium rund um FPGA&Co.

5

26.07.2015, 12:21

Da ich keine Ahnung habe, wie du das nun in deinem Spiel anzeigst, hier mal eine eher generische Sache:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
#include <sstream> //std::stringstream
#include <iomanip> //std::setprecision

std::stringstream ss;
ss << std::setprecision(2) << foo2
std::string foo2AsAString = ss.str();

//Do stuff with it


Wäre foo2=8.33333f würde es als 8.3 angezeigt. ;)

MfG
Check

Tobiking

1x Rätselkönig

  • Private Nachricht senden

6

26.07.2015, 12:27

Für die Darstellung von float ist es sinnvoll nach maximal 7 Stellen (Vor- und Nachkomma gezählt) zu runden. Die Fehler bei der Rechnung sind in den meisten Fällen vernachlässigbar.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

26.07.2015, 13:21

Da das der Schaden ist der dann bei den Lebenspunkten abgezogen wird, wird mir im Spiel dann bei den Lebenspunkten auch eine sehr lange Nachkommastelle angezeigt.
Deshalb rundet man die Anzeige auch auf so viele Stellen, wie man's braucht und nicht die Zahlen selbst.
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]

8

26.07.2015, 13:41

Ja das Problem ist nicht das Floor ansich, das liefert mir 808.f zurück, erst nachdem es wieder / 10.f genommen wird, ist es das 80.800003f.

Hm um auf int zu wechseln müsste ich ziemlich viel Umbauen. Schon das ganze Grundgerüst, wo ich die Daten überhaupt Lade läuft über float, damit ich das einfach ändern kann. Ich hab da einen Grundwert und einen Faktor mit dem der Grundwert multipliziert wird und daraus ergeben sich dann die Werte beim laden. So kann ich den Grundwert einfach ändern und das Spiel passt alle Werte an, wenn ich kleinere Zahlen will.

z.B.
100 * 0.05 = 5
10 * 0.05 = 0.5

Für höhere Level dann noch:

lvl 1 -> 5
lvl 2 -> 5 * 1.2 = 6
lvl 3 -> 6 * 1.2 = 7.2
lvl 4 -> 7.2 * 1.2 = 8.64
usw.


Ich dachte jetzt halt ich kann das mit Floor einfach begrenzen und dann im Spiel so anzeigen. Also hab ich dann zwei Möglichkeiten, entweder ich erhöhe meinen Grundwert um das 10 fache und caste dann nach int für die Darstellung oder ich benütze das std::setprecision von Checkmateing.

Warum ich die Nachkomma stelle eigentlich wollte liegt daran, das ich "1000.0" besser finde als "10000" für die Lebenspunkte der Einheiten. Das erste sieht da finde ich übersichtlicher aus. Vorallem wenn man dann im Kopf etwas überschlagen soll ob man die Einheit jetzt schon heilt oder noch eine Runde wartet um dann einen größeren Heilzauber anwenden zu können. Ich finde dabei ja schon die 1000.0 für Level 1 eigentlich zu hoch. Benütze ich keinen kleineren Wert als 5 kann ich es auf 100.0 oder 1000 reduzieren. Aber soweit bin ich noch nicht um das sagen zu können.

So stört mich der Fehler eigentlich auch garnicht, er stört halt nur wenn er dann auf den Bildschirm erscheint. ;)


Oh zu lange zum schreiben gebraucht.

@BlueCobold

Hab bis jetzt kaum floats benützt und wusste deswegen jetzt garnicht das die Berechnungsfehler haben können. Was zu dem Irrglauben führte, es geht auch anders und weswegen mich der Fehler auch so überrascht hat.

9

26.07.2015, 13:50

Ja das Problem ist nicht das Floor ansich, das liefert mir 808.f zurück, erst nachdem es wieder / 10.f genommen wird, ist es das 80.800003f.

Das Problem ist der float. Allerdings hast du das selbe Problem mit double. Da diese Datentypen mit der Basis 2 arbeiten, lassen sich bestimmte Zahlen nicht genau darstellen. So ist zum Beispiel 1/10 periodisch (und das ist genau das Problem, über das du stolperst).
"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

10

26.07.2015, 14:10

Wenn ich das von dir jetzt so lese, habe ich das Problem glaube ich noch nicht ganz verstanden. Du schreibst ja bei bestimmten Zahlen hat es Probleme.

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. Solange die beiden Werte identisch sind dürfte er doch nie das Problem erzeugen. Oder ist das 808.f und 10.f nicht immer gleichwertig und es ändert sich bei dem was?

Werbeanzeige