-1

I'm trying to solve a question that says:

You must make a program in C that shows a sequence as in the example below:

I=0 J=1
I=0 J=2
I=0 J=3
I=0.2 J=1.2
I=0.2 J=2.2
I=0.2 J=3.2
.....
I=2 J=?
I=2 J=?
I=2 J=?

I tried to solve this question using the "for" structure, but at the program output, the last three integers appear with decimal places, and the question requires that integers appear without decimal places:

I=0 J=1
I=0 J=2
I=0 J=3
I=0.2 J=1.2
I=0.2 J=2.2
I=0.2 J=3.2
.....
I=1 J=2
I=1 J=3
I=1 J=4
I=1.2 J=2.2
I=1.2 J=3.2
I=1.2 J=4.2
.....
I=2.0 J=3.0
I=2.0 J=4.0
I=2.0 J=5.0

Why does it happen? Here is my code:

int main() {

  int II;
  float I, J, X, FI;
  X = 1;

  for(I = 0; I <= 2.2; I = I + 0.2){

      for(J = X; J <= X + 2; J = J + 1){

          II = (int) I;     //II = The Integer part of I
          FI = I - II;      //FI = The Fractionary part of I

          if(FI == 0)
              printf("I=%.0f J=%.0f\n", I, J);

              //If the fractionary part is 0, then
              //the number must be printed without
              //decimal places.              

          else
              printf("I=%.1f J=%.1f\n", I, J);

              //If the fractionary part is greater than 0,
              //then the number must be printed with just
              //one decimal place.

      }

      X += 0.2;
  }

  return 0;
}
John Kugelman
  • 349,597
  • 67
  • 533
  • 578
enzo
  • 9,861
  • 3
  • 15
  • 38

4 Answers4

1

Floating point numbers aren't always exact, you may need to do something like:

if ((FI > -0.1) || (FI < 0.1))
   printf("I=%.0f J=%.0f\n", I, J);
else
   ...

OR

if (fabs(FI) < 0.1)
   printf("I=%.0f J=%.0f\n", I, J);
else
   ...

It is common practice not to compare floats/doubles for exactness, but within some small difference (epsilon) that depends on the particular application.

As an example from the following C# code:

float f = 1;

for (int i = 0; i < 10; i++)
{
  Console.WriteLine(f.ToString("G9"));
  f += 0.2F;
}

This is the output; you can the series in not exact when stored in a float:

1
1.20000005
1.4000001
1.60000014
1.80000019
2.00000024
2.20000029
2.40000033
2.60000038
2.80000043
Marker
  • 972
  • 6
  • 9
  • Thanks, dude. Your code worked perfectly well. The only change I had to make was `if ((FI > -0.1) && (FI < 0.1))` – enzo Sep 15 '18 at 18:13
  • I would recommend using 0.000001 or similar instead of just 0.1. While this works in this case, you should compare to precision somewhat larger than any part of your code depends on. –  Sep 15 '18 at 18:19
  • @psinaught absolutely correct for general use, but it can sometimes depend on the accuracy needed the particular application. – Marker Sep 15 '18 at 18:27
  • Detail: "Floating point numbers aren't always exact" --> All finite FP numbers are exact. It is the conversions/operations that do not yield the exact result as math would suggest. – chux - Reinstate Monica Sep 15 '18 at 18:46
  • @chux, how do you represent 1.2 exactly in a float (32-bit) or even a double (64-bit) IEEE 754 number? – Marker Sep 15 '18 at 23:25
  • 1
    @Marker: One would represent 1.2 exactly in IEEE 754 formats using one of the several decimal floating-point formats specified in the IEEE 754 standard. One would not represent 1.2 exactly in the binary floating-point formats. chux’ point is correct; it is an error to think of the floating-point **numbers** as inexact. The specification is carefully written, and the **numbers** represented in the format are **exact**. Approximations occur when **operations** are performed. Each number `x` or `y` in a floating-point format represents a mathematical number exactly, but… – Eric Postpischil Sep 16 '18 at 00:08
  • 1
    … the result of an operation, such as `x+y`, `x*y`, `x/y`, or `sqrt(x)`, is defined to be the result of the mathematical operation rounded (according to certain rules) to the nearest representable value. Thus, approximations occur in operations. Understanding this distinction is crucial for performing numerical error analysis, writing proofs, and using floating-point correctly. In particular, the recommendation to use tolerances to compare floating-point numbers is generally bad advice. It is better to understand floating-point arithmetic and to design algorithms that avoid such comparisons. – Eric Postpischil Sep 16 '18 at 00:10
  • @Marker A 64-bit `double` cannot represent all numbers. It can represent about 2^64 different values, _exactly_. With [binary64](https://en.wikipedia.org/wiki/Double-precision_floating-point_format), 1.2 is not one of them. – chux - Reinstate Monica Sep 16 '18 at 00:47
1

Why are some numbers printed with decimal places?

Because the algorithm employed assumes exact decimal floating-point math, yet uses the common binary floating point double.

Instead values near OP's goal were computed.


Limit issues caused by trying got do decimal math with binary coded floating-pint numbers.

Since code need to iterate 11 times, with I = [0, 0.2, 0.4, ... 2], use an integer counter for the loop and construct I from it.

// for (I = 0; I <= 2.2; I = I + 0.2) {
for (int i = 0; i <= 10; i++) {
  I = i/5.0;

With only this change the output is

I=0 J=1
I=0 J=2
I=0 J=3
I=0.2 J=1.2
I=0.2 J=2.2
I=0.2 J=3.2
...
I=0.8 J=1.8
I=0.8 J=2.8
I=0.8 J=3.8
I=1 J=2
I=1 J=3
I=1 J=4
I=1.2 J=2.2
I=1.2 J=3.2
I=1.2 J=4.2
...
I=1.8 J=2.8
I=1.8 J=3.8
I=1.8 J=4.8
I=2 J=3
I=2 J=4
I=2 J=5

To gain insight into what went wrong, it is useful to see the FP values to much greater precision. E. g.:

int main(void) {
  int II;
  float I, J, X, FI;
  X = 1;
  printf("0.2 (%.20f)\n", 0.2);
  printf("2.2 (%.20f)\n", 2.2);
  for(I = 0; I <= 2.2; I = I + 0.2){
      for(J = X; J <= X + 2; J = J + 1){
          II = (int) I;     //II = The Integer part of I
          FI = I - II;      //FI = The Fractionary part of I
          if(FI == 0)
              printf("I=%.0f J=%.0f (%.20f %.20f)\n", I, J, I,J);
          else
              printf("I=%.1f J=%.1f (%.20f %.20f)\n", I, J, I, J);
      }
      X += 0.2;
  }
}

Output

0.2 (0.20000000000000001110)
2.2 (2.20000000000000017764)
I=0 J=1 (0.00000000000000000000 1.00000000000000000000)
I=0 J=2 (0.00000000000000000000 2.00000000000000000000)
I=0 J=3 (0.00000000000000000000 3.00000000000000000000)
I=0.2 J=1.2 (0.20000000298023223877 1.20000004768371582031)
I=0.2 J=2.2 (0.20000000298023223877 2.20000004768371582031)
I=0.2 J=3.2 (0.20000000298023223877 3.20000004768371582031)
I=0.4 J=1.4 (0.40000000596046447754 1.40000009536743164062)
I=0.4 J=2.4 (0.40000000596046447754 2.40000009536743164062)
I=0.4 J=3.4 (0.40000000596046447754 3.40000009536743164062)
I=0.6 J=1.6 (0.60000002384185791016 1.60000014305114746094)
I=0.6 J=2.6 (0.60000002384185791016 2.60000014305114746094)
I=0.6 J=3.6 (0.60000002384185791016 3.60000014305114746094)
I=0.8 J=1.8 (0.80000001192092895508 1.80000019073486328125)
I=0.8 J=2.8 (0.80000001192092895508 2.80000019073486328125)
I=0.8 J=3.8 (0.80000001192092895508 3.80000019073486328125)
I=1 J=2 (1.00000000000000000000 2.00000023841857910156)
I=1 J=3 (1.00000000000000000000 3.00000023841857910156)
I=1 J=4 (1.00000000000000000000 4.00000000000000000000)
I=1.2 J=2.2 (1.20000004768371582031 2.20000028610229492188)
I=1.2 J=3.2 (1.20000004768371582031 3.20000028610229492188)
I=1.2 J=4.2 (1.20000004768371582031 4.20000028610229492188)
I=1.4 J=2.4 (1.40000009536743164062 2.40000033378601074219)
I=1.4 J=3.4 (1.40000009536743164062 3.40000033378601074219)
I=1.4 J=4.4 (1.40000009536743164062 4.40000057220458984375)
I=1.6 J=2.6 (1.60000014305114746094 2.60000038146972656250)
I=1.6 J=3.6 (1.60000014305114746094 3.60000038146972656250)
I=1.6 J=4.6 (1.60000014305114746094 4.60000038146972656250)
I=1.8 J=2.8 (1.80000019073486328125 2.80000042915344238281)
I=1.8 J=3.8 (1.80000019073486328125 3.80000042915344238281)
I=1.8 J=4.8 (1.80000019073486328125 4.80000019073486328125)
I=2.0 J=3.0 (2.00000023841857910156 3.00000047683715820312)
I=2.0 J=4.0 (2.00000023841857910156 4.00000047683715820312)
I=2.0 J=5.0 (2.00000023841857910156 5.00000047683715820312)
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

Because float numbers will accumulate some imprecision during the iterations. I have done the debug of your code and in the iteration of the value FI=1, the exact value was 8 trailing zeroes. But in the iteration of FI=2 the exact value had some error, so it wouldn't enter the IF condition. Debug of code provided

0

Use %g. As seen in this post

if(FI == 0) printf("I=%g J=%g\n", I, J); //using %g

Odot
  • 1
  • 1
  • 1