2017-04-14 5 views
0

Je ces trois chiffres:Comment analyser et de diviser un double en C++

double n1 = 1.1 
double n2 = 1.10 
double n3 = 1.101 

et je me attends à les convertir en chaînes pour séparer les parties décimales pour les utiliser ailleurs. Par conséquent, je veux avoir les éléments suivants:

string s1 = 1 
string s2 = 10 
string s3 = 101 

Je lis que ce n'est pas possible en utilisant std::to_string car il renvoie toujours toutes les décimales, par exemple s3 serait quelque chose comme 101000.

Je puis essayé ce qui suit:

double n3 = 1.101; 
std::ostringstream strs; 
strs << n3; 
std::string str = strs.str(); 

boost::char_separator<char> sep("."); 
boost::tokenizer<boost::char_separator<char>> tokens(str,sep); 

for (const auto& t : tokens) { 
    EV << "separated parts " << t << endl; 
} 

Cela fonctionne très bien dans n1 et n3 cas, mais quand je l'utilise n2 retourne 1 au lieu de 10.

Je réfléchis à la façon de résoudre ce problème et la seule chose à faire est de compter la précision avant de la convertir en chaîne, puis de redéfinir la précision.

Est-ce une stratégie viable? Comment puis-je compter le nombre de chiffres après le point?

+0

'1.1 == 1.10', il n'y a aucune différence. – Jarod42

+0

Simple mathématique élémentaire, peu importe le nombre de zéros à la fin de la partie décimale. Donc, 1.1 == 1.10, aussi 1.10 == 1.100000000000000000 ... –

+0

Pourquoi ne pas utiliser ['std :: modf()'] (http://fr.cppreference.com/w/cpp/numeric/math/modf) ? – piwi

Répondre

2

Si vos nombres apparaissent initialement dans le type de données double, je ne vois aucune chance de séparer la partie décimale telle qu'elle est écrite dans le littéral utilisé pour l'initialisation. Ces informations sont tout simplement perdu que je vais essayer d'expliquer dans les paragraphes suivants:

Notez que littéraux 1.10 et 1.1 les deux se tiennent pour un littéral numérique de type double. Le compilateur traduira les deux littéraux dans une représentation à virgule flottante/représentation binaire, et 1.10 et 1.1 obtiendra exactement la même représentation binaire. Par conséquent, vous n'aurez aucune chance de savoir si une double valeur a été initialisée avec un littéral 1.1 ou 1.10.

Les choses deviennent encore pire quand on considère que nombre décimal 1.1 n'a pas une représentation binaire exacte, mais conduit à une fraction de répétition:

0.1₁₀ = 0.0001100110011001100110011001100110011001100110011…₂ 

Ainsi, lorsque vous imprimez 1.1 littérale (ou 1.10, qui est le même), cela dépend de la précision sur laquelle vous souhaitez arrondir:

std::cout << "1.1 is..." << std::setprecision(6) << 1.1 << std::endl; 
std::cout << "1.1 is..." << std::setprecision(17) << 1.1 << std::endl; 
// 1.1 is...1.1 
// 1.1 is...1.1000000000000001 

Cela signifie que - une fois stocké sous la forme d'une double valeur, vous obtenez des résultats différents en fonction de la pré cision que vous utilisez pour imprimer la valeur; Cela s'applique également à la conversion de la partie décimale en une chaîne de caractères, ce qui revient à imprimer avec une précision particulière.

encore plus pire, en raison d'être pas en mesure de représenter exactement toutes les valeurs décimales sous une forme binaire, deux valeurs décimales différentes peuvent donner la même valeur sous forme binaire:

double n1 = 1.1; 
double n2 = 1.100000000000000088817841970012523233890533447265625; 

if (n1 == n2) 
    std::cout << "equal!" << std::endl; 
// Output: equal! 

vous ne pouvez pas distinguer n1 et n2 plus.

Beaucoup de mots, et une brève conclusion:

Si vous voulez distinguer 1.1 de 1.10, ou si vous voulez généralement savoir la partie décimale de littéraux numériques comme écrit dans votre code source, vous avoir à les stocker initialement en tant que chaînes, pas en tant que doubles.

0

Je suppose que vous n'êtes pas familier avec ce qu'est réellement un nombre 'virgule flottante'. Un double est un nombre à virgule flottante comme décrit sur https://en.wikipedia.org/wiki/IEEE_floating_point. Fondamentalement 1.10 est le même que 1.1, qui est le même que 1.1000000 et ainsi de suite. Il existe maintenant des solutions appelées «nombres à virgule fixe», plus communément appelées «décimales» et «numériques». Si vous êtes familier avec les moteurs de base de données, vous savez que 1.10 est un numérique (3,2) et 1,1 est un numérique (2,1). Remarquez comment le type change et définit à la fois la précision (nombre de chiffres) et l'échelle (nombre de chiffres après la virgule). Cependant, C++ ne supporte pas nativement les décimales.

+0

Merci pour votre réponse, mais je ne comprends pas comment cela m'aide. Êtes-vous en train de dire que ce que j'essaie de faire n'est pas possible? – brid

+0

@brid, un «double» ne stocke pas les informations sur le nombre de chiffres qu'il y a. Donc non, en utilisant un double simple ce n'est pas possible. Vous pouvez bien sûr l'intégrer dans une structure de données personnalisée et ajouter ces informations lors de l'analyse, ou utiliser une bibliothèque de points fixe. – atlaste

-2

C'est juste un calcul simple. L'analyseur syntaxique convertit simplement votre x.10 en x.1 :)