Reputation: 47
Running on a x64 architecture , Visual Studio 2013 Windows 8.1
I am trying to run a loop which uses a float as its loop variable , the issue is during the increment operation the decimal values are being lost .
Eg :
float incrementValue = 360 / 14;
for (float i = 0; i <= 360; i = i + incrementValue)
{
cout << endl << " I " << i;
}
I need the value of i >= 360 . But it stops at 350 . Since 360/14 =25.7142857 but looks like the increments are in steps of 25 . If i do the same thing with any whole number it works fine , this issue is only with any number of the form xx.yyyy
I tried looking up various sites on this issue but i was unable to find anything that helps me / answers my questions .
Upvotes: 0
Views: 8703
Reputation: 125
When I really want a float in my loop, I change the upper limit to make sure that I have no errors from continual floating point errors.
float x_min = 0.;
float x_max = 360.;
int N_steps = 14;
float x_step = (x_max - x_min) / N_steps;
for (float x = x_min; x <= x_max + x_step / 2; x += x_step)
{
// do stuff
}
While this ensures that I get each step correct, the problems with precision can build up if there are a large number of steps. In that case using an integer loop variable and calculating the corresponding float each time. Then I only the floating point error one time as opposed to 14 (or a million) times summed up.
Upvotes: 0
Reputation: 71070
It would be hard to get 'i = 360' since 'i = 360.0000001' would fail the test and getting exactly '360' would be tricky. Floating point on computers is hard and full of little gotchas.
It would be better to use integers as much as possible:-
int num_steps = 14;
for (int i = 0 ; i <= num_steps ; ++i)
{
float value = 360.0f * i / num_steps;
// use value
}
Using '<=' in the loop does mean you get a '360' for 'value' because 'i / num_steps' is one. Having said that, you might not get exactly '360.0f' due to floating point errors.
Upvotes: 2
Reputation: 1974
If you know the number of iterations, it is not a good idea to use a float to control a loop, because floats are not exact.
In fact, using a float to control any loop is a bad idea, without use of tolerances (which will depend on machien precision) to allow for potential rounding errors.
In this case, you know the number of iterations, so a loop like this would do the trick.
int num_steps = 14
float factor = 360.0/num_steps;
for (int i = 0; i < num_steps; ++i)
{
std::cout << "\nI" << (i*factor);
}
Upvotes: 0
Reputation: 881423
You have three problems here (two related), all of which are probably contributing.
The first is that floating point comparisons are generally unwise since, while you may think you have 360
, it may in fact be 359.999999942
.
The second is that inaccuracies build up over time. Every time you add a number like 0.99
that you think is 1
, the error accumulates.
With the values you're using, these errors are likely to stay small but you should be aware of them anyway. If you start processing lots of numbers, you'll find out about the problems pretty quickly.
The final, and unrelated, problem is that 360 / 14
is integer division, and it will give you an integer result, 25
instead of 25.714285714
.
You can fix that final problem by ensuring one of the values is a float:
float incrementValue = float(360) / 14;
But that's not going to fix the first two, which will bite you at some point.
To fix that, you would be better off sticking with integers (for this simple case anyway) and converting to floating point at the latest possible instance:
#include<iostream>
int main (void) {
int incrementValue = 360;
for (int i = 0; i <= 360 * 14; i = i + incrementValue)
std::cout << " I " << float(i) / 14 << '\n';
return 0;
}
which gives you:
I 0
I 25.7143
I 51.4286
I 77.1429
I 102.857
I 128.571
I 154.286
I 180
I 205.714
I 231.429
I 257.143
I 282.857
I 308.571
I 334.286
I 360
Upvotes: 5
Reputation: 1863
float incrementValue = (float)360 / 14;
for (float i = 0; i <= 360; i = i + incrementValue)
{
cout << endl << " I " << i;
}
Upvotes: 0
Reputation: 4763
Make the operands from the division float type :
float incrementValue = 360.f / 14.f;
Upvotes: 1