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 rsultats sont plutt bons (x6) par contre je rencontre des
problmes numriques 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;
}
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