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.
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've noticed some weird behaviour in c++ which i don't understand,
i'm trying to print a truncated double in a hexadecimal representation
this code output is 17 which is a decimal representation
double a = 17.123;
cout << hex << floor(a) << '\n';
while this code output is 11 and also my desirable output
double a = 17.123;
long long aASll = floor(a);
cout << hex << aASll << '\n';
as double can get really big numbers i'm afraid of wrong output while storing the truncated number in long long variable, any suggestions or improvements?
Quoting CPPreference's documentation page for std::hex (and friends)
Modifies the default numeric base for integer I/O.
This suggests that std::hex does not have any effect on floating point inputs. The best you are going to get is
cout << hex << static_cast<long long>(floor(a)) << '\n';
or a function that does the same.
uintmax_t from <cstdint> may be useful to get the largest available integer if the values are always positive. After all, what is a negative hex number?
Since a double value can easily exceed the maximum resolution of available integers, this won't cover the whole range. If the floored values exceed what can fit in an integer type, you are going to have to do the conversion by hand or use a big integer library.
Side note: std::hexfloat does something very different and does not work correctly in all compilers due to some poor wording in the current Standard that is has since been hammered out and should be corrected in the next revision.
Just write your own version of floor and have it return an integral value. For example:
long long floorAsLongLong(double d)
{
return (long long)floor(d);
}
int main() {
double a = 17.123;
cout << hex << floorAsLongLong(a) << endl;
}
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.
This is a small program that calculates the gaps of 'interval' size that are beetween two numbers 'from' 'to'. Then I calculate the 'size' (number of gaps) and store it in an int variable, and give me a smaller value sometimes.
Here is the code:
double from=0, to=1, interval=0.1;
cout << "WORKING WITH VARIABLES: " << endl;
double operation = (to-from)/interval +1;
cout << "Size: " << operation << endl;
int size = operation;
cout << "Size after storing: " << size << endl << endl;
cout << "WORKING WITHOUT VARIABLES: " << endl;
cout << "Size: " << (to-from)/interval +1 << endl;
size = (to-from)/interval +1;
cout << "Size after storing: " << size << endl << endl;
Problem seems to be in how it's stored interval. If interval=1 everything is good, but if is 0.1, as in the example it give me 10 instead 11 in the "Size after storing" of the second case.
I've found out that it works well with interval=0.25 (2^-2).
EDIT: I haven't found that it fails in the first case, always does in the second.
Floating point numbers are stored with a finite precision, and in binary. 0.25 is easy. That's just 1/4, so 0.01 binary. 0.1 is 1/10, which cannot be represented by a finite binary string. It's 1/16+1/32+ ...
So 1/10 is rounded down, and 10 * 1/10 is slightly less than 1.
As for the different results in the first and second case, that's probably because intermediate values are rounded to more digits than double has.
You are suffering from the inaccuracies inherent in floating point arithmetic. What you probably get in the 0.1 case is 10.999.... instead of 11. Converting double to int truncates instead of rounding so you get 10. Add a small value before converting to int to combat this.
int size=operation+0.0000000001;
If you want to convert a double that is close to an integer (due to rounding errors, as explained by others) to an int, always round the value to the nearest integer, e.g. with round(), before converting the value to int, since double to int conversion truncates the value and will yield an incorrect result if the error is negative.
I'm new in C++ and would like to get some help.
I don't understand why I'm getting an output of only one digit after the decimal on the sum below.
I have tried to solve this with no success.
int main()
{
double alt, t;
t = 4.5;
// function for calculating the altitude over time.
alt = (-0.12)*pow(t, 4) +(12.0)*pow(t, 3) -(380.0)*pow(t, 2) +(4100.0)*t +220.0;
cout << alt << endl;
return 0;
}
The default behaviour of cout is to print six significant digits of floating points. You can change that with:
cout.precision(10);
cout << alt << endl;
which gives the output:
12019.2925
which seems to be the correct solution.
You should not try to set the precision to anything higher than roughly 15, because that is about the precision limit of the double type (typically). You can use the numeric_limits<double>::digits10 from <limits> to make sure what precision you actually have.