c++precisionpoint-cloud-libraryboost-lexicalcast

Set precision of a double variable in 'string to double' using lexical cast


I have a string which has the value "496934.079" . I use boost::lexical_cast () to convert this into a double variable (named pVar).

However the value stored in pVar after conversion is "496934" not "496934.079". The digits after the decimal points are missing. I have read about std::setprecision() for writing the double value with needed precision in the output window here. But it only displays value with the given precision and it does not saves it in the variable with the given prescision.

But I want to store the double value exactly as it is in the string variable str so that the value in pVar is "496934.079". How can I store the value in the variable with same precision as in the input string so that I can use the variable for further processing?

My code snippet is:

int func()
{
    string str = "496934.079";
    double pVar = boost::lexical_cast<double> (str);
    cout << pVar << endl;
    return 0;
}

EDIT: This conversion from string to float is part of the code I am developing which parses values from a text file line-by-line and writes them into another file (.pcd format). I am adding the entire code I use for this conversion for reference.

int txt2pcd()
{
    ifstream is("input_text_file.txt");                                         //read input text file
    string str;
    using namespace boost::algorithm;
    pcl::PointCloud<pcl::PointXYZ>::Ptr point_cloud_ptr (new pcl::PointCloud<pcl::PointXYZ>);
    while(getline(is, str))                                                     //parsing the text file contents line-by-line
    {   
        std::string s = str.c_str();
        std::vector<std::string> result;            
        std::istringstream iss(s);
        for(std::string s; iss >> s; )
            result.push_back(s);

        pcl::PointXYZ point;

        point.x = boost::lexical_cast<double> (result[0]);                      //string to float conversion for adding the X coordinate of the point
        point.y = boost::lexical_cast<double> (result[1]);                      //string to float conversion for adding the Y coordinate of the point
        point.z = boost::lexical_cast<double> (result[2]);                      //string to float conversion for adding the Z coordinate of the point

        point_cloud_ptr->points.push_back (point);
        point_cloud_ptr->width = (int) point_cloud_ptr->points.size ();
        point_cloud_ptr->height = 1;            
    }   
    pcl::io::savePCDFile ("output_pcd_file.pcd", *point_cloud_ptr, false);    //this is where the converted float values are stored (with digits altered after decimal point when compared to text file)
    return 0;
}

Below are few sample few lines from the text file and the corresponding lines from the converted '.pcd' file.

In text file:

496934.999 5419547.239 265.179

496933.981 5419542.579 263.819

496934.891 5419545.399 264.849

496934.939 5419546.329 265.111

496934.829 5419544.489 264.781

In '.pcd' file (corresponding values resulting from boost::lexical_cast ())

496935 5419547 265.17899

496933.97 5419542.5 263.819

496934.91 5419545.5 264.849

496934.94 5419546.5 265.11099

496934.84 5419544.5 264.78101

Note that the values are either rounded off or the digits after decimal point are altered in the output '.pcd' file. What could be the reason for this?


Solution

  • boost::lexical_cast<double>(str) already returns the full value 496934.079 as a double. This full value is stored in pVar, and can be used for further processing.

    string str = "496934.079";
    double pVar = boost::lexical_cast<double>(str); // pVar now contains 496934.079
    

    std::setprecision does not impact the stored value - it merely sets the number of digits (before and after the decimal point) that are displayed. The default display precision is 6, so :

    std::cout << pVar << std::endl; // this prints "496934" (6 digits)
    

    Displaying the stored value with a higher precision (eg. 10) gives :

    #include <iomanip>
    
    std::cout << std::setprecision(10) << pVar << std::endl; // this prints "496934.079"
    

    But to re-iterate : none of this impacts the stored value. pVar still contains 496934.079. For example :

    std::cout << (int) (pVar * 1000) << std::endl; // this displays 496934079
    

    EDIT

    The updated code in the question shows that actually, a float is used to store the value, not a double (ref. pcl::PointXYZ).

    A float doesn't have enough precision to store the full value 496934.079 - instead it will store the best approximation (496934.09375) it can represent (ref. eg. What is the difference between float and double?).

    If you want to ensure you can retain the full value (unmodified), make sure to stick to double.