Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected rounding of double types in C++ writing to file

I am working on a C++ program with a lot of numbers that are type double (values in the millions and billions with just a couple places to the right of the decimal point). I am performing calculations on these numbers and then printing the result to text/CSV files. I noticed that in the text files, all of my numbers appear to be rounded (to six digits). So, a value of 13,169,911 is showing up as 13,169,900 in my output file.

Is this rounding only occuring on the print? In order to get the full number of digits in the variable, do I just need to specify something when I write to a file? I included a sample of my write to file code below:

void PrintPropFinance(vector<PropFinance>& PF, int NumProps, int Iterations, int ForecastLength, 
          string CurDeal, string ModelRunID, string ScenName, Assumptions& Ass) {

string filename;
ofstream OutFile;
ostringstream s1;

s1 << BASEPATH << "Output/" << CurDeal << "_" << ModelRunID << "_" << 
            ScenName << "_PropFinance" << ".csv";
filename = s1.str();

OutFile.open(filename);

// Put in the column headers first
OutFile << "PropID" << "," 
        << "Item" << ","
        << "StartDate" << ","
        << "NumOfPeriod" << ","
        << "Result" << ","
        << "Isap" << ","
        << "CurLoanBal" << ","

for (int i=1; i<=NumProps; ++i) {
    // Populate the single-vector variables
    OutFile << PF[i].PropID << "," 
            << PF[i].Item << ","
            << PF[i].StartDate << ","
            << PF[i].NumOfPeriod << ","
            << PF[i].Result << ","
            << PF[i].Isap << ","
            << PF[i].CurLoanBal << ","
                                    << endl;
}
OutFile.close();
}

// Prop finance class definition
class PropFinance {
public:
    string PropID;
    int Item;
    string StartDate;

    int NumOfPeriod;
    string Isap;
    double CurLoanBal;
}
like image 776
brentf Avatar asked Jan 12 '23 16:01

brentf


2 Answers

The problem is likely to do with the way the output stream produces the output for doubles: if 13169911 gets printed in "scientific notation", it would look like 1.31699E7. Excel will read this notation just fine, but would put zeros for the digits it does not "see", making the number look like 13,169,900.

To fix this problem, add fixed manipulator when you output your double to ensure that all digits get printed:

OutFile << PF[i].PropID << "," 
        << PF[i].Item << ","
        << PF[i].StartDate << ","
        << PF[i].NumOfPeriod << ","
        << fixed << PF[i].Result << ","
        << PF[i].Isap << ","
        << fixed << PF[i].CurLoanBal << ","
        << endl;
like image 89
Sergey Kalinichenko Avatar answered Jan 16 '23 01:01

Sergey Kalinichenko


You need to use std::setprecision to increase the precision of the stream. By default an iostream has only 6 digits of precision.

Try this:

OutFile << std::setprecision(std::numeric_limits<long double>::digits10 << PF[i].CurLoanBal;

Bear in mind that this will affect all subsequent operations on the stream. To be honest though, that's probably what you want!

As comparison between std::setprecision and std::fixed, this program:

#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
    const long double test_value = 13169911.7777777;
    std::cout << "default precision (6):              " << test_value << '\n'
              << "std::fixed:                         " << std::fixed << test_value << '\n'
              << "std::precision(10):                 " << std::defaultfloat << std::setprecision(10) << test_value << '\n'
              << "std::precision(10) & std::fixed:    " << std::fixed        << std::setprecision(10) << test_value << '\n'
              << "max precision:                      " << std::defaultfloat << std::setprecision(std::numeric_limits<long double>::digits10) << test_value << '\n'
              << "max precision & std::fixed:         " << std::fixed        << std::setprecision(std::numeric_limits<long double>::digits10) << test_value << '\n'
    ;
}

Produces this output:

default precision (6):              1.31699e+007
std::fixed:                         13169911.777778
std::precision(10):                 13169911.78
std::precision(10) & std::fixed:    13169911.7777777000
max precision:                      13169911.7777777
max precision & std::fixed:         13169911.777777700000000

So I think you may want std::setprecision rather than std::fixed. Though I imagine that you'll only have two decimal places anyway so perhaps it doesn't matter.

Read more here: http://en.cppreference.com/w/cpp/io/manip/setprecision

like image 41
Ben Hymers Avatar answered Jan 16 '23 01:01

Ben Hymers