2010-01-03 3 views
8

J'ai une bibliothèque qui doit analyser des nombres doubles qui utilisent toujours un point '.' comme séparateur décimal. Malheureusement pour ce cas, strtod() respecte les paramètres régionaux qui pourraient utiliser un séparateur différent et ainsi l'analyse peut échouer. Je ne peux pas setlocale() - ce n'est pas thread-safe. Donc, je suis à la recherche d'une implémentation strtod propre aux paramètres régionaux, maintenant. J'ai trouvé plusieurs implémentations jusqu'à présent, mais tous ont l'air hacky ou tout simplement comme un mauvais code. Quelqu'un peut-il me recommander une implémentation C bien testée, fonctionnelle et propre (ANSI)?Implémentation de strtod indépendante des paramètres régionaux

Répondre

3

Prenez une implémentation connue (qui ne dépend pas de atof), telle que celle distribuée avec ruby: ruby_1_8/missing/strtod.c.

+0

Merci. C'est exactement ce que j'ai cherché. Une implémentation bien testée et propre. – bert

+0

Je crains que ce ne soit pas une implémentation correcte, ça ne se souciait pas de l'arrondi, ce qui est très important dans la conversion de chaînes de caractères. S'il vous plaît google "Correctement arrondi décimal à la conversion en virgule flottante" et jetez un oeil. – amanjiang

0

Il y a aussi gdtoa disponible sur netlib, BSD licence de type: http://www.netlib.org/fp/gdtoa.tgz

+0

gdtoa convertit le double en chaîne tandis que l'OP recherche une chaîne à double conversion. – vitaut

+0

@vitaut il a des implémentations des deux choses dedans, ce n'est pas juste une implémentation de 'dtoa()' – Spudd86

2

Suite à la réponse ci-dessus, j'ai essayé d'utiliser à la mise en œuvre ruby_1_8/missing/strtod.c Ruby. Cependant, pour certains intrants cela donne des réponses différentes à gcc intégré analyseur et strtod de stdlib.h, à la fois sur Mac et sur les plates-formes Linux:

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) ; 

qui imprime

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. 

Donc, mon conseil est de tester l'implémentation choisie avant utilisation.

2

Avertissement: L'implémentation proposée de ruby ​​contient des bogues. Je ne me dérangerait pas la petite différence a par gavin, mais si vous essayez d'analyser quelque chose comme « 0,000000000000000000000000000000000000783475 » vous obtiendrai au lieu de 0,0 7.834750e-37 (comme le rendement. Strtod() stock)

Autre solution:

#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; 
} 

Je ne sais pas à quelle vitesse c'est, cependant.

+0

Ceci est environ 5x plus lent que le strtod intégré, et ne vous donne pas le pointeur de fin, qui est nécessaire quand vous ' re l'utiliser pour l'analyse. –

+0

Oui, vous avez raison. Mais le point n'est pas la performance. C'est une dépendance locale. Par conséquent, 'strtod()' ne peut pas être utilisé. –

+2

Le fait est que ce n'est pas un remplacement pour strtod. –

Questions connexes