1

I recently created this simple program to find average velocity.

Average velocity = Δx / Δt

I chose x as a function of t as x = t^2

Therefore v = 2t

also, avg v = (x2 - x1) / (t2 - t1)

I chose the interval to be t = 1s to 4s. Implies x goes from 1 to 16

Therefore avg v = (16 - 1) / (4 - 1) = 5

Now the program :

#include <iostream>

using namespace std;
int main() {
    float t = 1, v = 0, sum = 0, n = 0;  // t = time, v = velocity, sum = Sigma v, n = Sigma 1
    float avgv = 0;

    while( t <= 4 ) {
        v = 2*t;
        sum += v;
        t += 0.0001;
        n++;
    }
    avgv = sum/n;
    cout << "\n---->  " << avgv << "  <----\n";
    return 0;
}

I used very small increments of time to calculate velocity at many moments. Now, if the increment of t is 0.001, The avg v calculated is 4.99998.
Now if i put increment of t as 0.0001, The avg v becomes 5.00007!

Further decreasing increment to 0.00001 yields avg v = 5.00001

Why is that so?

Thank you.

Max Payne
  • 2,423
  • 17
  • 32
  • See http://stackoverflow.com/questions/588004/is-floating-point-math-broken to understand why floating point math cannot be expected to produce exact results. – R Sahu Jul 03 '15 at 13:58
  • Change from float to double and see the average is precisely 5. The problem here is that float lacks the precision. See http://stackoverflow.com/questions/2100490/floating-point-inaccuracy-examples. – Robinson Jul 03 '15 at 13:58
  • Computers work in binary, not decimal. Round-off error and error propagation is a topic you should (at the least) be aware of when using floating point. Here is your code using a loop that will run the requisite number of times: http://ideone.com/KTzKaP Note the final value after looping the required number of times. This is the error propagation that occurs when adding `0.0001` to a float 30,0001 times. Since `0.0001` cannot be represented exactly in binary, you get the issue. – PaulMcKenzie Jul 03 '15 at 14:25

1 Answers1

0

In base 2 0.0001 and 0.001 are periodic numbers, so they don't have an exact representation. One of them is being rounded up, the other one is rounded down, so when you sum lots of them you get different values.

This is the same thing that happens in decimal representation, if you choose the numbers to sum accordingly (assume each variable can hold 3 decimal digits). Compare:

a = 1 / 3; // a becomes 0.333
b = a * 6; // b becomes 1.998

with:

a = 2 / 3; // a becomes 0.667
b = a * 3; // b becomes 2.001

both should (theoretically) result into 2 but because of rounding error they give different results

In the decimal system, since 10 is factorised into primes 2 and 5 only fractions whose denominator is divisible only by 2 and 5 can be represented with a finite number of decimal digits (all other fractions are periodic), in base 2 only fractions which have as denominator a power of 2 can be represented exactly. Try using 1.0/512.0 and 1.0/1024.0 as steps in your loop. Also, be careful because if you choose a step that is too small, you may not have enough digits to represent that in the float datatype (i.e., use doubles)

pqnet
  • 6,070
  • 1
  • 30
  • 51
  • Is there any method to improve this loop using only float, ie improve accuracy using only float? Thanx. – Max Payne Jul 04 '15 at 06:43