Lassen Sie C-Gleitkomma-Literale schweben (anstatt zu verdoppeln)

76

Es ist bekannt, dass in C Gleitkomma-Literale (z . B. 1.23) einen Typ haben double. Infolgedessen wird jede Berechnung, die sie betrifft, auf das Doppelte hochgestuft.

Ich arbeite an einem eingebetteten Echtzeitsystem mit einer Gleitkommaeinheit, die nur floatZahlen mit einfacher Genauigkeit ( ) unterstützt. Alle meine Variablen sind float, und diese Genauigkeit ist ausreichend. Ich brauche (und kann es mir überhaupt nicht leisten) double. Aber jedes Mal so etwas

if (x < 2.5) ...

geschrieben ist, passiert eine Katastrophe: Die Verlangsamung kann bis zu zwei Größenordnungen betragen. Die direkte Antwort ist natürlich zu schreiben

if (x < 2.5f) ...

Dies ist jedoch so leicht zu übersehen (und bis zu spät schwer zu erkennen), insbesondere wenn ein ' #definedisziplinierter ' Wert von einem weniger disziplinierten (oder nur neuen) Entwickler in einer separaten Datei gespeichert wird.

Gibt es also eine Möglichkeit, den Compiler zu zwingen, alle (Gleitkomma-) Literale wie mit einem Suffix als float zu behandeln f? Auch wenn es gegen die Spezifikationen ist, ist es mir egal. Oder irgendwelche anderen Lösungen? Der Compiler ist übrigens gcc.

Zeus
quelle
30
Es gibt -Wdouble-promotion, die Ihnen zumindest Warnungen geben werden. Kombiniert mit -Wfloat-conversionsollte eine ziemlich gute Abdeckung ergeben.
Brett Hale
3
Dies beantwortet Ihre Frage nicht direkt, aber es wäre nicht so schwierig, ein Skript zu schreiben, um nur fehlende fs aus FP-Literalen einzufügen .
Xophmeister
1
Hilft dies: stackoverflow.com/questions/24688911/… ?
Rahul Tripathi
4
Einige Compiler für eingebettete Systeme ordnen double to float zu und aktivieren nur die doppelte Genauigkeit mit einer Option. Ich weiß nicht, ob es etwas Ähnliches in GCC gibt
phuclv
3
@BrettHale Dieser Kommentar verdient eine richtige Antwort. Ich denke, dass das Abrufen von Warnungen in diesem Fall produktiver wäre als eine andere Compileroption, mit der Programmierer Code schreiben können, der nicht mit dem Standard kompatibel ist.
user694733

Antworten:

83

-fsingle-precision-constantFlag kann verwendet werden. Dadurch werden Gleitkommakonstanten mit einfacher Genauigkeit geladen, auch wenn dies nicht genau ist.

Hinweis: Hierbei werden auch Konstanten mit einfacher Genauigkeit bei Operationen mit Variablen mit doppelter Genauigkeit verwendet.

ameyCU
quelle
2
Vielen Dank! Ich wusste nichts über diese Flagge. Dies beantwortet meine Frage perfekt - auch wenn es, wie andere vorgeschlagen haben, vielleicht vorsichtiger wäre, Warnungen zu generieren.
Zeus
@Zeus Ich bin froh, dass es geholfen hat !! :)
ameyCU
2
Ich würde diese Option mit Bedacht nutzen! Stellen Sie sich einen neuen Entwickler vor, tippen Sie einfach x < 2.5, alles wird in Ordnung sein. Er wird wahrscheinlich diese spezielle Compiler-Option verpassen, die ihm das Leben rettet :-). Wenn er stattdessen Warnungen erhält (mit -Wdouble-promotion, -Wfloat-conversion) und Sie verwenden -Werror, die alle Warnungen in Fehler umwandeln, checkt er den Code möglicherweise nicht direkt ein und wundert sich möglicherweise und lernt. Aber nur für die Release-Qualität möchten Sie vielleicht auf Nummer sicher gehen und sie mit der spezifischen Option ( -fsingle-precision-constant) kompilieren . Bitte beachten Sie, dass dies nur ein Kommentar ist.
Mathe
52

Verwenden Sie stattdessen Warnungen: -Wdouble-promotionWarnt vor implizitem Float, um die Promotion zu verdoppeln, wie in Ihrem Beispiel. -Wfloat-conversionwarnt vor Fällen, in denen Sie Floats möglicherweise noch Doppelte zuweisen.

Dies ist eine bessere Lösung, als einfach doppelte Werte auf den nächsten Gleitkommawert zu zwingen. Ihr Gleitkomma-Code ist immer noch kompatibel und Sie werden keine bösen Überraschungen erleben, wenn ein Doppelwert einen positiven Wert enthält, beispielsweise kleiner als FLT_DENORM_MIN(unter der Annahme von IEEE-754) oder größer als FLT_MAX.

Brett Hale
quelle
Sie haben im Allgemeinen natürlich Recht. Unter meinen besonderen Umständen -fsingle-precision-constantfunktioniert es jedoch besser. Erstens hat meine Version von GCC (4.4.7) einfach keine dieser Optionen. Zweitens habe ich keine kniffligen Konstanten (außer NaN) und alle Berechnungen müssen floatsowieso sein (das ist der springende Punkt). Schließlich generiert die mitgelieferte Chipbibliothek so viele Warnungen (die meisten davon explizit!), Dass die nützlichen häufig im Stapel vergraben werden ... Und wie gesagt, ich bin in diesem Fall nicht sehr besorgt über die strikte Einhaltung.
Zeus
2
Ich glaube auch, dass es gefährlich ist, ein Problem in Ihrem Quellcode mit einem Befehlsschalter zu verbergen. Denken Sie nur daran, dass Ihr Code in fünf Jahren möglicherweise von einer anderen Person verwendet wird, die eine neue Version des Compilers verwendet und möglicherweise nicht über diesen netten Schalter verfügt. Es ist viel besser, die Probleme im Quellcode zu beheben, als sie auszublenden. Und zu all diesen Warnungen ... Beim Kompilieren für die Produktion sollten Warnungen als Fehler betrachtet werden. -Werror :-)
ChrisB
1

Sie können die definierten Konstanten (float)überall dort umwandeln, wo sie verwendet werden. Der Optimierer sollte seine Aufgabe erfüllen. Dies ist eine tragbare Lösung.

#define LIMIT 2.5

if (x < (float)LIMIT) ...
Yves Daoust
quelle
Oder wirf sie in die Definition, wie in #define foo ((float) 1.234)
CuriousRabbit
2
@CuriousRabbit: Damit wird das Problem "ein weniger disziplinierter (oder nur neuer) Entwickler" nicht behoben.
Yves Daoust
1

Das -Wunsuffixed-float-constantsFlag könnte auch verwendet werden, möglicherweise kombiniert mit einigen der anderen Optionen in der oben akzeptierten Antwort. Dies fängt jedoch wahrscheinlich keine nicht angehängten Konstanten in Systemheadern ab. Müsste auch verwenden -Wsystem-headers, um diese zu fangen. Könnte viele Warnungen erzeugen ...

Delsauce
quelle