Significant figures in C++ - c++

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

I've found some success in just computing the integer significant figures, and then setting the floating significant figures to be X - <integer sig figs>:
Edit
To address Bob's comments, I'll account for more edge cases. I've refactored the code somewhat to adjust the field precision based on leading and trailing zeros. There would still be an edge case I believe for very small values (like std::numeric_limits<double>::epsilon:
int AdjustPrecision(int desiredPrecision, double _in)
{
// case of all zeros
if (_in == 0.0)
return desiredPrecision;
// handle leading zeros before decimal place
size_t truncated = static_cast<size_t>(_in);
while(truncated != 0)
{
truncated /= 10;
--desiredPrecision;
}
// handle trailing zeros after decimal place
_in *= 10;
while(static_cast<size_t>(_in) == 0)
{
_in *= 10;
++desiredPrecision;
}
return desiredPrecision;
}
With more tests:
double a = 0.000123456789012345;
double b = 123456789012345;
double x = 0.12345678901234567890;
double y = 1.12345678901234567890;
double z = 11.12345678901234567890;
std::cout.setf( std::ios::fixed, std:: ios::floatfield);
std::cout << "a: " << std::setprecision(AdjustPrecision(15, a)) << a << std::endl;
std::cout << "b: " << std::setprecision(AdjustPrecision(15, b)) << b << std::endl;
std::cout << "x " << std::setprecision(AdjustPrecision(15, x)) << x << std::endl;
std::cout << "y " << std::setprecision(AdjustPrecision(15, y)) << y << std::endl;
std::cout << "z: " << std::setprecision(AdjustPrecision(15, z)) << z << std::endl;
Output:
a: 0.000123456789012345
b: 123456789012345
x 0.123456789012346
y 1.12345678901235
z: 11.1234567890123
Live Demo
int GetIntegerSigFigs(double _in)
{
int toReturn = 0;
int truncated = static_cast<int>(_in);
while(truncated != 0)
{
truncated /= 10;
++toReturn;
}
return toReturn;
}
(I'm sure there are some edge cases I'm missing)
And then using it:
double x = 0.12345678901234567890;
double y = 1.12345678901234567890;
std::cout << td::setprecision(15-GetIntegerSigFigs(x)) << x
<< "\t" << std::setprecision(15-GetIntegerSigFigs(y)) << y << "\n";
Prints:
0.123456789012346 1.12345678901235
Live Demo

Related

Format a decimal to string, whilst removing any trailing zeros and avoiding scientific notation [duplicate]

What is the most elegant way to output a floating point number in C++ with no scientific notation or trailing zeros?
float a = 0.000001f;
float b = 0.1f;
cout << "a: " << a << endl; // 1e-006 terrible, don't want sci notation.
cout << "b: " << b << endl; // 0.1 ok.
cout << fixed << setprecision(6);
cout << "a: " << a << endl; // 0.000001 ok.
cout << "b: " << b << endl; // 0.100000 terrible, don't want trailing zeros.
I am not sure about the "most elegant way" but here's one way.
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std ;
string fix( float x, int p )
{
ostringstream strout ;
strout << fixed << setprecision(p) << x ;
string str = strout.str() ;
size_t end = str.find_last_not_of( '0' ) + 1 ;
return str.erase( end ) ;
}
int main()
{
float a = 0.000001f ;
float b = 0.1f ;
cout << "a: " << fix( a, 6 ) << endl; // 0.000001 ok.
cout << "b: " << fix( b, 6 ) << endl; // 0.1 ok.
return 0;
}
You could perhaps create your own I/O manipulator if you need to to a lot of this kind of output. That is arguably more elegant, but the implementation could be similar.
If string manipulating doesn't hurt your eyes:
std::string fixedfloat(float x)
{
std::ostringstream ss;
ss << std::fixed << std::setprecision(std::cout.precision()) << x;
std::string str = ss.str();
return str.substr(0, str.find_last_not_of('0') + 1);
}
int main()
{
float b = 0.1f;
std::cout << std::setprecision(6) << fixedfloat(b);
}
or
class fixedfloat
{
public:
fixedfloat(float x) : x(x) {}
float value() const { return x; }
private:
float x;
};
ostream &operator<<(ostream &out, const fixedfloat &f)
{
ostringstream ss;
ss << fixed << setprecision(out.precision()) << f.value();
string str = ss.str();
out << str.substr(0, str.find_last_not_of('0') + 1);
return out;
}
int main()
{
float b = 0.1f;
cout << setprecision(6) << fixedfloat(b);
}
the other example like mine actually output "200." or did "200" >> "2".
this should work for everything (as I took it from a string to val function I use).
string fix(float in) {
string s = to_string(in);
size_t dot = s.find_first_of('.'), last = s.find_last_not_of(".0");
if (dot!=string::npos) return s.substr(0, max(dot,last+1));
else return s;
}

Integer overflow and std::stoi

if x > INT_MAX or if x > INT_MIN the function will return 0... or that's what i'm trying to do :)
in my test case i pass in a value that is INT_MAX + 1... 2147483648 ... to introduce integer overflow to see how the program handles it.
i step through... my IDE debugger says that the value immediately goes to -2147483648 upon overflow and for some reason the program executes beyond both of these statements:
if (x > INT_MAX)
if (x < INT_MIN)
and keeps crashes at int revInt = std::stoi(strNum);
saying out of range
Must be something simple, but it's got me stumped. Why isn't the program returning before it ever gets to that std::stoi() given x > INT_MAX? Any help appreciated. Thanks! Full listing of function and test bed below: (sorry having trouble with the code insertion formatting..)
#include <iostream>
#include <algorithm>
#include <string> //using namespace std;
class Solution {
public: int reverse(int x)
{
// check special cases for int and set flags:
// is x > max int, need to return 0 now
if(x > INT_MAX)
return 0;
// is x < min int, need to return 0 now
if(x < INT_MIN)
return 0;
// is x < 0, need negative sign handled at end
// does x end with 0, need to not start new int with 0 if it's ploy numeric and the functions used handle that for us
// do conversion, reversal, output:
// convert int to string
std::string strNum = std::to_string(x);
// reverse string
std::reverse(strNum.begin(), strNum.end());
// convert reversed string to int
int revInt = std::stoi(strNum);
// multiply by -1 if x was negative
if (x < 0)
revInt = revInt * -1;
// output reversed integer
return revInt;
}
};
Main:
#include <iostream>
int main(int argc, const char * argv[]) {
// test cases
// instance Solution and call it's method
Solution sol;
int answer = sol.reverse(0); // 0
std::cout << "in " << 0 << ", out " << answer << "\n";
answer = sol.reverse(-1); // -1
std::cout << "in " << -1 << ", out " << answer << "\n";
answer = sol.reverse(10); // 1
std::cout << "in " << 10 << ", out " << answer << "\n";
answer = sol.reverse(12); // 21
std::cout << "in " << 12 << ", out " << answer << "\n";
answer = sol.reverse(100); // 1
std::cout << "in " << 100 << ", out " << answer << "\n";
answer = sol.reverse(123); // 321
std::cout << "in " << 123 << ", out " << answer << "\n";
answer = sol.reverse(-123); // -321
std::cout << "in " << -123 << ", out " << answer << "\n";
answer = sol.reverse(1024); // 4201
std::cout << "in " << 1024 << ", out " << answer << "\n";
answer = sol.reverse(-1024); // -4201
std::cout << "in " << -1024 << ", out " << answer << "\n";
answer = sol.reverse(2147483648); // 0
std::cout << "in " << 2147483648 << ", out " << answer << "\n";
answer = sol.reverse(-2147483648); // 0
std::cout << "in " << -2147483648 << ", out " << answer << "\n";
return 0;
}
Any test like (x > INT_MAX) with x being of type int will never evaluate to true, since the value of x cannot exceed INT_MAX.
Anyway, even if 2147483647 would be a valid range, its reverse 7463847412 is not.
So I think its better to let stoi "try" to convert the values and "catch" any out_of_range-exception`. The following code illustrates this approach:
int convert() {
const char* num = "12345678890123424542";
try {
int x = std::stoi(num);
return x;
} catch (std::out_of_range &e) {
cout << "invalid." << endl;
return 0;
}
}

The code is printing the same values when it should be randomly generating each ovr and also it is not printing the first value in the array

The issue that I am having is that with the code below, each plOvr for all of the class objects is the same. This causes them to have the same stats for everything. Also, I have an array with names that should be printed but it is skipping the first value.
using namespace std;
class Player
{
public:
int plOvr;
float plSpg, plSps;
string werk;
void setPlayeName(string);
string plName;
void setPlyrVal()
{
srand (time(NULL));
plOvr = rand()% 29 + 70;
plSps = plOvr / 10;
plSpg = plSps / 2;
}
};
void Player::setPlayeName(string werk)
{
plName = werk;
}
int main()
{
Player plyr1,plyr2,plyr3,plyr4,plyr5;
string firstTime;
string name[5] = {"Eric Gelinas","John Merill", "Jaromir Jagr", "Travis Zajac","Reid Boucher"};
bool firstOp;
cout << "Is this the first time this program has run?" << endl;
cin >> firstTime;
if (firstTime == "Yes" || firstTime == "yes")
{
firstOp == firstOp;
plyr1.setPlyrVal();
plyr1.setPlayeName(name[1]);
plyr2.setPlyrVal();
plyr2.setPlayeName(name[2]);
plyr3.setPlyrVal();
plyr3.setPlayeName(name[3]);
plyr4.setPlyrVal();
plyr4.setPlayeName(name[4]);
plyr5.setPlyrVal();
plyr5.setPlayeName(name[5]);
ofstream playerSaveData;
playerSaveData.open ("savedata.txt");
playerSaveData << plyr1.plName << "," << plyr1.plOvr << "," << plyr1.plSpg << "," << plyr1.plSps << "\n";
playerSaveData << plyr2.plName << "," << plyr2.plOvr << "," << plyr2.plSpg << "," << plyr2.plSps << "\n";
playerSaveData << plyr3.plName << "," << plyr3.plOvr << "," << plyr3.plSpg << "," << plyr3.plSps << "\n";
playerSaveData << plyr4.plName << "," << plyr4.plOvr << "," << plyr4.plSpg << "," << plyr4.plSps << "\n";
playerSaveData << plyr5.plName << "," << plyr5.plOvr << "," << plyr5.plSpg << "," << plyr5.plSps << "\n";
playerSaveData.close();
cout << "done.\n";
}
else
{
firstOp == !firstOp;
}
return 0;
}
You may use std::uniform_int_distribution<int> and an engine as std::mt19937 from <random>.
The engine (as srand) has to be initialized with seed only once.
Your program rewritten:
#include <ctime>
#include <iostream>
#include <fstream>
#include <string>
#include <random>
class Player
{
public:
void setPlayeName(const std::string& name) { plName = name; }
void setPlyrVal(std::mt19937& rand_engine)
{
std::uniform_int_distribution<int> distr(70, 98);
plOvr = distr(rand_engine);
plSps = plOvr / 10;
plSpg = plSps / 2;
}
public:
int plOvr;
float plSpg, plSps;
std::string werk;
std::string plName;
};
int main()
{
std::mt19937 rand_engine(time(nullptr));
Player plyrs[5];
const std::string names[5] = {"Eric Gelinas","John Merill", "Jaromir Jagr", "Travis Zajac","Reid Boucher"};
std::cout << "Is this the first time this program has run?" << std::endl;
std::string firstTime;
std::cin >> firstTime;
if (firstTime == "Yes" || firstTime == "yes") {
for (int i = 0; i != 5; ++i) {
plyrs[i].setPlyrVal(rand_engine);
plyrs[i].setPlayeName(names[i]);
}
std::ofstream playerSaveData;
playerSaveData.open ("savedata.txt");
for (const auto& plyr : plyrs) {
playerSaveData << plyr.plName << "," << plyr.plOvr << "," << plyr.plSpg << "," << plyr.plSps << "\n";
}
std::cout << "done." << std::endl;
}
return 0;
}
Live example
You should call srand() only once in the whole program, instead of calling it before each rand().

Histogram Formatting

I am writing a program to create a horizontal histogram from an array of type double data. I was able to get the program to display the boundaries of each sub-interval along with the correct number of asterisks. However, the data is not formatted.
Here's the part of the program responsible for the output:
// endpoints == the boundaries of each sub-interval
// frequency == the number of values which occur in a given sub-interval
for (int i = 0; i < count - 1; i++)
{
cout << setprecision(2) << fixed;
cout << endPoints[i] << " to " << endPoints[i + 1] << ": ";
for (int j = frequency[i]; j > 0; j--)
{
cout << "*";
}
cout << " (" << frequency[i] << ")" << endl;
}
Here's what my output looks like:
0.00 to 3.90: *** (3)
3.90 to 7.80: * (1)
7.80 to 11.70: * (1)
11.70 to 15.60: (0)
15.60 to 19.50: ***** (5)
Here's what I would like it to look like:
00.00 to 04.00: *** (3)
04.00 to 08.00: * (1)
08.00 to 12.00: * (1)
12.00 to 16.00: (0)
16.00 to 20.00: ****** (6)
I've looked up C++ syntax and have found things like setw() and setprecision(). I tried to use both to format my histogram but have not been able to make it look like the model. I was hoping someone could tell me if I'm on the right track and, if so, how to implement setw() and/or setprecision() to properly format my histogram.
Assuming that all numbers are in the [0,100) interval, what you want is a chain of manipulators like:
#include <iostream>
#include <iomanip>
int main() {
std::cout
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< 2.0
<< std::endl;
return 0;
}
Which will output:
02.00
This is for a single value, you can easily adapt it to suit your needs.
You could, for instance, turn this into an operator and use it like:
#include <iostream>
#include <iomanip>
class FixedDouble {
public:
FixedDouble(double v): value(v) {}
const double value;
}
std::ostream & operator<< (std::ostream & stream, const FixedDouble &number) {
stream
<< std::setfill('0') << std::setw(5)
<< std::setprecision(2) << std::fixed
<< number.value
<< std::endl;
return stream;
}
int main() {
//...
for (int i = 0; i < count - 1; i++) {
std::cout
<< FixedDouble(endPoints[i])
<< " to "
<< FixedDouble(endPoints[i + 1])
<< ": ";
}
for (int j = frequency[i]; j > 0; j--) {
std::cout << "*";
}
std::cout << " (" << frequency[i] << ")" << std::endl;
//...
}

How to output float to cout without scientific notation or trailing zeros?

What is the most elegant way to output a floating point number in C++ with no scientific notation or trailing zeros?
float a = 0.000001f;
float b = 0.1f;
cout << "a: " << a << endl; // 1e-006 terrible, don't want sci notation.
cout << "b: " << b << endl; // 0.1 ok.
cout << fixed << setprecision(6);
cout << "a: " << a << endl; // 0.000001 ok.
cout << "b: " << b << endl; // 0.100000 terrible, don't want trailing zeros.
I am not sure about the "most elegant way" but here's one way.
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std ;
string fix( float x, int p )
{
ostringstream strout ;
strout << fixed << setprecision(p) << x ;
string str = strout.str() ;
size_t end = str.find_last_not_of( '0' ) + 1 ;
return str.erase( end ) ;
}
int main()
{
float a = 0.000001f ;
float b = 0.1f ;
cout << "a: " << fix( a, 6 ) << endl; // 0.000001 ok.
cout << "b: " << fix( b, 6 ) << endl; // 0.1 ok.
return 0;
}
You could perhaps create your own I/O manipulator if you need to to a lot of this kind of output. That is arguably more elegant, but the implementation could be similar.
If string manipulating doesn't hurt your eyes:
std::string fixedfloat(float x)
{
std::ostringstream ss;
ss << std::fixed << std::setprecision(std::cout.precision()) << x;
std::string str = ss.str();
return str.substr(0, str.find_last_not_of('0') + 1);
}
int main()
{
float b = 0.1f;
std::cout << std::setprecision(6) << fixedfloat(b);
}
or
class fixedfloat
{
public:
fixedfloat(float x) : x(x) {}
float value() const { return x; }
private:
float x;
};
ostream &operator<<(ostream &out, const fixedfloat &f)
{
ostringstream ss;
ss << fixed << setprecision(out.precision()) << f.value();
string str = ss.str();
out << str.substr(0, str.find_last_not_of('0') + 1);
return out;
}
int main()
{
float b = 0.1f;
cout << setprecision(6) << fixedfloat(b);
}
the other example like mine actually output "200." or did "200" >> "2".
this should work for everything (as I took it from a string to val function I use).
string fix(float in) {
string s = to_string(in);
size_t dot = s.find_first_of('.'), last = s.find_last_not_of(".0");
if (dot!=string::npos) return s.substr(0, max(dot,last+1));
else return s;
}