Strange rounding behavior [duplicate] - c++

This question already has answers here:
C++ floating point precision [duplicate]
(5 answers)
Closed 5 years ago.
I'm trying to round doubles to a specific precision, however the following functions give me different results:
Version 1:
static double RoundPrecision(double& val)
{
val = floor(val * 1000 + 0.5) * 0.001;
return val;
}
Version 2:
static double RoundPrecision(double& val)
{
val = floor(val * 1000 + 0.5) / 1000;
return val;
}
Example output when rounding the number 300.9:
Version 1: 300.90000000000003
Version 2: 300.89999999999998
Both versions sometimes give the same result, but for specific inputs the results differ. I have to have consistent behavior when equating numbers to other variables in the program.
EDIT:
I am aware of the problems with floating point precision, which is exactly what I'm trying to avoid here by rounding. I need a consistent way to round to 3 decimal point precision.

Computers are limited in their precision. You either accept the available precision in double or float, or you seek other libraries that give you sufficient precision, but with worse performance. Realistically, you cannot achieve exact real-numbers on computers, and you won't even need it. double gives you 10^-16 relative precision, then try long double. If that isn't enough, then seek external libraries that would do that for you. Here's an example of an arbitrary precision library.
From the comments I see that you need 3 decimal places precision. If you read this number up to 3 decimal points, then both results are the same. I think the reasons you're confused is that you don't know how to compare floats. Here's how you do it.

Related

How do I solve this for loop in C++? [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
How dangerous is it to compare floating point values?
(12 answers)
Closed 7 years ago.
for(float i=1; i<=1.5; i+=0.1)
{
// statements
}
The above C++ for loop runs for 5 times. Shouldn't this run for 6 times?
This is a great example of a floating point precision error. Precise values like multiples of 0.1, 0.2 cannot be precisely represented internally in the computer's memory. You'll want to do a comparison using EPSILON (http://en.cppreference.com/w/cpp/types/numeric_limits/epsilon)
Something like
for (float i = 1; fabs(1.5 - i) < EPSILON; i+=0.1) {
//statements
}
It is because multiples of 0.1 cannot be presented precisely in binary, and the actual value stored is an approximation that may be slightly less than 0.1. So, 5*0.1 might be less than 0.5 or it might be more (depending on how the floating point values are represented).
It is usually a really bad idea to use a floating point variable (and tests involving equality or inequality of floating point values) to control loops at all. Effects can include running more (or less) times that intended, or - in some bad cases - an infinite loop where a finite number of runs was expected.
In your case, you would be better off doing something like
for (int i = 0; i < 5; ++i)
{
float value = 1.0 * i*0.1;
// use value here rather than the i in your original code
}
Alternatively, you can use some test that allows for the imprecision of floating point (e.g. compare i - 1.5 with some value such as machine epsilon). The catch with this is that the actual number of iterations still potentially has some level of unpredictability, particularly in loops that involve a large number of iterations (e.g. iterating from 1.0 to 50000.0 in steps of 0.01) because rounding errors can either accumulate or cancel out at different stages during the loop.

Reading string in to float produces incorrect accuracy [duplicate]

This question already has answers here:
Why are floating point numbers inaccurate?
(5 answers)
Closed 8 years ago.
Now I understand floats are less accurate than double, but does this explain when I have the std::string:
"7.6317"
and I do:
float x = atof(myString.c_str());
getting 7.63170004 is expected? Is there any way I can tell the assignment of x to only read the first 4 decimal places? Or is this because of the way the float representation stores the number 7.6317?
Yes. It is expected. It is so-called floating point error.
Some floating point literals do not have an accurate representation in the computer, even if -- in decimal notation -- the number seems harmless. This is because the computer uses 2 as a base. So even if a number might have a finite representation in base 10, it might not have on in base 2.
you can do it like:
float x = floorf(val * 10000) / 10000;
i think it should work! see See

Rounding double in C++ [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I apologize for asking yet another rounding question. However, all the search has not yielded a satisfactory solution to my problem. The only possible answer is that what I am looking for may not be possible at all. Just wanted to make sure if the experts think the same.
So, here is my sample code:
double Round(double dbVal, int nPlaces)
{
const double dbShift = pow(10.0, nPlaces);
return floor(dbVal * dbShift + 0.5) / dbShift;
}
main()
{
string sNum = "1.29585";
double dNum = stod(sNum);
int iNumDecimals = 5;
double dRoundedNum = Round(dNum, iNumDecimals);
}
The number sNum is read as a string from a file. For example, the number in the file is 1.29585. I convert it to double using stod. dNum comes out to be 1.295849999999.... I would like to get back 1.29585 in double. Using a Round function as shown above does not help. The round function also returns 1.295849999999....
Is it possible to get back the exact 1.29585 at all? Any other possible solution?
Thanks in advance for any advice.
Your number is rounded to the closest representable double to the number you provided ( 1.29585 ). To 17 places, it is: 1.29584999999999995
The next largest representable double-precision number is 1 / 252 larger than that: 1.29585000000000017.
That's roughly 1 part in 5 quadrillion. An error of that magnitude, scaled to the circumference of the entire solar system, would only be about 8 centimeters.
So, in terms of rounding, the double you have is correctly rounded to the nearest representable binary value.
By default, floating point numbers are stored in binary. Just as you can't express 1/3 as an exact decimal fraction (you can approximate it with "0.33333333", extending out the 3s until you get sick of it), you can't express all round decimal values exactly in binary.
If you're curious what the above two values look like in binary: (You can refer to the diagram and description here to understand how to interpret that hexadecimal value if you are interested.)
1.29584999999999995 == 0x3FF4BBCD35A85879
1.29585000000000017 == 0x3FF4BBCD35A8587A
For your zillions of calculations, this approximate representation should cause no problem, unless you're computing a series of values that need to be rounded to an exact number of decimal places. Typically, that's only necessary if you're computing actual bank transactions or the like. Bankers want decimal rounding, so that their computations today match the way computations were done 100 years ago so that they have continuity between the pre- and post-computer eras, not because they're magically more accurate.
Double precision arithmetic carries 16 to 17 decimal positions of precision. The fact that it doesn't print as a nice round number of decimal digits doesn't mean it's inaccurate. If you compare the calculation the computer makes with double precision to the same calculation you'd do by hand (even with the aid of a standard calculator displaying 9 to 12 digits of precision), the computer's double precision arithmetic will generally come out ahead.
What you most likely want to do is to make sure to print out your final calculations to the appropriate number of decimal places. For example, you can use std::setprecision() from <iomanip> to control the precision of values printed via std::cout.
EDIT: If your application actually requires decimal arithmetic and decimal rounding, then you will need to look into decimal floating point support, either built into the compiler or in a 3rd party library. Some recent compilers do have support for this, and some processors even have hardware support for decimal floating point. GCC has decimal floating point extensions, for example, as does Intel's compiler. In contrast, Microsoft suggests finding a BCD library, it seems.
Try this way, i don´t remember the format for double right now, i use float.
float num;
sscanf("1.29585", "%f", &num);
std::cout << num << std::endl;
The "I whipped it up in Haskell and translated it" answer:
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main()
{
double d = 1.2958499999999;
cout << setprecision(15) << d << endl;
cout << setprecision(15) << double(round(d * 1e5) / 1e5) << endl;
return 0;
}
// outputs:
// 1.2958499999999
// 1.29585
It is hardly a general answer, but it is correct to the letter of the question. I highly recommend understanding the evil that is IEEE floating point using e.g. Jim Buck's reference rather than putting this hack to any great use.

Increasing float value [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Floating point inaccuracy examples
I have the following line inside a WHILE loop, in C/C++:
while(...)
{
x = x + float(0.1); // x is a float type. Is the cast necessary?
}
x starts as 0. The thing is, after my first loop, x = 0.1. That's cool. After my second loop, x = 0.2. That's sweet. But, after my third loop, x = 0.3000001. That's not OK. I want it to have 0.3 as value, not 0.3000001. Can it be done? Am I looping wrongly?
Floating point does not work that way there are infinitely many real numbers between any two real numbers and only a finite amount of bits this means that in almost all cases the floating point representation is approximate. Read this link for more info.
It's not the loop, it's just how floats are represented in memory. You don't expect all real numbers to be directly representible in a limited number of bytes, right?
A 0.3 can't be exactly represented by a float. Try a double (not saying it will work, it probably won't, but the offset will be lower).
This is a common misconception with floating point numbers. 0.3 may not be exactly representable with 32bit or 64bit binary floating point. Lots of numbers are not exactly representable. Your loop is working fine ignoring the unnecessary syntax.
while (...)
{
x += 0.1f; /* this will do just fine in C++ and C */
}
If this doesn't make sense consider the fact that there are an infinite number of floating point numbers...with only a finite number of bits to describe them.
Either way, if you need exact results you need to use a decimal type of the proper precision. Good news though, unless you're doing calculations on money you likely do not need exact results (even if you think you do).
Code such as this:
for (int i = 0;… ; ++i)
{
float x = i / 10.f;
…
}
will result in the value of x in each iteration being the float value that is closest to i/10. It will usually not be exact, since the exact value of i/10 is usually not representable in float.
For double, change the definition to:
double x = i / 10.;
This will result in a finer x, so it will usually be even closer to i/10. However, it will still usually not be exactly i/10.
If you need exactly i/10, you should explain your requirements further.
NO the cast is not necessary in this case
float x;
x = x + float(0.1);
You can simply write
x+= 0.1

Rounding a double number up to the tenths place [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
round() for float in C++
Ok suppose I had the number 8.47434. I want to round it up to 8.5 and to 1 decimal place. How would I go about doing this in C++
Multiply by 10, round and divide by 10 again.
Example:
round(10 * 8.47434f) / 10;
Edit:
OK, I just found out that round() is not always present in math.h.
The above works in gcc and icl (with Microsoft's libraries), but not in tcc.
floor(), however, is part of the standard libraries. So to round, we can add 0.5 and use floor().
Example:
floor(10 * 8.47434f + 0.5f) / 10;
std::floor(d)+std::floor((d-std::floor(d))*10.0+0.5)/10.0
Doing it this way won't lose precision, as opposed to the other answers which multiply the original double by 10. (d would be your number by the way)
Be forewarned though: floating point numbers can't represent anything. With doubles: 1.35 will round to 1.3999999999999999; 123.34 will be represented as 123.34999999999999 in the first place causing it to round down to 123.3 instead of the intended 123.4; etc
You could multiple by 10 add 0.5 cast to an int and divide by ten.
if the number is negative subtract 0.5 or multiply and divide by negative ten.