0

The question I am working on asks me to write code that prints each value from -1 to 1 inclusive, incremented by a value of 0.01 to solve the mathematical function f(x) = x^2 + 4 (to 4 decimal places).

example:

f(-1.00) = 5.0000
f(-0.99) = 4.9801
...
f(1.00) = 5.0000

Problem:

I do not get the last line of the code: f(1.00) = 5.0000. My question is how do I modify my program so that it does appear, and can you also explain why it does not appear in the first place, please?

Code:

Below is my code. It is printing out every value of y when x is between 0 and 1, except for f(1.00) = 5.0000...

double numberForQ4 = -1.00; 
double valueOfY = 0; 

for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01 ) { 
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.2f) = %.4f \n", numberForQ4, valueOfY );
}
Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
Sam
  • 1
  • 2
  • Try flushing the output buffer after the `for` loop: `fflush(stdout);` – Robert Harvey Dec 12 '18 at 05:12
  • 3
    Haven't tested, but you might be facing floating precision problem. Simply, change the `<=1.00` to something like `<=1.00+1e-6` – ZisIsNotZis Dec 12 '18 at 05:19
  • 2
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – Lasse V. Karlsen Dec 12 '18 at 07:03
  • Code with monetary values use the number of pennies rather than fractions of a dollar for this kind of weird floating behavior. What if you tried `numberForQ4 = -100; numberForQ4 <= 100; numberForQ4++`, and divide `numberForQ4` by `100.0` for the math? – Sean Monroe Dec 12 '18 at 16:02

6 Answers6

4

Why do not get the last line of my output?

Floating point math has peculiarities since 0.01 is not exactly representable as a double given it encodes as some binary fraction. In OP's case, something just higher or lower than 0.01 and subsequent math makes for just slightly unexpected results.

how do I modify my program

Instead, iterate using an integer.

// for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01 ) { 
for ( int i = -100; i <= 100; i++ ) { 
  numberForQ4 = i/100.0;
  ...

Tip: iteration loops are best coded using integers.


can you also explain why it does not appear in the first place, please?

Try your original code again and use enough precision to see why.

printf( ".01 = %.21f\n", 0.01);
for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01 ) { 
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.21f) = %.21f \n", numberForQ4, valueOfY );
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
3

If you make this little change:

for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01 ) { 
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.20f) = %.4f \n", numberForQ4, valueOfY );
         //       ^ 20 instead of 2
}

You will get output like:

f(-1.00000000000000000000) = 5.0000 
f(-0.98999999999999999112) = 4.9801 
f(-0.97999999999999998224) = 4.9604 
f(-0.96999999999999997335) = 4.9409 
. . .
. . .
f(0.97000000000000141664) = 4.9409 
f(0.98000000000000142553) = 4.9604 
f(0.99000000000000143441) = 4.9801 

As you can see, the rounding error of the double causes the "last" iteration to be skipped. That is: Adding 0.1 to 0.99000000000000143441 will give something greater than 1.0 causing the loop to end.

For a way to solve this, see the answer by @chux: https://stackoverflow.com/a/53736875/4386427

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

The reason that you dont get the last value is about the variable type you are using (double). When you increment your index variable by 0.1 it is not as precise as you expected, You can observe that values with the code below.

    int main()
{
    double numberForQ4 = -1.00; 
    double valueOfY = 0; 

    for ( ; numberForQ4 <= 1.00; numberForQ4 += 0.01) {
    printf("numForQ4 =  %.5f \n", &numberForQ4);
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.2f) = %.4f \n", numberForQ4, valueOfY );
    }

    return 0;
}

As you will notice the last call is made with numberForQ4= 0.98. This is why you are not able to calculate the value with 1.00.

When you update your code line where you initilize variables to as shown below, you will get the correct output as I did in the online compiler. 



int main()
{
    float numberForQ4 = 1.00; 
    double valueOfY = 0; 

    for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.0100 ) {
    printf("numForQ4 =  %.5f\n", &numberForQ4);
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.2f) = %.4f \n", numberForQ4, valueOfY );
    }

    return 0;
}
Hasan
  • 1,243
  • 12
  • 27
0
double numberForQ4 = 1.00; 
double valueOfY = 0; 

for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01 ) { 
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.2f) = %.4f \n", numberForQ4, valueOfY );
}

Im guessing you meant to put -1.00 or 0 in the assignment of numberForQ4

sjdm
  • 591
  • 4
  • 10
  • 1
    That doesn't really explain the problem he's having, though. In fact, the initial value of `numberForQ4` doesn't matter anyway, because it will get set to a new intial value (-1.00) in the first iteration of the `for` loop. – Robert Harvey Dec 12 '18 at 05:13
  • Well it will matter otherwise it will only loop once and print out (5.000) – sjdm Dec 12 '18 at 05:16
  • Thank you for both of your help! I edited my code and changed the initial value of numberForQ4 to -1.00. Now, my code prints all the way up to f(0.99) but not f(1.00) = 5. Do you know how to go about printing f(1.00) = 5? – Sam Dec 12 '18 at 05:20
  • change the condition to for ( numberForQ4 = -1.00; numberForQ4 < 1.01; numberForQ4 += 0.01 ) – sjdm Dec 12 '18 at 05:26
  • as to why that works, but <= doesnt I am actually not sure at this stage. odd – sjdm Dec 12 '18 at 05:26
  • 2
    @sjdm `<= 1.00` doesn't work because the closest `double` value to 0.01 is 0.01000000000000000020816681711721685132943093776702880859375. So you won't actually reach 1.00 exactly, but rather a number that's slightly larger. – user3386109 Dec 12 '18 at 05:48
0

change to:

double numberForQ4; 
double valueOfY = 0; 
int i=0;


for ( numberForQ4 = -1.00; i <= 200; numberForQ4 += 0.01 , i++ ) { 
    valueOfY = numberForQ4 * numberForQ4 + 4; 
    printf( "f(%.2f) = %.4f \n", numberForQ4, valueOfY );
}

you old loop start from 1.00 and ends on 1.00, so it will do only one iteration. the condetion for the loop to stop is !(numberForQ4 <= 1.00), and if you start from 1.00, in the next iteration numberForQ4 will be equal 1.01 (numberForQ4 > 1.00)

you counter is not precise enough, best solution as mentioned in comments is to use integer counter.

Atheel Massalha
  • 424
  • 1
  • 6
  • 18
  • Thanks for your help! However, I still am unable to print f(1.00) = 5.0000 with your code. Do you know how to fix this? – Sam Dec 12 '18 at 05:29
  • even with float? it works for me: https://www.onlinegdb.com/online_c++_compiler what compiler are you using? – Atheel Massalha Dec 12 '18 at 05:40
  • you should use float not double. – Atheel Massalha Dec 12 '18 at 05:41
  • Why would you want to use float instead of double? That makes no sense. Trying to solve floating point rounding errors by *decreasing* the precision makes no sense at all. Bad answer. – Tom Karzes Dec 12 '18 at 05:52
  • decreasing the precision will remove erros in his case, if he is not interesting in double why to use it? he only want %.2 , float will add unwanted errors – Atheel Massalha Dec 12 '18 at 05:54
  • 1
    That's ridiculous. You're saying you want to rely on a *specific* floating point implementation whose errors result in the value coming out right (or too low) at the end. No one should ever do that. The right solution is to add a margin of error to termination value, as ZizizNotZis suggested. – Tom Karzes Dec 12 '18 at 06:01
  • 1
    Actually, the best way is to use an integer counter, then multiply and add on each iteration to get the desired floating point value. That way it avoids accumulating errors on each iteration. It's a little slower, but much more accurate. – Tom Karzes Dec 12 '18 at 06:14
  • I agree with the integer counter – Atheel Massalha Dec 12 '18 at 06:24
0

increment is 0.01 but it may not adding exactly 0.01 to numberForQ4 due to the way floating/double precision works( since 0.01 can't be sure it is float or double here since double is just more precisioin of float).

append f at end of the value like below, would help

numberForQ4 += 0.01f

for ( numberForQ4 = -1.00; numberForQ4 <= 1.00; numberForQ4 += 0.01f ) {

following is good read about these rounding of errors http://www.cs.yale.edu/homes/aspnes/pinewiki/C(2f)FloatingPoint.html

ShivYaragatti
  • 398
  • 2
  • 8