2010-01-03 8 views
8

Ich habe eine Bibliothek, die doppelte Zahlen analysieren muss, die immer einen Punkt '.' als Dezimaltrennzeichen. Unglücklicherweise respektiert strtod() in diesem Fall das Gebietsschema, das möglicherweise ein anderes Trennzeichen verwendet, und daher kann das Parsen fehlschlagen. Ich kann locale() nicht festlegen - es ist nicht Thread-sicher. Also suche ich jetzt nach einer sauberen locale-unabhängigen Implementierung von strtod. Ich habe bis jetzt mehrere Implementierungen gefunden, aber alle sehen hacky oder einfach wie schlechter Code aus. Kann mir jemand eine gut getestete, funktionierende, saubere (ANSI) C-Implementierung empfehlen?Locale-unabhängige Implementierung von Strtod

Antwort

3

Ergreifen Sie einige bekannte Implementierung (die nicht von atof abhängt), wie die mit Ruby verteilt: ruby_1_8/missing/strtod.c.

+0

Vielen Dank. Genau das habe ich gesucht. Eine gut getestete und saubere Implementierung. – bert

+0

Ich fürchte, das ist keine korrekte Implementierung, es hat sich nicht um das Runden gekümmert, was eine sehr wichtige Sache bei der String-Doppelwandlung ist. Bitte googeln Sie "Korrekt abgerundete Dezimal zu Fließkomma-Konvertierung" und schauen Sie. – amanjiang

0

Es gibt auch gdtoa auf netlib, BSD-Lizenz: http://www.netlib.org/fp/gdtoa.tgz

+0

gdtoa konvertiert double in string, während das OP nach einer doppelten Konvertierung sucht. – vitaut

+0

@vitaut es hat Implementierungen von beiden Dingen, es ist nicht nur eine Implementierung von 'dtoa()' – Spudd86

2

die Antwort über Folgen, habe ich versucht, die Ruby-Implementierung bei ruby_1_8/missing/strtod.c verwenden. Doch für manche Eingänge gibt diese unterschiedliche Antworten auf gcc eingebauten Parser und strtod aus stdlib.h, sowohl auf Mac und Linux-Plattformen:

char * endptr ; 
double value1 = 1.15507e-173 ; 
double value2 = strtod("1.15507e-173", &endptr) ; 
double value3 = test_strtod("1.15507e-173", &endptr) ; 
assert(sizeof(double) == sizeof(unsigned long)) ; 
printf("value1 = %lg, 0x%lx.\n", value1, *(unsigned long*)(&value1)) ; 
printf("value2 = %lg, 0x%lx.\n", value2, *(unsigned long*)(&value2)) ; 
printf("value3 = %lg, 0x%lx.\n", value2, *(unsigned long*)(&value3)) ; 
assert(value1 == value2) ; 
assert(value1 == value3) ; 

die

value1 = 1.15507e-173, 0x1c06dace8bda0ee0. 
value2 = 1.15507e-173, 0x1c06dace8bda0ee0. 
value3 = 1.15507e-173, 0x1c06dace8bda0edf. 
Assertion failed: (value1 == value3), function main, file main.c, line 16. 

So druckt mein Rat ist, die gewählte Implementierung vor der Verwendung zu testen.

2

Warnung: Die vorgeschlagene Implementierung von Ruby enthält Fehler. Ich würde nicht der kleine Unterschied von gavin wies darauf hin, etwas dagegen, aber wenn Sie versuchen, so etwas wie „0,000000000000000000000000000000000000783475“ zu analysieren, werden Sie 0,0 statt 7.834750e-37 (wie die Aktien strtod() zurückkehrt.)

Andere bekommen Lösung:

#include <sstream> 
#include "strtod_locale_independent.h" 

extern "C" double strtod_locale_independent(const char* s) 
{ 
    std::istringstream text(s); 
    text.imbue(std::locale::classic()); 
    double result; 
    text >> result; 
    return result; 
} 

Ich weiß nicht, wie schnell das ist, obwohl.

+0

Das ist ungefähr 5x langsamer als die eingebaute strtod, und gibt Ihnen nicht den Endzeiger, der benötigt wird, wenn Sie ' Verwenden Sie es zum Parsen. –

+0

Ja, Sie haben Recht. Aber der Punkt ist nicht Leistung. Es ist Gebietsschema-Abhängigkeit. Daher kann 'strtod()' nicht verwendet werden. –

+2

Der Punkt ist, dass dies kein Ersatz für Strtod ist. –