计算浮点数中“。”后面的位数?

时间:2013-07-24 14:55:21

标签: c floating-point

这是一个面试问题。 如何计算浮点数.之后的数字位数。

e.g。如果给出3.554输出= 3

表示43.000输出= 0。 我的代码段在这里

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

float类型无法指示某些数字。例如,73.487类型中没有float,c中float指示的数字是73.486999999999995近似值。

现在如何在无限循环中解决它。

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

8 个答案:

答案 0 :(得分:5)

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

int digits_after_decimal_point(double x)
{
    int i;
    for (i=0; x!=rint(x); x+=x, i++);
    return i;
}

答案 1 :(得分:3)

问题并不像所述那样可以解决,因为浮点通常用二进制表示,而不是十进制。如你所说,许多(实际上大多数)十进制数在浮点数中并不完全可以表示。

另一方面,在二进制浮点中可以精确表示的所有数字都是具有有限位数的小数 - 但是如果你想要{的结果为2那么这并不是特别有用{1}}。

当我运行您的代码段时,它表示3.44在小数点后有2位数 - 因为3.44恰好恰好产生3.44 * 10.0 * 10.0。这可能不会发生在另一个数字上,例如344.0(我还没试过)。

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

对于大数字,重复乘以10将不可避免地给你一个浮点溢出。有办法避免这种情况,但它们无法解决其他问题。

如果将值int存储在3.44对象中,则存储的实际值(至少在我的系统上)正好是double,其小数部分中包含51位小数。假设您确实想要来计算3.439999999999999946709294817992486059665679931640625中点之后的小数位数。由于3.4399999999999999467092948179924860596656799316406253.44实际上是相同的数字,因此任何C函数都无法区分它们并知道它是应该返回2还是51(如果你是意思是3.439999999999999946709294817992486059665679931640625,或......)。

您可能检测到存储的值与3.43999999999999994670929481799248605966567993164062“足够接近”,但这使得它成为一个更复杂的问题 - 并且它失去了确定小数部分中小数位数的能力3.44

只有当您给出的数字以某种实际上可以表示小数部分(例如字符串)的格式存储时,或者如果您添加一些复杂的要求来确定给定二进制近似值的小数部分时,问题才有意义意为代表。

通过查找给定浮点类型中最接近的近似值的给定二进制浮点数,可能有一种合理的方法来执行后者。

答案 2 :(得分:3)

问题可以解释为:

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

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

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

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

另请参阅Compute the double value nearest preferred decimal result对Smalltalk实现的引用。

答案 3 :(得分:2)

听起来你需要使用sprintf来获得实际的圆形版本,或者输入是一个字符串(而不是解析为float)。

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

答案 4 :(得分:1)

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

  1. 将输入作为字符串 char str [10] =“ 245.98”;
  2. 将字符串转换为int,用于计算小数点前的位数。 int atoi(con​​st char * string)
  3. 在while内使用逻辑n / 10计数数字。
  4. 十进制逻辑后的数字
    • 使用strlen(n)获取字符串的长度
    • 在while中(a [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   

                 

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:-1)

你可以做的是将数字乘以10的各种幂,将其舍入到最接近的整数,然后除以相同的10次幂。当最终结果与原始数字不同时,你&#39已经过了一个数字。

我很久没读过了,所以我不知道它与这个想法有什么关系,但是如何从PLDI 1990和{{3准确打印浮点数可能与基本问题非常相关。

答案 7 :(得分:-1)

请求,例如如果给出3.554输出= 3,则43.000输出= 0

问题:这已经是0.33345的小数。当它转换为double时,它可能类似于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