【问题标题】:printing the double number wrongly错误地打印双数
【发布时间】:2021-03-09 14:47:00
【问题描述】:

我想编写这样的代码,如果我输入像 612.216 这样的十进制数,我可以将其打印为 612216(实际上将其转换为整数)。但是,该程序将我的号码更改为 2162160000000000000000001 之类的东西,我不知道该怎么办。

这是我的代码:

#include <stdio.h>
#include <math.h>
int main() {

long double x;
scanf_s("%Lf", &x);
while (floor(x)!=x)
    x = x * 10;

printf("%Lf", x);

return 0;}

【问题讨论】:

    标签: c integer double


    【解决方案1】:

    这个怎么样:

    #include <stdio.h>
    int main() {
        double number =  612.216; 
        char number_as_string[20];
        snprintf(number_as_string,"%lf", number);
        for(int i = 0; number_as_string[i] != '\0'; i++)
            if(number_as_string[i] != '.')
            printf("%c", number_as_string[i]);
        return 0; 
    }
    

    缺点是静态分配的数组。您可以使用 snprintf 将double 转换为array of chars

    【讨论】:

    • 由于浮点固有的错误,这可能会产生最准确的int 转换。 @mhmdrzmirdamadi - 您应该在您的帖子中包含诸如 no arrays 之类的信息,而不是在评论中,这样其他人就不会看到它。
    【解决方案2】:

    浮点表示不准确,因此任何浮点数都存在非常小的错误。你可以试试这个伪代码,

    while ((x - floor(x) > 0.0000000000000000001) x *= 10;

    您的数学库可能会定义一个更好的数字来使用,例如 FLT_MIN 或类似的;)

    【讨论】:

      【解决方案3】:

      floor(x)!=x 检查的问题在于它没有考虑输入 long double 数字表示中的任何不准确性。 (在给出的示例中,这会导致将“额外”0.0000000000000000000001 添加到实际值中。)请参阅Is floating point math broken?,了解有关浮点数表示中固有的此类不准确性的更多信息。

      要在您的代码中解决此问题,您可以将 floor(x)x 之间的差异与给定的“容差”进行比较 - 如果小于这个值,则认为循环已完成。您可以使用从LDBL_EPSILON 常量派生的值作为该“容差”的典型值,尽管您可能想尝试不同的值。

      这是一个可能的代码解决方案:

      #include <stdio.h>
      #include <math.h>
      #include <float.h> // For the LDBL_EPSILON definition
      
      int main()
      {
          long double x;
          scanf_s("%Lf", &x);
          while ((x - floor(x)) > (LDBL_EPSILON * x * 10)) // Try changing the "10" value!
              x = x * 10;
      
          printf("%.0Lf", x); // Add the ".0" to remove the trailing ".000000" in the output
      
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        long double 可以准确地存储许多有限值。有所有的形式:

        +/- some_integer * 2some_exponent

        由于“612.216”不能像那样表示(0.216 不能像 0.25 那样表示为二进制分数),因此使用了附近的 long double 值,例如 ~612.2160000000000000253...

        此外,OP 对x = x * 10; 的重复使用会增加小的舍入误差,并且不会构成合理的转换限制。


        另一种方法是使用LDBL_DIG(从十进制文本到long double 到十进制文本的有效十进制位数不变)并将double 打印到缓冲区。让*printf() 完成将double 转换为最佳十进制文本的繁重工作。

        #include <float.h>
        #include <stdio.h>
        
        // To print up to the LDBL_DIG most significant digits w/o trailing zeros:
        void print_sig_digits(long double x) {
          //       -   d   .    ddd....ddd    e   -  expo \0
          char buf[1 + 1 + 1 + (LDBL_DIG-1) + 1 + 1 + 8   +1];
          #define e_OFFSET (1 + 1 + 1 + (LDBL_DIG-1))
        
          // Print using exponential format    
          snprintf(buf, sizeof buf, "%+.*Le", LDBL_DIG, x);
          buf[e_OFFSET] = '\0';  // End string at 'e'
          for (int i = e_OFFSET - 1; buf[i] == '0'; i--) {
            buf[i] = '\0';  // Lop off trailing '0'
          }
          buf[2] = buf[1]; // Copy first digit over '.'
          printf("%s\n", &buf[2]);
        }
        
        int main(void) {
          printf("LDBL_DIG: %d\n", LDBL_DIG);
          print_sig_digits( 612.216L);
          print_sig_digits( 1.0L/7);
          print_sig_digits( 0.000123L);
          return 0;
        }
        

        输出

        LDBL_DIG: 18
        612216
        142857142857142857
        123
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-01
          • 1970-01-01
          相关资源
          最近更新 更多