I am trying to round in scientific notation but considering the correct rule which is:
A) for all decimal numbers finishing by 0, 1, 2, 3, 4 the rounding must be at the low order of magnitude
B) for all decimal numbers finishing by 5, 6, 7, 8, 9 the rounding must be up.
I did the following function:
std::string MyClass::doubleToString(double num, int precision) {
std::ostringstream ss;
ss << std::scientific << std::setprecision(precision) << num;
return ss.str();
}
For instance, when I call doubleToString(0.35, 0), it returns 3E-1 while it should return 4E-1.
I think it is a very simple question but I cannot figure out why I do not get the correct behavior.
It seems that you are trying to round half up1.
In C++ you can try to change the floating-point rounding mode using std::fesetround:
#include <iostream>
#include <iomanip>
#include <cfenv>
int main()
{
std::cout << std::setprecision(0) << std::scientific;
std::fesetround(FE_DOWNWARD);
std::cout << "rounding down: " << 0.35 << "\n\n"; // --> 3e-01
std::fesetround(FE_UPWARD);
std::cout << "rounding up: " << 0.35 << '\n'; // --> 4e-01
}
See e.g. https://godbolt.org/z/WhGe89one
Note though, that this won't produce the output you want.
https://en.wikipedia.org/wiki/Rounding#Rounding_half_up
Related
I have a float number ranging from 0.001 up to 999.999
The question: how I can format all the range numbers like this:
0.001 becomes 000.001
0.002 becomes 000.002
0.2 becomes 000.200
1.001 becoes 001.001
9.090 becomes 009.090
99.100 becomes 099.100
Thanks
Please inspect documentation of of stream manipulators.
There couple tools which will let you do it:
while (std::cin >> x) {
std::cout
<< std::setfill('0') << std::setw(7)
<< std::fixed << std::setprecision(3)
<< x << '\n';
}
std::fixed forces fixed format (decimal separator in same place)
std::setprecision(3) defines how many digits should be after a decimal separator.
std::setw(7) - defines minimum space number should occupy
std::setfill('0') defines what should be used to fill extra space introduced by std::setw(7).
https://godbolt.org/z/zf6q8n97r
Extra note:
C++20 introduces nice type safe and clean equivalent of printf from C: format, but there is no compiler which already supports that.
use std stream formatters from iomanip.
Stop using printf : Why not use printf() in C++
#include <iostream>
#include <iomanip>
#include <vector>
int main()
{
std::vector<double> values{ 0.001, 0.002, 0.2, 1.001, 9.090, 99.100 };
for (const auto value : values)
{
std::cout << std::fixed;
std::cout << std::setprecision(3);
std::cout << std::setfill('0') << std::setw(7);
std::cout << value << std::endl;
}
return 0;
}
With std::printf:
#include <cstdio>
int main(void)
{
float f = 99.01f;
std::printf("%07.03f", f);
}
07 specifies that if the number takes up less space than 7 characters it'll be padded with leading 0s while 03 specifies that the if the numbers after the decimal point take up less space than 3 characters then it'll be padded with trailing 0s.
As of C++20 you can use similar formatting in std::format:
std::cout << std::format("{:07.03f}", f);
I am getting an issue when trying to output my float using std::cout <<
I have the following values:
vector2f = {-32.00234098f, 96.129380f} //takes 2 floats (x, y)
output: -32.0023:96.1294
What I am looking for is:
output: -32.00234098:96.129380
The actual numbers could be vary from the 7 decimal places (.0000007) to 3 decimal places (.003) so setting a fixed rounding number does not work in this case.
Any help would be great as I have tried changed to doubles as well but to no avail.
Thanks in advance!
There are 2 problems.
you need to include <iomanip> and use the std::setprecision manipulator.
To get the level of accuracy you want you will need to use doubles rather than floats.
e.g.:
#include <iostream>
#include <iomanip>
int main()
{
auto x = -32.00234098f, y = 96.129380f;
std::cout << std::setprecision(8) << std::fixed << x << ":" << y << std::endl;
// doubles
auto a = -32.00234098, b = 96.129380;
std::cout << std::setprecision(8) << std::fixed << a << ":" << b << std::endl;
}
example output:
-32.00234222:96.12937927
-32.00234098:96.12938000
You can set the output precision of the stream using std::precision manipulator.
To print trailing zeroes up to the given precision like in your example output, you need to use std::fixed manipulator.
I'm using visual studio 2015 to print two floating numbers:
double d1 = 1.5;
double d2 = 123456.789;
std::cout << "value1: " << d1 << std::endl;
std::cout << "value2: " << d2 << std::endl;
std::cout << "maximum number of significant decimal digits (value1): " << -std::log10(std::nextafter(d1, std::numeric_limits<double>::max()) - d1) << std::endl;
std::cout << "maximum number of significant decimal digits (value2): " << -std::log10(std::nextafter(d2, std::numeric_limits<double>::max()) - d2) << std::endl;
This prints the following:
value1: 1.5
value2: 123457
maximum number of significant decimal digits (value1): 15.6536
maximum number of significant decimal digits (value2): 10.8371
Why 123457 is printed out for the value 123456.789? Does ANSI C++ specification allow to display anything for floating numbers when std::cout is used without std::setprecision()?
The rounding off happens because of the C++ standard which can be seen by writing
std::cout<<std::cout.precision();
The output screen will show 6 which tells that the default number of significant digits which will be printed by the std::cout statement is 6. That is why it automatically rounds off the floating number to 6 digits.
What you have have pointed out is actually one of those many things that the standardization committee should consider regarding the standard iostream in C++. Such things work well when you write :-
printf ("%f\n", d2);
But not with std::cout where you need to use std::setprecision because it's formatting is similar to the use of %g instead of %f in printf. So you need to write :-
std::cout << std::setprecision(10) << "value2: " << d2 << std::endl;
But if you dont like this method & are using C++11 (& onwards) then you can also write :-
std::cout << "value2: " << std::to_string(d2) << std::endl;
This will give you the same result as printf ("%f\n", d2);.
A much better method is to cancel the rounding that occurs in std::cout by using std::fixed :-
#include <iostream>
#include <iomanip>
int main()
{
std::cout << std::fixed;
double d = 123456.789;
std::cout << d;
return 0;
}
Output :-
123456.789000
So I guess your problem is solved !!
I think the problem here is that the C++ standard is not written to be easy to read, it is written to be precise and not repeat itself. So if you look up the operator<<(double), it doesn't say anything other than "it uses num_put - because that is how the cout << some_float_value is implemented.
The default behaviour is what print("%g", value); does [table 88 in n3337 version of the C++ standard explains what the equivalence of printf and c++ formatting]. So if you want to do %.16g you need to change the precision by calling setprecision(16).
Here is what I am thinking:
#include <iostream>
#include <iomanip>
int main ()
{
double x = 10-9.99;
std::cout << x << std::endl;
std::cout << std::setprecision (16);
std::cout << x;
return 0;
}
The above program prints 0.01 by evaluating x before setprecision () and a long number that is not exactly equal to 0.01, for x after setprecision ().cout has a default precision of 16 when printing floating point numbers in my machine. If precision is 16, the above value should be something like 0.0100000000000000 but it remains 0.01but when I setprecision () to 16, the program prints a long number containing 16 digits. So my question is, why cout doesn't prints all the digits according to types default precision. Why we need to force cout (by using setprecision ()) to print all the digits?
why cout doesn't prints all the digits according to types default precision.
If you use std::fixed as well as setprecision, it will display however-many digits the precision asks for, without rounding and truncating.
As for why the rounding accounts for the output...
Let's get your code to print a couple other things too:
#include <iostream>
#include <iomanip>
int main ()
{
double x = 10-9.99;
std::cout << x << '\n';
std::cout << std::setprecision (16);
std::cout << x << '\n';
std::cout << 0.01 << '\n';
std::cout << std::setprecision (18);
std::cout << x << '\n';
std::cout << 0.01 << '\n';
std::cout << x - 0.01 << '\n';
}
And the output (on one specific compiler/system):
0.01 // x default
0.009999999999999787 // x after setprecision(16)
0.01 // 0.01 after setprecision(16)
0.00999999999999978684 // x after setprecision(18)
0.0100000000000000002 // 0.01 after setprecision(18)
-2.13370987545147273e-16 // x - 0.01
If we look at how 0.01 is directly encoded at 18 digit precision...
0.0100000000000000002
123456789012345678 // counting digits
...we can see clearly why it could get truncated to "0.01" during output at any precision up to 17.
You can also see clearly that there's a different value in x to that created by directly coding 0.01 - that's allowed because it's the result of a calculation, and dependent on a double or CPU-register approximation of 9.99, either or both of which have caused the discrepancy. That error is enough to prevent the rounding to "0.01" at precision 16.
Unfortunately, this kind of thing is normal when handling doubles and floats.
Consider the following:
#include <iostream>
#include <cmath>
int main()
{
using std::cout;
using std::endl;
const long double be2 = std::log(2);
cout << std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
<< endl;
cout << std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
<< endl;
}
Outputs
3, 2
3, 3
Why does the output differ? What am I missing here?
Also here is the link to codepad: http://codepad.org/baLtYrmy
And I'm using gcc 4.5 on linux, if that's important.
When I add this:
cout.precision(40);
I get this output:
2.999999999999999839754918906642444653698, 2
3.00000000000000010039712117215771058909, 3
You're printing two values that are very close to, but not exactly equal to, 3.0. It's the nature of std::floor that its results can differ for values that are very close together (mathematically, it's a discontinuous function).
#include <iostream>
#include <cmath>
#include <iomanip>
int main()
{
using std::cout;
using std::endl;
const long double be2 = std::log(2);
cout << setprecision (50)<<std::log(8.0)<<"\n";
cout << setprecision (50)<<std::log(8.0L)<<"\n";
cout << setprecision (50)<<std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
<< endl;
cout << setprecision (50)<< std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
<< endl;
return 0;
}
The output is:
2.0794415416798357476579894864698871970176696777344
2.0794415416798359282860714225549259026593063026667
2.9999999999999998397549189066424446536984760314226, 2
3.0000000000000001003971211721577105890901293605566, 3
If you check the output here, you will notice that there is a slight difference in the precision of the two outputs. These roundoff errors usually kick in on operations on float & double here while performing floor() and the results that appear are not what one feels they should be.
It is important to remember two attributes Precision & Rounding when you are working with float or double numbers.
You might want to read more about it in my answer here, the same reasoning applies here as well.
To expand on what Als is saying-
In the first case you are dividing an 8-byte double precision value by a 16-byte long double. In the second case you are dividing a 16-byte long double by a 16-byte long double. This results in a very small roundoff error which can be seen here:
cout << std::setprecision(20) << (std::log(8.0) / be2) << std::endl;
cout << std::setprecision(20) << (std::log(8.0L) / be2) << std::endl;
which yields:
2.9999999999999998398
3.0000000000000001004
Edit to say: in this case, sizeof is your friend (To see the difference in precision):
sizeof(std::log(8.0)); // 8
sizeof(std::log(8.0L)); // 16
sizeof(be2); // 16