2008-11-04 3 views

Répondre

5

Analyser le nombre sous la forme a + N/(10^k), où a et N sont des entiers, et k est le nombre de décimales que vous avez.

Exemple: 12,0345 -> 12 + 345/10^4, a = 12, N = 345, k = 4

Or, 10^k = (2 * 5)^k = 2^k * 5^k

Vous pouvez représenter votre nombre comme une fraction binaire exacte si et seulement si vous vous débarrassez du terme 5^k dans le dénominateur.

Le résultat vérifie (N mod 5^k) == 0

+0

qu'en est-il 11111111111111111111111111111111111111111111111111111111111111111? – BCS

+0

Ou une meilleure façon de le mettre (100/epsilon + 1) – BCS

-2

Convertir la chaîne en un flotteur avec une portée plus grande qu'un double. Jetez cela en double et voyez s'ils correspondent.

+0

Je serais heureux de savoir pourquoi ceci a été rejeté. Si ma réponse est fausse, dites-moi pourquoi. – Treb

+0

long double == double sur certains systèmes – BCS

+0

Très bien, mais il n'y a peut-être pas de flotteur. – DJClayworth

0

Cela devrait faire l'affaire:

bool isRepresentable(const char *realNumber) 
{ 
    double value = strtod(realNumber, NULL); 

    char test[20]; 
    sprintf(test, "%f", value); 

    return strcmp(realNumber, test) == 0; 
} 

probablement préférable d'utiliser la version « sûre » de sprintf pour éviter un dépassement de tampon potentiel

+0

Cela ne fonctionne pas si le nombre a une précision différente de 6 (la précision par défaut du format% lf) –

+0

Vous pouvez définir dynamiquement la chaîne "% f" pour avoir bonne largeur. Vous devez gérer les espaces, les zéros, les zéros, les +, - et d'autres cas spéciaux pour être totalement robustes. –

+0

snprintf serait une version 'sûre' - http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.basetechref/doc/basetrf1/printf.htm –

0

I »(est-il même possible dans ce cas?) d convertit la chaîne en sa représentation numérique en bits, (un tableau de bits ou un long), puis convertit la chaîne en un double et vérifie s'ils correspondent.

+0

..et si (sur votre machine) long double est la même taille que le double? – DJClayworth

+0

Désolé, j'ai posté ce commentaire à la mauvaise réponse. – DJClayworth

1

Voici ma version. sprintf convertit 0,5 à 0,50000, les zéros à la fin doivent être supprimés.

EDIT: Doit être réécrit pour gérer des nombres sans point décimal se terminant par 0 correctement (comme 12300).

 
bool isRepresentable(const char* realNumber) 
{ 
    bool answer = false; 

    double dVar = atof(realNumber); 
    char check[20]; 
    sprintf(check, "%f", dVar); 

    // Remove zeros at end - TODO: Only do if decimal point in string 
    for (int i = strlen(check) - 1; i >= 0; i--) { 
    if (check[i] != '0') break; 
    check[i] = 0; 
    } 

    answer = (strcmp(realNumber, check) == 0); 

    return answer; 
} 
+0

Presque - que diriez-vous de 1.200e10? – DJClayworth

5

Devoirs sacrés, batman! :)

Ce qui rend cela intéressant, c'est que vous ne pouvez pas simplement faire une boucle (atof | strtod | sscanf) -> sprintf et vérifier si vous avez récupéré la chaîne d'origine. sprintf sur de nombreuses plates-formes détecte le "aussi proche que vous pouvez obtenir à 0.1" double et l'imprime comme 0.1, par exemple, même si 0,1 n'est pas représentable avec précision.

#include <stdio.h> 

int main() { 
    printf("%llx = %f\n",0.1,0.1); 
} 

impressions: 3fb999999999999a = 0,100000

sur mon système. La vraie réponse nécessiterait probablement d'analyser le double pour le convertir en une représentation fractionnaire exacte (0,1 = 1/10), puis de s'assurer que l'atof de conversion fois le dénominateur est égal au numérateur.

Je pense.