Wie Bereichsüberschreitungen bei long/double usw. feststellen
-
Guten Tag zusammen,
ich habe hier einen Standard, der folgendes vorgibt:
- Die größtmögliche Zahl passt in einen std::int64_t (hat also 8 Bytes)
- Es kann noch ein Faktor dazukommen, der sich aus std::pow(10.0, n); ergibt
Das ist schon wahnsinnig genius, denn irgendwann komme ich nicht mehr umhin, den wahren finalen Wert zu berechnen, um ihn dem Nutzer zu zeigen http://proximonivel.pt/wp-content/uploads/2013/01/senador-america-genius-pn-n.jpg
Wie kann ich denn jetzt feststellen, ob ich den Bereich der Variablen überschreite, wenn ich folgendes berechne:
std::int64_t valInt = /* Initiale Zuweisung */; double valDouble; if (n < 0) { valReal = static_cast<double>valInt * std::pow(10.0, n); valDouble = true; } else { valInt = (valInt * static_cast<std::int64_t>(std::pow(10.0, n))); }
Ich würde dann gerne eine Meldung ausgeben, das der Wert auf dem aktuellen System nicht interpretiert werden kann.
-
Brauchst du nicht.
Für die Ausgabe reicht es aus, an die Ziffern ein paar Nullen dran zu hängen bzw. das Komma einzufügen.
-
DerStandard schrieb:
ich habe hier einen Standard, der folgendes vorgibt:
- Die größtmögliche Zahl passt in einen std::int64_t (hat also 8 Bytes)
- Es kann noch ein Faktor dazukommen, der sich aus std::pow(10.0, n); ergibt
Das ist schon wahnsinnig genius, denn irgendwann komme ich nicht mehr umhin, den wahren finalen Wert zu berechnen, um ihn dem Nutzer zu zeigen
Etwas dubios. Der Nutzer will doch keinen double sehen, sondern ein paar Zeichen auf dem Bildschirm.
Weiter sehe ich keinen speziellen Grund, eine Bereichsüberschreitung bei der Konvertierung zu prüfen. Wenn du damit weiterrechnen willst, kann es auch beim zweiten oder jedem weiteren Schritt zu einer Überschreitung kommen:
double((1, 1e300)) * 1e300 = "1e600". Die erste Zahl ist repräsentierbar, beim Weiterrechnen sprengst du den Wertebereich.
Du müsstest also ehrlicherweise grundsätzlich jede Rechenoperation auf Überlauf prüfen.
-
Auf einigen Systemen gibt es eingebaute Integraltypen mit 128 Bit (GCC/Clang unterstützen bspw.
__int128_tbzw.__int128)Für die Zehnerpotenzen könntest du ganz nebenbei eine Lookup-Table verwenden.
Wie kann ich denn jetzt feststellen, ob ich den Bereich der Variablen überschreite, wenn ich folgendes berechne:
Wieso nicht
if (valInt > std::numeric_limits<std::int64_t>::max()/zehnerPotenz) // ...?
Übrigens erzeugen Overflows mit vorzeichenbehafteten Ganzzahltypen (wie
std::int64_t) undefiniertes Verhalten, du solltest dich also nicht auf irgendwelche Tricks die letzteres ausnutzen verlassen.
-
DirkB schrieb:
Brauchst du nicht.
Für die Ausgabe reicht es aus, an die Ziffern ein paar Nullen dran zu hängen bzw. das Komma einzufügen.
Hm theoretisch schon. Praktisch wäre das dann aber eine textuelle Darstellung. D.h. in der Datenbank würde ich Text speichern. Was solange funktioniert, wie der Nutzer keine Historie von Werten als Graph sehen möchte, denn dann bräuchte ich wieder ints/doubles.
Würde ich die Rohwerte sowie den Faktor in der Datenbank speichern, dann müsste man das Problem in php lösen, wenn der Benutzer z.B. eine Werte-Historie sehen möchte.
Ist Bashar's Ansatz ("Du müsstest also ehrlicherweise grundsätzlich jede Rechenoperation auf Überlauf prüfen.") der einzig legitime?
-
Arcoth schrieb:
Auf einigen Systemen gibt es eingebaute Integraltypen mit 128 Bit [...]
. o O ( Hat außer mir auch noch wer ne VAX rumstehen? Hände hoch! )
Arcoth schrieb:
[...] Integraltypen [...]
Integer reicht.
-
Was haltet ihr von der Lösung in der ersten Antwort (mit den 85 "likes"):
http://stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-c-c
-
Hat außer mir auch noch wer ne VAX rumstehen?
Eingebaut ist ein Typ mMn. dann wenn er ohne Einbindung jeglicher Header verwendet werden kann. Genau das ist bei
__int128der Fall. Falls sich dein Verständnis von "eingebaut" von meinem unterscheidet, lass es mich wissen
-
DerStandard schrieb:
Was haltet ihr von der Lösung in der ersten Antwort (mit den 85 "likes"):
http://stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-c-csieht nicht fein aus.
DerStandard schrieb:
ich habe hier einen Standard, der folgendes vorgibt:
Die größtmögliche Zahl passt in einen std::int64_t (hat also 8 Bytes)
Es kann noch ein Faktor dazukommen, der sich aus std::pow(10.0, n); ergibtDu sollst nicht zufällig sowas wie die Fakultär von 1000 ausrechnen/anzeigen? Dann vermeide einfach die Bereichsüberschreitungen im Voraus.
-
Also das riecht für mich sehr nach "decimal".
Ich verstehe aber den ganzen Wirbel nicht.
Wie DirkB schon in der ersten Antwort geschrieben hat braucht man für die Konvertierung in einen dezimalen (!) String keinen grösseren Typen.
-
hustbaer: Eine Umwandlung in einen arithmetischen Basistyp anzubieten ist nicht völlig abwegig, auch wenn es gerade für die Textanzeige mal nicht nötig ist.
-
Oh, sorry, ich hatte übersehen dass der OP selbst an der Diskussion beteiligt ist, und jetzt auch an anderen Dingen interessiert. Manchmal ist man schon was blind...

@DerStandard
Die meisten Datenbanken bieten auch einen "decimal" Typ an. Damit man ordentlich mit Geldbeträgen arbeiten kann.
Wenn deine DB so einen Typ hat würde ich den nehmen.
Wenn nicht, dann halt als Text.In PHP damit zu rechnen sollte so oder so kein Problem sein: http://de2.php.net/manual/en/ref.bc.php