I know that widening conversions are safe in that they result in no loss of data, but is there a real gain in precision or is it a longer representation with the same number of signifigant figures?
For example,
#include <iostream>
#include <iomanip>
int main()
{
float i = 0.012530f;
std::cout << std::setw(20) << std::setprecision(7) << i << std::endl;
double ii = (double)i;
std::cout << std::setw(20) << std::setprecision(15) << ii << std::endl;
double j = 0.012530;
std::cout << std::setw(20) << std::setprecision(15) << j << std::endl;
}
Produces the output
0.01253
0.012529999949039
0.01253
Looking at the variables in the debugger shows that j is rounded as floating point cannot represent the original number exactly, but it is still a more exact approximation of the original number than ii.
i = 0.012530000
ii = 0.012529999949038029
j = 0.012529999999999999
Why is it that the cast is less exact than the direct assignment? Can I only count on 8 digits of exactitude if I widen the precision of a float?
It seems like the answer to your question is obvious. Because double holds more precision than float, you get a more precise value if you assign directly to a double and lose precision if you go through a float.
When you do float i = 0.012530f; you get a float that's as close to 0.01253 as a float can get. To 7 digits, that looks like 0.012530.
When you do double j = 0.012530;, you get a double that's as close to 0.01253 as a double can get.
If you cast the float to a double, you get a double that's as close to 0.01253 as a float can get.
You can't really compare numbers output to different precisions to see which is closer. For example, say the correct number is 0.5, and you have two approximations, "0.5001" and "0.49". Clearly, the first is better. But if you display the first with 5 decimal digits "0.5001" and the second with only one decimal digit "0.5", the second looks closer. Your first output has this kind of false, apparent precision due to showing with few digits and lucky rounding.
Related
For a number a = 1.263839, we can do -
float a = 1.263839
cout << fixed << setprecision(2) << a <<endl;
output :- 1.26
But what if i want set precision of a number and store it, for example-
convert 1.263839 to 1.26 without printing it.
But what if i want set precision of a number and store it
You can store the desired precision in a variable:
int precision = 2;
You can then later use this stored precision when converting the float to a string:
std::cout << std::setprecision(precision) << a;
I think OP wants to convert from 1.263839 to 1.26 without printing the number.
If this is your goal, then you first must realise, that 1.26 is not representable by most commonly used floating point representation. The closest representable 32 bit binary IEEE-754 value is 1.2599999904632568359375.
So, assuming such representation, the best that you can hope for is some value that is very close to 1.26. In best case the one I showed, but since we need to calculate the value, keep in mind that some tiny error may be involved beyond the inability to precisely represent the value (at least in theory; there is no error with your example input using the algorithm below, but the possibility of accuracy loss should always be considered with floating point math).
The calculation is as follows:
Let P bet the number of digits after decimal point that you want to round to (2 in this case).
Let D be 10P (100 in this case).
Multiply input by D
std::round to nearest integer.
Divide by D.
P.S. Sometimes you might not want to round to the nearest, but instead want std::floor or std::ceil to the precision. This is slightly trickier. Simply std::floor(val * D) / D is wrong. For example 9.70 floored to two decimals that way would become 9.69, which would be undesirable.
What you can do in this case is multiply with one magnitude of precision, round to nearest, then divide the extra magnitude and proceed:
Let P bet the number of digits after decimal point that you want to round to (2 in this case).
Let D be 10P (100 in this case).
Multiply input by D * 10
std::round to nearest integer.
Divide by 10
std::floor or std::ceil
Divide by D.
You would need to truncate it. Possibly the easiest way is to multiply it by a factor (in case of 2 decimal places, by a factor of 100), then truncate or round it, and lastly divide by the very same factor.
Now, mind you, that floating-point precision issues might occur, and that even after those operations your float might not be 1.26, but 1.26000000000003 instead.
If your goal is to store a number with a small, fixed number of digits of precision after the decimal point, you can do that by storing it as an integer with an implicit power-of-ten multiplier:
#include <stdio.h>
#include <math.h>
// Given a floating point value and the number of digits
// after the decimal-point that you want to preserve,
// returns an integer encoding of the value.
int ConvertFloatToFixedPrecision(float floatVal, int numDigitsAfterDecimalPoint)
{
return (int) roundf(floatVal*powf(10.0f, numDigitsAfterDecimalPoint));
}
// Given an integer encoding of your value (as returned
// by the above function), converts it back into a floating
// point value again.
float ConvertFixedPrecisionBackToFloat(int fixedPrecision, int numDigitsAfterDecimalPoint)
{
return ((float) fixedPrecision) / powf(10.0f, numDigitsAfterDecimalPoint);
}
int main(int argc, char ** arg)
{
const float val = 1.263839;
int fixedTwoDigits = ConvertFloatToFixedPrecision(val, 2);
printf("fixedTwoDigits=%i\n", fixedTwoDigits);
float backToFloat = ConvertFixedPrecisionBackToFloat(fixedTwoDigits, 2);
printf("backToFloat=%f\n", backToFloat);
return 0;
}
When run, the above program prints this output:
fixedTwoDigits=126
backToFloat=1.260000
If you're talking about storing exactly 1.26 in your variable, chances are you can't (there may be an off chance that exactly 1.26 works, but let's assume it doesn't for a moment) because floating point numbers don't work like that. There are always little inaccuracies because of the way computers handle floating point decimal numbers. Even if you could get 1.26 exactly, the moment you try to use it in a calculation.
That said, you can use some math and truncation tricks to get very close:
int main()
{
// our float
float a = 1.263839;
// the precision we're trying to accomplish
int precision = 100; // 3 decimal places
// because we're an int, this will keep the 126 but lose everything else
int truncated = a * precision; // multiplying by the precision ensures we keep that many digits
// convert it back to a float
// Of course, we need to ensure we're doing floating point division
float b = static_cast<float>(truncated) / precision;
cout << "a: " << a << "\n";
cout << "b: " << b << "\n";
return 0;
}
Output:
a: 1.26384
b: 1.26
Note that this is not really 1.26 here. But is is very close.
This can be demonstrated by using setprecision():
cout << "a: " << std:: setprecision(10) << a << "\n";
cout << "b: " << std:: setprecision(10) << b << "\n";
Output:
a: 1.263839006
b: 1.25999999
So again, it's not exactly 1.26, but very close, and slightly closer than you were before.
Using a stringstream would be an easy way to achieve that:
#include <iostream>
#include <iomanip>
#include <sstream>
using namespace std;
int main() {
stringstream s("");
s << fixed << setprecision(2) << 1.263839;
float a;
s >> a;
cout << a; //Outputs 1.26
return 0;
}
I run this code but the output was different from what I expected.
The output:
c = 1324
v = 1324.99
I expected that the output should be 1324.987 for v. Why is the data in v different from output?
I'm using code lite on Windows 8 32.
#include <iostream>
using namespace std;
int main()
{
double v = 1324.987;
int n;
n = int (v);
cout << "c = " << n << endl;
cout << "v = " << v << endl;
return 0;
}
Floating point types inherit rounding errors as a result of their fixed width representations. For more information, see What Every Computer Scientist Should Know About Floating-Point Arithmetic.
The default precision when printing with cout is 6, so only 6 decimal places will be displayed. The number is rounded to the nearest value, that's why you saw 1324.99. You need to set a higher precision to see the more "correct" value
However, setting the precision too high may print out a lot of garbage digits behind, because binary floating-point types cannot store all decimal floating-point values exactly.
How I can prevent rounding error in C++ or fix it?
Example:
float SomeNumber = 999.9999;
cout << SomeNumber << endl;
It prints out 1000!
You can alter the rounding done by cout by setting the precision.
cout.precision(7);
float SomeNumber = 999.9999;
cout << SomeNumber << endl;
Alternatively, you can use printf from cstdio.
By default, formatted output via std::ostream rounds floating-point values to six significant decimal figures. You need seven to avoid your number being rounded to 1000:
cout << setprecision(7) << SomeNumber << endl;
^^^^^^^^^^^^^^^
Also, be aware that you're close to the limit of the precision of float, assuming the commonly-used 32-bit IEEE representation. If you need more than seven significant figures then you'll need to switch to double. For example, the following prints 1000, no matter how much precision you specify:
float SomeNumber = 999.99999; // 8 significant figures
cout << setprecision(10) << SomeNumber << endl;
To prevent your output being rounded, use setprecision in iomanip.
float SomeNumber = 999.9999;
std::cout << SomeNumber << std::endl; //outputs 1000
std::cout << std::setprecision (7) << SomeNumber << std::endl; //outputs 999.9999
return 0;
The actual value stored in SomeNumber will always be 999.9999 though, so you don't need to worry about the value itself (unless you need more precision than float provides).
As mentioned previously, if you're looking only for cout rounding fix, use the .precision function. If you're referring to the incapacity of floating points to represent every possible fractions, read below:
You can't avoid such rounding errors using floating point numbers. You need to represent your data in a different way. For example, if you want 5 digits of precision, just store it as a long which represent the number of your smallest units.
I.e. 5.23524 w/ precision at 0.00001 can be represented in a long (or int if your range of values fit) as 523524. You know the units are 0.00001 so you can easily make it work.
I have the following :
int R=25;
double pi=3.14;
double r=R*sqrt(rand());
cout<<"r: "<<r<<endl;
double th=2*pi*rand();
cout<<"th: "<<theta<<endl;
I want to convert : r=1.98 and th=5.08. I would also like the double result=r*th to be with 2 zecimals.
when I print double result =r*th; the number is very huge and is not realistic.
How to change the r and th value to 1.98 and 5.08? How to solve this?
I need to change each double to just 2 decimals after "."
I am working in c++ under ubuntu.
Thx appreciate
To produce random values in the range you specified, try this:
r = (R*(rand()/(RAND_MAX + 1.0)));
th = (2*3.14*(rand()/(RAND_MAX + 1.0)));
The expression rand()/(RAND_MAX+1.0) produces values in the range [0,1.0). Multiplying that by the range limit gives you the numbers you want.
Note: this doesn't limit the numbers to two decimal places, which is more a function of how you print them. To print them with two decimal places, try this:
std::cout << std::fixed << std::setprecision(2) << r << "\n";
std::cout << std::fixed << std::setprecision(2) << th << "\n";
std::cout << std::fixed << std::setprecision(2) << (r*th) << "\n";
See this question: C++ generating random numbers
If you need to make both numbers smaller by the same amount then you can simply divide them both by the same number. You'll lose approximately the same precision either way.
If you really want to completely alter the result by chopping off the exponent then you could probably dig into the double number format itself and separate out the mantissa.
Why you would do this is a mystery to me.
Floating point precision is limited in C++ and for novice programmers that often causes trouble when rounding values.
When teaching students it is often useful to demonstrate the floating point precision number rounding issue. What possible ways do you know to demonstrate such rounding issue consistently on all C++ compilers?
You can use this example:
#include <iostream>
using namespace std;
int main() {
for (double d = 0.0; d != 1.0; d += 0.1)
cout << d << "\n";
}
The program will never terminate as d never equals 1.
First, we should note that, in IEEE754 floating point, 1.5, 0.5, and 2.0 are all exactly represented. So, in this specific example, 1.5 will never be 1.499999999999.
Having said that, I think the thing to do is to expose your students to numbers are not exactly representable. Say, 1.1.
Here is a sample program:
#include <iostream>
#include <iomanip>
int main() {
std::cout << std::setprecision(30);
double d1(1.1);
std::cout << d1 << "\n";
double d2(11);
double eps = d2/10 - d1;
std::cout << d2 << "\n";
std::cout << eps << "\n";
bool equal = (d1 == d2);
std::cout << equal << "\n";
}
Perhaps you can walk them through this program, being careful to say that d1 and d2 are both approximately equal to 1.1.
For advanced students, you can go through factional binary arithmetic and see why 1/2 is representable, but 1/10 is not.
EDIT: I think the way to bring the point home is to compare repeating decimal fractions with repeating binary fractions. Show your students 1/7 in decimal. Do the long division on the board. Point out that you cannot write 1/7 down exactly using finite resources. Then, either show them how to write 1/10 as a binary fraction, or just tell them that you can't write down it either using finite resources.
Point out that floats are finite (32 bits) and doubles are finite (64 bits). Maybe introduce pigeonhole principal and say that you can't represent an infinite set (like all rationals) in a finite word length.
Whatever you try, please report back here and let us know how it works.
I like the following example:
double sum = 0;
for (int i = 0; i < 10; i++, sum += 0.1);
cout << "sum = " << sum << endl;
cout << "(sum == 1.) is " << boolalpha << (sum == 1.) << endl;
The output follows:
sum = 1
(sum == 1.) is false
The cause of contradiction is floating point calculations.
printf("%.20f\n",0.1f);
or
cout << fixed << setprecision(20) << 0.1f << endl;
:)
Try this example:
#include <cstdio>
int main() {
printf("%.20lf rounded to two decimal places is %.2lf\n", 0.075, 0.075);
return 0;
}
which prints
0.07499999999999999722 rounded to two decimal places is 0.07
note that 0.075 rounded to two decimal places should be 0.08, not 0.07 as we see in the output. This example clearly demonstrates double rounding issue