I've written a program that calculates values in a series and all of the values are particularly lengthy doubles. I want to print these values each displaying 15 significant figures. Here's some code that illustrates the issue I'm having:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double x = 0.12345678901234567890;
double y = 1.12345678901234567890;
cout << setprecision(15) << fixed << x << "\t" << y << "\n";
return 0;
}
With just setprecision trailing zeros are not shown so I added fixed as I have seen in other answers on this site. However, now I just seem to have 15 decimal places and for values that aren't 0.something this is not what I want. You can see this from the output of the above:
0.123456789012346 1.123456789012346
The first number has 15 sig figs but the second has 16. What can I do to resolve this?
EDIT: I have been specifically asked to use setprecision, so I am unable to try cout.precision.
You can simply use scientific (note the 14 instead of 15):
std::cout << std::scientific << std::setprecision(14) << -0.123456789012345678 << std::endl;
std::cout << std::scientific << std::setprecision(14) << -1.234567890123456789 << std::endl;
-1.23456789012346e-01
-1.23456789012346e+00
or you can use a function:
#include <iostream>
#include <vector>
#include <iomanip>
#include <string>
#include <sstream>
enum vis_opt { scientific, decimal, decimal_relaxed };
std::string figures(double x, int nfig, vis_opt vo=decimal) {
std::stringstream str;
str << std::setprecision(nfig-1) << std::scientific << x;
std::string s = str.str();
if ( vo == scientific )
return s;
else {
std::stringstream out;
std::size_t pos;
int ileft = std::stoi(s,&pos);
std::string dec = s.substr(pos + 1, nfig - 1);
int e = std::stoi(s.substr(pos + nfig + 1));
if ( e < 0 ) {
std::string zeroes(-1-e,'0');
if ( ileft < 0 )
out << "-0." << zeroes << -ileft << dec;
else
out << "0." << zeroes << ileft << dec;
} else if ( e == 0) {
out << ileft << '.' << dec;
} else if ( e < ( nfig - 1) ) {
out << ileft << dec.substr(0,e) << '.' << dec.substr(e);
} else if ( e == ( nfig - 1) ) {
out << ileft << dec;
} else {
if ( vo == decimal_relaxed) {
out << s;
} else {
out << ileft << dec << std::string(e - nfig + 1,'0');
}
}
return out.str();
}
}
int main() {
std::vector<double> test_cases = {
-123456789012345,
-12.34567890123456789,
-0.1234567890123456789,
-0.0001234,
0,
0.0001234,
0.1234567890123456789,
12.34567890123456789,
1.234567890123456789,
12345678901234,
123456789012345,
1234567890123456789.0,
};
for ( auto i : test_cases) {
std::cout << std::setw(22) << std::right << figures(i,15,scientific);
std::cout << std::setw(22) << std::right << figures(i,15) << std::endl;
}
return 0;
}
My output is:
-1.23456789012345e+14 -123456789012345
-1.23456789012346e+01 -12.3456789012346
-1.23456789012346e-01 -0.123456789012346
-1.23400000000000e-04 -0.000123400000000000
0.00000000000000e+00 0.00000000000000
1.23400000000000e-04 0.000123400000000000
1.23456789012346e-01 0.123456789012346
1.23456789012346e+01 12.3456789012346
1.23456789012346e+00 1.23456789012346
1.23456789012340e+13 12345678901234.0
1.23456789012345e+14 123456789012345
1.23456789012346e+18 1234567890123460000