2016-01-12 3 views
1

J'ai un programme C++ utilisant SDL. Pendant le rendu, j'ai besoin de dessiner des composants graphiques. J'ai parfois besoin de convertir double variables, arrondies à une décimale, à std::string.Convertir le double en corde rapidement en observant une précision donnée

Pour cela, j'utilise actuellement un objet ostringstream et cela fonctionne très bien. Cependant, je me demande si cette façon de convertir des variables est une bonne idée en termes de performance.

J'ai essayé d'arrondir les variables double avec std::to_string(std::round(x * 10)/10)), mais cela n'a pas fonctionné - j'ai toujours une sortie comme 2.500000000.

  • Existe-t-il une autre solution?
  • Est-ce que ostringstream est lourd?
+1

compte tenu de la performance: le 'ostringstream' utilisera un' locale' qui invoque certains frais généraux, sinon si vous réutiliser un seul 'ostringstream' pendant votre appel de rendu (allocation unique/croissance de la mémoire tampon interne) alors il ne devrait pas y avoir plus de surcharge que' sprintf' – BeyelerStudios

+0

* mais cela n'a pas fonctionné. * vous devriez élaborer là-dessus. – NathanOliver

+0

Juste au cas où vous * signifieriez vraiment "cela n'a pas fonctionné", vous * avez * compilé avec un compilateur C++ 11, ou votre compilateur réglé sur (au moins) la norme C++ 11, n'est-ce pas? – DevSolar

Répondre

3

Vous ne pouvez pas spécifier la précision avec std::to_string car il est un équivalent direct à printf avec le paramètre %f (si vous utilisez double).

Si vous êtes préoccupé de ne pas allouer à chaque fois que le flux, vous pouvez effectuer les opérations suivantes:

#include <iostream> 
#include <sstream> 
#include <iomanip> 

std::string convertToString(const double & x, const int & precision = 1) 
{ 
    static std::ostringstream ss; 
    ss.str(""); // don't forget to empty the stream 
    ss << std::fixed << std::setprecision(precision) << x; 

    return ss.str(); 
} 


int main() { 
    double x = 2.50000; 

    std::cout << convertToString(x, 5) << std::endl; 
    std::cout << convertToString(x, 1) << std::endl; 
    std::cout << convertToString(x, 3) << std::endl; 

    return 0; 
} 

Il délivre en sortie (see on Coliru):

2,50000

2,5

2.500

Je n'ai pas vérifié la performance cependant ... mais je pense que vous pourriez même faire mieux en encapsulant ceci dans une classe (comme appeler seulement std::fixed et std::precision une fois).

Sinon, vous pouvez toujours utiliser sprintf avec les paramètres qui vous conviennent.


Pour aller un peu plus loin, avec une classe d'encapsulage que vous pouvez utiliser comme une instance statique ou un membre d'une autre classe ... que vous le souhaitez (View on Coliru).

#include <iostream> 
#include <sstream> 
#include <iomanip> 

class DoubleToString 
{ 
public: 
    DoubleToString(const unsigned int & precision = 1) 
    { 
     _ss << std::fixed; 
     _ss << std::setprecision(precision); 
    } 

    std::string operator() (const double & x) 
    { 
     _ss.str(""); 
     _ss << x; 
     return _ss.str(); 
    } 

private: 
    std::ostringstream _ss; 

}; 


int main() { 
    double x = 2.50000; 

    DoubleToString converter; 

    std::cout << converter(x) << std::endl; 

    return 0; 
} 

Une autre solution sans utiliser ostringstream (View on Coliru):

#include <iostream> 
#include <string> 
#include <memory> 

std::string my_to_string(const double & value) { 
    const int length = std::snprintf(nullptr, 0, "%.1f", value); 

    std::unique_ptr<char[]> buf(new char[length + 1]); 
    std::snprintf(buf.get(), length + 1, "%.1f", value); 

    return std::string(buf.get()); 
} 

int main(int argc, char * argv[]) 
{ 

    std::cout << my_to_string(argc) << std::endl; 
    std::cout << my_to_string(2.5156) << std::endl; 

} 
+0

Il utilise toujours 'ostringstream' (pas de choix je suppose) mais c'est beaucoup plus propre que ma solution. Je ne vais pas le marquer comme réponse, mais je vais l'augmenter. Merci. –

+1

@ Q3SanD J'ai ajouté une autre solution sans 'ostringstream', mais je ne suis pas sûr que ce soit plus efficace, vous devriez lancer un banc. – dkg