C / C ++计算小数位数?

假设用户输入的是十进制数,例如。 5. 2155 (有4位小数)。 它可以自由存储(int,double)等。

是否有任何聪明 (或非常简单)的方法来找出这个数字有多少小数? (有点像问题,如何通过屏蔽最后一位来找到一个数字是偶数还是奇数)。

我知道的两种方式,不幸的是不是很聪明,但这更像是对环境的限制而不是我:-)

第一种是将数字sprintf到一个带有"%.50f"格式字符串的大缓冲区,剥去尾随的零,然后计算小数点后的字符。 这将受到printf系列本身的限制。 或者您可以使用该字符串作为用户输入(而不是sprintf一个浮点值),以避免浮点问题。

第二个是减去整数部分然后迭代乘以10并再次减去整数部分直到你得到零。 这受到浮点数的计算机表示限制的限制 – 在每个阶段,您可能会遇到无法准确表示的数字的问题(因此.2155实际上可能是.215499999998)。 类似下面的内容(未经测试,除了在我脑海中,与COMX-35相当):

 count = 0 num = abs(num) num = num - int(num) while num != 0: num = num * 10 count = count + 1 num = num - int(num) 

如果您知道您将获得的数字类型(例如,它们都是小数点后的0到4位数),您可以使用标准浮点“技巧”来正确执行。 例如,而不是:

 while num != 0: 

使用

 while abs(num) >= 0.0000001: 

一旦将数字从用户表示(字符串,OCR-ed gif文件,等等)转换为浮点数,您就不必处理相同的数字。 所以严格的,不是非常有用的答案是“不”。

如果( 情况A )您可以避免从字符串表示转换数字,问题变得更加容易,您只需要计算小数点后面的数字并减去尾随零的数量。

如果你不能这样做( 情况B ),那么你需要假设最大小数位数,将数字转换回字符串表示forms,并使用round-to-even方法将其四舍五入到这个最大数字。 例如,如果用户提供的1.1表示为1.09999999999999(假设),将其转换回字符串产生,猜猜是什么,“1.09999999999999”。 将这个数字四舍五入到比如四个小数点可以得到“1.1000”。 现在回到案例A。

脱离我的头顶:

从小数部分开始:.2155

重复乘以10并丢弃数字的整数部分,直到你得到零。 步数将是小数位数。 例如:

 .2155 * 10 = 2.155 .155 * 10 = 1.55 .55 * 10 = 5.5 .5 * 10 = 5.0 

4步= 4位小数

你是什​​么意思“自由存储(int”?一旦存储在一个int中,它剩下零小数,显然。一个double以二进制forms存储,因此与“decimal”没有明显或简单的关系。为什么不在将输入发送到最终的数字变量目标之前,您将输入保持为字符串,只需要足够长的时间来计算这些小数。

这样的事情也可能有效:

 float i = 5.2154; std::string s; std::string t; std::stringstream out; out << i; s = out.str(); t = s.substr(s.find(".")+1); cout<<"number of decimal places: " << t.length(); 

使用科学记数法格式(以避免舍入错误):

 #include  #include  /* Counting the number of decimals * * 1. Use Scientific Notation format * 2. Convert it to a string * 3. Tokenize it on the exp sign, discard the base part * 4. convert the second token back to number */ int main(){ int counts; char *sign; char str[15]; char *base; char *exp10; float real = 0.00001; sprintf (str, "%E", real); sign= ( strpbrk ( str, "+"))? "+" : "-"; base = strtok (str, sign); exp10 = strtok (NULL, sign); counts=atoi(exp10); printf("[%d]\n", counts); return 0; } 

[5]

战斗后多年,但我已经用三条线做出了自己的解决方案:

 string number = "543.014"; size_t dotFound; stoi(number, &dotFound)); string(number).substr(dotFound).size() 

当然你必须先测试它是否真的是一个浮点数( stof(number) == stoi(number)

我建议将值作为字符串读取,搜索小数点,并将其前后的文本解析为整数。 没有浮点或舍入错误。

 char* fractpart(double f) { int intary={1,2,3,4,5,6,7,8,9,0}; char charary={'1','2','3','4','5','6','7','8','9','0'}; int count=0,x,y; f=f-(int)f; while(f<=1) { f=f*10; for(y=0;y<10;y++) { if((int)f==intary[y]) { chrstr[count]=charary[y]; break; } } f=f-(int)f; if(f<=0.01 || count==4) break; if(f<0) f=-f; count++; } return(chrstr); } 

这是完整的计划

  #include  #include  #include  #include  char charary[10]={'1','2','3','4','5','6','7','8','9','0'}; int intary[10]={1,2,3,4,5,6,7,8,9,0}; char* intpart(double); char* fractpart(double); int main() { clrscr(); int count = 0; double d = 0; char intstr[10], fractstr[10]; cout<<"Enter a number"; cin>>d; strcpy(intstr,intpart(d)); strcpy(fractstr,fractpart(d)); cout<=1) { z=x%10; for(y=0;y<10;y++) { if(z==intary[y]) { chrstr[count1]=charary[y]; break; } } x=x/10; count1++; } for(x=0,y=strlen(chrstr)-1;y>=0;y--,x++) retstr[x]=chrstr[y]; retstr[x]='\0'; return(retstr); } char* fractpart(double f) { int count=0,x,y; f=f-(int)f; while(f<=1) { f=f*10; for(y=0;y<10;y++) { if((int)f==intary[y]) { chrstr[count]=charary[y]; break; } } f=f-(int)f; if(f<=0.01 || count==4) break; if(f<0) f=-f; count++; } return(chrstr); } 

一种方法是以字符串forms读取数字。 找到小数点后子字符串的长度,即该人输入的小数位数。 通过使用将此字符串转换为浮点数

atof(string.c_str());

另一方面; 处理浮点运算以将它们存储在具有有限精度的特殊对象中时,总是一个好主意。 例如,您可以将浮点存储在称为“十进制”的特殊类型的对象中,其中整数部分和数字的小数部分都是整数。 这样你就有了有限的精度。 这样做的缺点是你必须写出算术运算的方法(+, – ,*,/等),但你可以很容易地用C ++覆盖运算符。 我知道这偏离了你原来的问题,但最好以有限的forms存储你的小数。 通过这种方式,您还可以回答您的问题,即该数字的小数位数。