为什么有些数字用小数位打印?

时间:2018-09-15 18:02:26

标签: c for-loop floating-point formatting

我正在尝试解决一个问题:

  

您必须使用C语言编写一个程序,该程序显示如下所示的序列:

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=?

我尝试使用“ for”结构解决此问题,但在程序输出中,最后三个整数出现时带有小数位,并且问题要求整数出现时不带小数位:

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

为什么会发生?这是我的代码:

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;
}

4 个答案:

答案 0 :(得分:2)

浮点数并不总是精确的,您可能需要执行以下操作:

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
   ...

通常的做法是不比较浮点数/双精度数的准确性,而是在取决于特定应用的一些小差异(ε)之内。

以以下C#代码为例:

float f = 1;

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

这是输出;您可以将序列存储在浮点数中时不完全精确:

1
1.20000005
1.4000001
1.60000014
1.80000019
2.00000024
2.20000029
2.40000033
2.60000038
2.80000043

答案 1 :(得分:1)

  

为什么有些数字用小数位打印?

因为所采用的算法假定使用精确的十进制浮点数学,但使用了通用的二进制浮点double

计算接近OP目标的值。


尝试使用二进制编码的浮点数进行十进制数学运算导致的限制问题。

由于代码需要使用I = [0, 0.2, 0.4, ... 2]进行11次迭代,因此请使用整数计数器进行循环,并从中构造I

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

只有此更改,输出为

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

要洞悉出了什么问题,可以更精确地查看FP值。例如:

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;
  }
}

输出

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)

答案 2 :(得分:0)

因为浮点数在迭代过程中会累积一些不精确性。我已经完成了代码的调试,并且在值FI = 1的迭代中,确切的值是8个尾随零。但是在FI = 2的迭代中,精确值有一些错误,因此不会进入IF条件。 Debug of code provided

答案 3 :(得分:0)

使用%g。如this post

如果(FI == 0)     printf(“ I =%g J =%g \ n”,I,J); //使用%g