I wrote a program in C and I think the result of it should be 12.3 and 12.2. But the final result is 12.2 and 12.2. Obviously, it is not rounding rightly. But why? Thanking you very much :)
#include <iostream>
#include <iomanip>
using namespace std;
string dtos(double num) {
stringstream ss;
ss << fixed << setprecision(1) << num;
return ss.str();
}
int main() {
double num1 = 12.25;
double num2 = 12.24;
string str1 = dtos(num1);
string str2 = dtos(num2);
cout << str1 << ' ' << str2 << endl;
return 0;
}
I also tried the way that num1 = 12.05 and num2 = 12.04 and get the desired result as 12.1 and 12.0.
CodePudding user response:
Before you ask "why double num1 = 12.25;
is not successfully rounded up to 12.3", you have to be aware that double/float cannot represent all non-decimal numbers, and comparing double/float is not that "accurate"; see https://en.wikipedia.org/wiki/IEEE_754
Regarding your question, it might because that num1
does not contain 12.25, but something smaller than that (something like, 12.2499999999...) and the comparision (num1 >= 12.5) is not necessary true. If you set it to 12.26 or 12.51, you will see the expected output.
CodePudding user response:
I inspected the feature of each round function. As a result, basically these functions return nearest integer from the value, but if the value is in the position of halfway between two integers, there are the type of behaviors below for calculating.
- rounding type
- NI: nearest integer far from zero. (e.g. 2.5 -> 3)
- NE: nearest even integer from the value. (e.g. 2.5 -> 2)
- halfway type
- Exactly: take floating point error into account. (e.g. 2.500002 is not halfway)
- Not Exactly: ignore floating point error. (e.g. 2.500002 is regarded as 2.5)
That's why each function can be classified to several types below.
setprecision
- rounding type: NE
- halfway type: Exactly
rint
- rounding type: NE
- halfway type: Not Exactly
round
- rounding type: NI
- halfway type: Not Exactly
#include <iostream>
#include <cfenv>
#include <iomanip>
#include <math.h>
using namespace std;
int main() {
fesetround(FE_TONEAREST);
//fesetround(FE_DOWNWARD);
//fesetround(FE_UPWARD);
printf("round type=%d\n\n", fegetround());
auto f = [&](auto v) {
printf("%-14s %.30f\n", "orig val", v);
cout << fixed << "setprecision" << setw(7) << setprecision(1) << v << endl;
printf("%-14s %.30f\n", "rint", rint((v * 10)) / 10);
printf("%-14s %.30f\n", "round", round((v * 10)) / 10);
cout << "-----------------" << endl;
};
f(12.05);
f(12.25);
f(12.35);
f(12.75);
}
output is
round type=0
orig val 12.050000000000000710542735760100
setprecision 12.1
rint 12.000000000000000000000000000000
round 12.099999999999999644728632119950
-----------------
orig val 12.250000000000000000000000000000
setprecision 12.2
rint 12.199999999999999289457264239900
round 12.300000000000000710542735760100
-----------------
orig val 12.349999999999999644728632119950
setprecision 12.3
rint 12.400000000000000355271367880050
round 12.400000000000000355271367880050
-----------------
orig val 12.750000000000000000000000000000
setprecision 12.8
rint 12.800000000000000710542735760100
round 12.800000000000000710542735760100
-----------------