6

这是一道面试题。你如何计算.浮点数后的位数。

例如,如果给定 3.554 output=3

对于 43.000 输出 = 0。我的代码片段在这里

double no =3.44;
int count =0;
while(no!=((int)no))
{
    count++;
    no=no*10;
}
printf("%d",count);

有些数字不能按float类型表示。比如没有73.487infloat类型,floatc 中表示的数字是73.486999999999995近似的。

现在如何解决它,因为它正在无限循环中。

注意:在 IEEE 754 规范中,32 位浮点数被划分为 24+7+1 位。7 位表示尾数。

4

8 回答 8

6

我怀疑这是您想要的,因为问题是要求通常对浮点数没有意义的东西,但这是答案:

int digits_after_decimal_point(double x)
{
    int i;
    for (i=0; x!=rint(x); x+=x, i++);
    return i;
}
于 2013-07-24T15:03:06.733 回答
5

如前所述,该问题并不能真正解决,因为浮点通常以二进制而不是十进制表示。正如您所说,许多(实际上是大多数)十进制数不能用浮点数精确表示。

另一方面,所有可以用二进制浮点数精确表示的数字都是具有有限位数的小数——但如果你想要 2 的结果,这并不是特别有用3.44

当我运行您的代码片段时,它说3.44小数点后有 2 位数字 - 因为3.44 * 10.0 * 10.0恰好产生了344.0. 3.43对于另一个数字,例如(我没有尝试过),这可能不会发生。

当我尝试使用它时1.0/3.0,它会进入无限循环。添加一些printfs 显示no恰好33333333333333324.0在 17 次迭代之后变为 - 但该数字太大而无法表示为int(至少在我的系统上),并将其转换为int具有未定义的行为。

而对于大数,反复乘以 10 将不可避免地给你一个浮点溢出。有一些方法可以避免这种情况,但它们并不能解决其他问题。

如果将值存储3.44double对象中,则存储的实际值(至少在我的系统上)是精确3.439999999999999946709294817992486059665679931640625的,它的小数部分有 51 个十进制数字。假设您真的计算3.439999999999999946709294817992486059665679931640625. 因为3.443.439999999999999946709294817992486059665679931640625实际上是相同的 number,所以任何 C 函数都无法区分它们并知道它应该返回 2 还是 51 (或者如果你的意思是 50 3.43999999999999994670929481799248605966567993164062,或者......)。

您可能会检测到存储的值“足够接近” 3.44,但这使它成为一个更复杂的问题 - 它失去了确定3.439999999999999946709294817992486059665679931640625.

仅当给定的数字以某种格式存储时才有意义.

可能有一种合理的方法来完成后者,方法是寻找唯一的小数部分,其在给定浮点类型中最接近的近似值是给定的二进制浮点数。

于 2013-07-24T15:22:17.407 回答
3

这个问题可以这样解释:

给定一个浮点数,找到最短的十进制表示,它将被重新解释为具有正确舍入的相同浮点值。

一旦像这样制定,答案是肯定的,我们可以 - 看这个算法:

快速准确地打印浮点数。Robert G. Burger 和 R. Kent Dybvig。ACM SIGPLAN 1996 编程语言设计和实现会议,1996 年 6 月

http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf

另请参阅计算Smalltalk 实现的最接近首选十进制结果的双精度值。

于 2013-07-24T20:29:42.077 回答
2

听起来您需要使用sprintf来获取实际的舍入版本,或者将输入设为字符串(而不是解析为 a float)。

无论哪种方式,一旦你有了数字的字符串版本,计算小数点后的字符应该是微不足道的。

于 2013-07-24T14:59:46.660 回答
2

我的逻辑是计算位数。数字 = 245.98

  1. 将输入作为字符串 char str[10] = "245.98";
  2. 将字符串转换为 int 用于计算小数点前的位数。int atoi(const char *string)
  3. 在 while 内使用逻辑 n/10 来计算数字。
  4. 十进制逻辑后的数字
    • 使用 strlen(n) 获取字符串的长度
    • 在 while (a[i]! ='.') 内。然后递增 i 稍后您可以添加第 3 步逻辑输出和第 4 步逻辑输出

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char num[100] = "345653.8768";
    int count=0;
    int i=0;
    int len;
    int before_decimal = atoi(num);
    int after_decimal;
    int total_Count;
    printf("Converting string to int : %d\n", before_decimal);
    
    //Lets count the numbers of digits before before_decimal
    while(before_decimal!=0){
        before_decimal = before_decimal/10;
        count++;
    }

    printf("number of digits before decimal are %d\n",count);
    //Lets get the number of digits after decimal
    
    // first get the lenght of the string
    len = strlen(num);
    printf("Total number of digits including '.' are =%d\n",len);
    
    //Now count the number after '.' decimal points
    // Hope you know how to compare the strings
    while(num[i]!='.'){
       i++; 
    }
    // total lenght of number - numberof digits after decimal -1(becuase every string ends with '\0')
    after_decimal= len-i-1;
    printf("Number of digits after decimal points are %d\n",after_decimal);
    
    //Lets add both count Now
    // ie. Number of digits before decmal and after decimal
    
    total_Count = count+ after_decimal;
    
    printf("Total number of digits are :%d\n",total_Count);
    return 0;
}

输出:

Converting string to int : 345653                                                                                                                                                  
number of digits before decimal are 6                                                                                                                                              
Total number of digits including '.' are =11                                                                                                                                       
Number of digits after decimal points are 4                                                                                                                                        
Total number of digits are :10   

                 
于 2020-09-29T08:25:26.433 回答
0

没有通用的精确解。但是您可以将值转换为字符串并且不计算超出类型精度的部分并排除尾随 0s 或 9s。这将适用于更多情况,但它仍然不会为所有人返回正确的答案。

例如,如果输入是来自用户的十进制字符串,则 double 的精度约为 15 位(二进制-十进制-二进制往返为 17 位),因此对于 73.486999999999995,小数点后有 15 - 2 = 13 位(减去 2 int 部分中的数字)。之后小数部分还有很多 9,也要从计数中减去它们。这里有十个 9,这意味着有 13 - 10 = 3 个十进制数字。如果您使用 17 位数字,那么最后一个数字可能只是垃圾,请在计算 9 或 0 之前将其排除。

或者,从第 15 位或第 16开始迭代,直到看到第一个非 0 和非 9 位。计算剩余的数字,在这种情况下你会得到 3。当然,在迭代时,您还必须确保尾随全为 0 或全为 9

于 2014-01-05T02:18:59.320 回答
0

请求:例如,如果给定 3.554 输出 = 3,对于 43.000 输出 = 0

问题:这已经是像 0.33345 这样的小数了。当它转换为 adouble时,它可能类似于 0.333459999...125。目标仅仅是确定 0.33345 是一个较短的小数,它会产生相同的双精度数。解决方案是将其转换为具有正确位数的字符串,从而产生相同的原始值。

int digits(double v){
   int d=0; while(d < 50){
      string t=DoubleToString(v,d); double vt = StrToDouble(t);
      if(MathAbs(v-vt) < 1e-15) break;
      ++d;
   }
   return d;
}

double v=0.33345;    PrintFormat("v=%g, d=%i", v,digits(v));// v=0.33345, d=5
       v=0.01;       PrintFormat("v=%g, d=%i", v,digits(v));// v=0.01, d=2
       v=0.00001;    PrintFormat("v=%g, d=%i", v,digits(v));// v=1e-05, d=5
       v=5*0.00001;  PrintFormat("v=%g, d=%i", v,digits(v));// v=5e-05, d=5
       v=5*.1*.1*.1; PrintFormat("v=%g, d=%i", v,digits(v));// v=0.005, d=3
       v=0.05;       PrintFormat("v=%g, d=%i", v,digits(v));// v=0.05, d=2
       v=0.25;       PrintFormat("v=%g, d=%i", v,digits(v));// v=0.25, d=2
       v=1/3.;       PrintFormat("v=%g, d=%i", v,digits(v));// v=0.333333, d=15
于 2016-12-04T19:29:48.837 回答
-1

您可以做的是将数字乘以 10 的各种幂,将其四舍五入到最接近的整数,然后除以相同的 10 幂。当最终结果与原始数字比较时,您已经走了一位太远。

好久没看了,不知道跟这个想法有什么关系,但是How to Print Floating-Point Numbers Accurately from PLDI 1990 and 2003 Retrospective可能和基本问题很相关。

于 2013-07-24T15:02:46.717 回答