Algo de conversion d'un double vers un char*

Le
Gégé
Hello,

Pour des raisons de performance, je suis en train de coder une
alternative à sprintf.
Les résultats sont plutôt bons (x6) par contre je rencontre des
problèmes numériques sur certaines valeurs.

Par exemple :

d = 0.00000000001;
double_to_ascii( d, s ); // >> 0.00000000000999

Je suis preneur de toute suggestion on autre piste algorithmique.
Merci !

G



Voici le code


#include <stdio.h>
#include <ctime>
#include <string>
#include <sstream>
#include <iostream>

class timer
{
private:
clock_t t0;
std::string s;

public:
timer( std::string msg )
{
s = msg;
t0 = clock();
}
~timer()
{
double x = ( clock() - t0 ) / ( double ) CLOCKS_PER_SEC;
std::stringstream ss;
ss << x;
std::cout << s << " : " << ss.str() << std::endl;
}
};


void double_to_ascii( double d, char* s )
{
int p = 15;

// negative case
if ( d < 0 )
{
*s++ = '-';
d = -d;
}

// exponential format is dealt with sprintf
const double thres_max = (double)(0x7FFFFFFF);
if( d > thres_max )
{
sprintf( s, "%.15G", d );
return;
}

// int / dec parts
int int_d = ( int )d;
double dec_d = d - int_d;

// int part
char* s_begin = s;
do
{
*s++ = ( char )( 48 + ( int_d % 10) );
--p;
}
while( int_d /= 10 );

// reverse
char* s_end = s - 1;
while( s_end > s_begin )
{
char c = *s_end;
*s_end-- = *s_begin;
*s_begin++ = c;
}

// ignore null decimal part
if( dec_d != 0 )
{
// dec separator
*s++ = '.';

// dec part
for( int i = 0;
i < p;
i++ )
{
double x = dec_d * 10;
int_d = (int) x;
*s++ = ( char )( 48 + int_d );
dec_d = x - int_d;
}
}
*s = '';

}


int main()
{

// VALUES

double d;
char s[24];

d = 0.00000000001;
double_to_ascii( d, s ); /// 0.00000000000999


// PERFS

const int n = 10000000;

{
timer T("double_to_ascii");
for( int i = 0; i < n; i++ )
{
double_to_ascii( d, s );
}
}

{
timer T("sprintf");
for( int i = 0; i < n; i++ )
{
sprintf( s, "%.15G", d );
}
}

system( "pause" );
return 0;
}
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Marc
Le #24003061
Gégé wrote:

Pour des raisons de performance, je suis en train de coder une
alternative à sprintf.
Les résultats sont plutôt bons (x6) par contre je rencontre des
problèmes numériques sur certaines valeurs.

Par exemple :

d = 0.00000000001;
double_to_ascii( d, s ); // >> 0.00000000000999



Euh, quel est le problème ?
Gégé
Le #24003741
J'aimerais avoir "0.00000000001"
comme ce que sprintf retournerait
Gégé
Le #24003561
On 25 nov, 20:37, Marc
Gégé  wrote:
> Pour des raisons de performance, je suis en train de coder une
> alternative à sprintf.
> Les résultats sont plutôt bons (x6) par contre je rencontre des
> problèmes numériques sur certaines valeurs.

> Par exemple :

>     d = 0.00000000001;
>     double_to_ascii( d, s );  // >> 0.00000000000999

Euh, quel est le problème ?




Un autre exemple plus visuel

d = 0.73;
double_to_ascii( d, s ); /// 0.72999999999999 au lieu de 0.73
Fabien LE LEZ
Le #24003991
On Fri, 25 Nov 2011 11:02:42 -0800 (PST), Gégé
Par exemple :

d = 0.00000000001;
double_to_ascii( d, s ); // >> 0.00000000000999



Ça vient probablement du fait que tu ne peux pas stocker la valeur
0.00000000001 dans un double.
Frederic Lachasse
Le #24004011
Bienvenue dans le monde du calcul en virgule flottante! Et l'un de ses plus gros problème: comme les nombres sont représenté en base 2 et non en base 10, la majorité des nombres à virgule n'a pas de représentation exacte et donc en fait représenté par une approximation. Pour converti r "correctement" (entre guillemet) de la base 2 en base 10, il faut arrondi r...

Je conseille de faire une recherche sur Google avec les mots clefs: "arrond i virgule flottante binaire" et de prévoir une bonne dose d'aspirine.

La citation suivante résume le sujet:
It makes me nervous to fly an airplane since I know they are designed usi ng
floating-point arithmetic.
Anton Householder
Gégé
Le #24004821
On 26 nov, 03:43, Frederic Lachasse wrote:
Bienvenue dans le monde du calcul en virgule flottante! Et l'un de ses pl us gros problème: comme les nombres sont représenté en base 2 et non en base 10, la majorité des nombres à virgule n'a pas de représentati on exacte et donc en fait représenté par une approximation. Pour conver tir "correctement" (entre guillemet) de la base 2 en base 10, il faut arron dir...

Je conseille de faire une recherche sur Google avec les mots clefs: "arro ndi virgule flottante binaire" et de prévoir une bonne dose d'aspirine.

La citation suivante résume le sujet:







> It makes me nervous to fly an airplane since I know they are designed u sing
> floating-point arithmetic.
> Anton Householder



Effectivement je sens que je m'embarque dans une sacrée aventure!
Cette page est assez intéressante, je vais partir de ça :
http://code.google.com/p/stringencoders/wiki/NumToA
Lucas Levrel
Le #24010241
Le 25 novembre 2011, Gégé a écrit :

Pour des raisons de performance, je suis en train de coder une
alternative à sprintf.
Les résultats sont plutôt bons (x6) par contre je rencontre des
problèmes numériques sur certaines valeurs.

Par exemple :

d = 0.00000000001;
double_to_ascii( d, s ); // >> 0.00000000000999

Je suis preneur de toute suggestion on autre piste algorithmique.



Tu devrais calculer une décimale de plus que n'exige la précision, et
arrondir en fonction.

--
LL
Publicité
Poster une réponse
Anonyme