Richtiges Design von C-Code, der Gleitkommazahlen mit einfacher und doppelter Genauigkeit verarbeitet?

8

Ich entwickle eine Bibliothek von speziellen mathematischen Funktionen in C. Ich muss der Bibliothek die Möglichkeit geben, sowohl mit einfacher als auch mit doppelter Genauigkeit zu arbeiten. Wichtig ist hier, dass die "single" -Funktionen NUR "single" -Arithmetik intern verwenden (bzw. für die "double" -Funktionen).

Sehen Sie sich zum Beispiel LAPACK (Fortran) an, das zwei Versionen jeder seiner Funktionen (SINGLE und DOPPELT). Auch die C Math Bibliothek (Beispiel, expf und exp ).

Um zu verdeutlichen, möchte ich etwas ähnliches wie das folgende (erfundene) Beispiel unterstützen:

%Vor%

Ich habe über die folgenden Ansätze nachgedacht:

  1. Verwenden von Makros für den Funktionsnamen. Dies erfordert immer noch zwei separate Quellcodebasen:

    %Vor%
  2. Verwenden von Makros für die Gleitkommatypen. Dadurch kann ich die Codebasis über die zwei verschiedenen Versionen hinweg teilen:

    %Vor%
  3. Entwickeln Sie einfach zwei separate Bibliotheken und vergessen Sie dabei, Kopfschmerzen zu vermeiden.

Hat jemand eine Empfehlung oder zusätzliche Vorschläge?

    
David H 27.10.2011, 19:14
quelle

4 Antworten

7

Für polynome Approximationen, Interpolationen und andere inhärent approximative mathematische Funktionen können Sie keinen Code zwischen einer Implementierung mit doppelter Genauigkeit und einfacher Genauigkeit austauschen, ohne Zeit in der Version mit einfacher Genauigkeit zu verschwenden oder näher als erforderlich im Double -präzise.

Wenn Sie jedoch die Route der einzelnen Codebasis verwenden, sollte das Folgende für Konstanten und Standardbibliotheksfunktionen funktionieren:

%Vor%     
Pascal Cuoq 27.10.2011, 19:24
quelle
5

(Teilweise inspiriert von Pascal Cuoqs Antwort) Wenn Sie eine Bibliothek mit float- und double-Versionen von allem wünschen, können Sie rekursive #include s in Kombination mit Makros verwenden. Es ergibt nicht den klarsten Code, aber Sie können den gleichen Code für beide Versionen verwenden, und die Verschleierung ist dünn genug, sie ist wahrscheinlich überschaubar:

mylib.h:

%Vor%

mylib.c:

%Vor%

Jede Datei #include s selbst erstellt eine zusätzliche Zeit, die beim zweiten Durchlauf verschiedene Makrodefinitionen verwendet, um zwei Versionen des Codes zu generieren, der die Makros verwendet.

Einige Leute könnten jedoch gegen diesen Ansatz Einwände erheben.

    
Dmitri 27.10.2011 22:13
quelle
2

Die große Frage für Sie wird sein:

  • Ist es einfacher, zwei getrennte, unverschmutzte Quellbäume oder einen verschleierten Quellbaum zu pflegen?

Wenn Sie die vorgeschlagene allgemeine Codierung haben, müssen Sie den Code stelzen schreiben, wobei Sie sehr darauf achten, keine undekorierten Konstanten oder Nicht-Makrofunktionsaufrufe (oder Funktionskörper) zu schreiben.

Wenn Sie separate Quellcode-Bäume haben, wird der Code einfacher zu pflegen sein, da jeder Baum wie normaler (nicht verschleierter) C-Code aussieht, aber wenn es einen Fehler in YourFunctionA in der "float" -Version gibt, wird Du erinnerst dich immer daran, die passende Änderung in der "doppelten" Version vorzunehmen.

Ich denke, das hängt von der Komplexität und Flüchtigkeit der Funktionen ab. Mein Verdacht ist, dass, sobald es das erste Mal geschrieben und debuggt wird, es selten nötig sein wird, darauf zurückzukommen. Das bedeutet tatsächlich, dass es egal ist, welchen Mechanismus Sie verwenden - beide werden praktikabel sein. Wenn die Funktionskörper etwas flüchtig sind oder die Liste der Funktionen flüchtig ist, kann die einzelne Codebasis insgesamt einfacher sein. Wenn alles sehr stabil ist, kann dies durch die Klarheit der zwei getrennten Codebasen bevorzugt werden. Aber es ist sehr subjektiv.

Ich würde wahrscheinlich mit einer einzigen Codebasis und Makros von Wand zu Wand gehen. Aber ich bin mir nicht sicher, ob das Beste ist, und der andere Weg hat auch seine Vorteile.

    
Jonathan Leffler 27.10.2011 19:38
quelle
1

Der & lt; tgmath.h & gt; Kopfzeile, standardisiert in C 1999, stellt typengenerische Aufrufe für die Routinen in & lt; math.h & gt; und & lt; komplex.h & gt ;. Nachdem Sie & lt; tgmath.h & gt; hinzugefügt haben, wird der Quelltext "sin (x)" sinl aufrufen, wenn x lang doppelt ist, sin wenn x doppelt ist und sinf, wenn x float ist.

Sie müssen weiterhin Ihre Konstanten konditionieren, so dass Sie "3.1" oder "3.1f" entsprechend verwenden. Dafür gibt es eine Vielzahl von syntaktischen Techniken, je nach Ihren Bedürfnissen und was Ihnen ästhetischer erscheint. Für Konstanten, die genau in Float-Genauigkeit dargestellt werden, können Sie einfach das Float-Formular verwenden. Z. B. wird "y = .5f * x" automatisch .5f in .5 konvertieren, wenn x doppelt ist. "Sin (.5f)" erzeugt jedoch sinf (.5f), was weniger genau ist als sin (.5).

Sie können die Konditionalisierung möglicherweise auf eine einzige klare Definition reduzieren:

%Vor%

Dann können Sie Konstanten wie folgt verwenden:

%Vor%

Dies ist möglicherweise nicht vollständig zufriedenstellend, da es in seltenen Fällen Fälle gibt, in denen eine Zahl, die in Doppel und dann in Gleitkomma umgewandelt wird, weniger genau ist als eine Zahl, die direkt in Gleitkomma umgewandelt wird. Sie können also besser mit einem oben beschriebenen Makro arbeiten, wo "C (Ziffer)" bei Bedarf ein Suffix an die Zahl anfügt.

    
Eric Postpischil 29.10.2011 14:25
quelle

Tags und Links