C/C++ 计算小数位数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1083304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C/C++ counting the number of decimals?
提问by Milan
Lets say that input from the user is a decimal number, ex. 5.2155(having 4 decimal digits). It can be stored freely (int,double) etc.
假设来自用户的输入是一个十进制数,例如。5. 2155(有 4 位十进制数字)。它可以自由存储(int,double)等。
Is there any clever(or very simple) way to find out how many decimals the number has? (kinda like the question how do you find that a number is even or odd by masking last bit).
有没有什么聪明(或非常简单)的方法来找出这个数字有多少个小数?(有点像你如何通过屏蔽最后一位来发现一个数字是偶数还是奇数的问题)。
回答by paxdiablo
Two ways I know of, neither very clever unfortunately but this is more a limitation of the environment rather than me :-)
我知道的两种方式,不幸的是都不是很聪明,但这更多是环境的限制而不是我:-)
The first is to sprintf
the number to a big buffer with a "%.50f"
format string, strip off the trailing zeros then count the characters after the decimal point. This will be limited by the printf
family itself. Or you could use the string as input by the user (rather than sprintf
ing a floating point value), so as to avoid floating point problems altogether.
第一种是sprintf
将数字放入带有"%.50f"
格式字符串的大缓冲区,去掉尾随的零,然后计算小数点后的字符数。这将受到printf
家庭本身的限制。或者您可以使用字符串作为用户的输入(而不是sprintf
输入浮点值),从而完全避免浮点问题。
The second is to subtract the integer portion then iteratively multiply by 10 and again subtract the integer portion until you get zero. This is limited by the limits of computer representation of floating point numbers - at each stage you may get the problem of a number that cannot be represented exactly (so .2155 may actually be .215499999998). Something like the following (untested, except in my head, which is about on par with a COMX-35):
第二种是减去整数部分,然后迭代地乘以 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)
If you know the sort of numbers you'll get (e.g., they'll all be 0 to 4 digits after the decimal point), you can use standard floating point "tricks" to do it properly. For example, instead of:
如果您知道将得到的数字类型(例如,它们都是小数点后的 0 到 4 位数字),您可以使用标准的浮点“技巧”来正确地完成它。例如,而不是:
while num != 0:
use
用
while abs(num) >= 0.0000001:
回答by quant_dev
Once the number is converted from the user representation (string, OCR-ed gif file, whatever) into a floating point number, you are not dealing with the same number necessarily. So the strict, not very useful answer is "No".
一旦数字从用户表示(字符串、OCR 格式的 gif 文件等)转换为浮点数,您就不必处理相同的数字。所以严格的,不是很有用的答案是“不”。
If (case A) you can avoid converting the number from the string representation, the problem becomes much easier, you only need to count the digits after the decimal point and subtract the number of trailing zeros.
如果(情况 A)您可以避免从字符串表示中转换数字,则问题变得容易得多,您只需要计算小数点后的数字并减去尾随零的数量。
If you cannot do it (case B), then you need to make an assumption about the maximum number of decimals, convert the number back into string representation and round it to this maximum number using the round-to-even method. For example, if the user supplies 1.1 which gets represented as 1.09999999999999 (hypothetically), converting it back to string yields, guess what, "1.09999999999999". Rounding this number to, say, four decimal points gives you "1.1000". Now it's back to case A.
如果您做不到(情况 B),那么您需要假设最大小数位数,将数字转换回字符串表示形式,并使用舍入到偶数方法将其舍入到此最大数字。例如,如果用户提供 1.1 表示为 1.09999999999999(假设),将其转换回字符串产量,猜猜是什么,“1.09999999999999”。将此数字四舍五入到小数点后四个小数点,您将得到“1.1000”。现在回到案例 A。
回答by Ferruccio
Off the top of my head:
在我的头顶:
start with the fractional portion: .2155
从小数部分开始:.2155
repeatedly multiply by 10 and throw away the integer portion of the number until you get zero. The number of steps will be the number of decimals. e.g:
重复乘以 10 并丢弃数字的整数部分,直到得到零。步数将是小数位数。例如:
.2155 * 10 = 2.155
.155 * 10 = 1.55
.55 * 10 = 5.5
.5 * 10 = 5.0
4 steps = 4 decimal digits
4 步 = 4 位十进制数字
回答by Gabriel
Since the goal is to be fast, this is a improvement on andrei alexandrescu's improvement. His version was already faster than the naive way (dividing by 10 at every digit). The version below is constant time and faster at least on x86-64 and ARM for all sizes, but occupies twice as much binary code, so it is not as cache-friendly.
由于目标是快速,这是对andrei alexandrescu的改进的改进。他的版本已经比朴素的方式更快(每个数字除以 10)。下面的版本是恒定时间并且至少在所有大小的 x86-64 和 ARM 上都更快,但占用两倍的二进制代码,因此它不是缓存友好的。
Benchmarks for this version vs alexandrescu's version on my PR on facebook folly.
这个版本与 alexandrescu 版本的基准测试在我的facebook folly上的公关上。
Works on unsigned
, not signed
.
适用于unsigned
,而不是signed
。
inline uint32_t digits10(uint64_t v) {
return 1
+ (std::uint32_t)(v>=10)
+ (std::uint32_t)(v>=100)
+ (std::uint32_t)(v>=1000)
+ (std::uint32_t)(v>=10000)
+ (std::uint32_t)(v>=100000)
+ (std::uint32_t)(v>=1000000)
+ (std::uint32_t)(v>=10000000)
+ (std::uint32_t)(v>=100000000)
+ (std::uint32_t)(v>=1000000000)
+ (std::uint32_t)(v>=10000000000ull)
+ (std::uint32_t)(v>=100000000000ull)
+ (std::uint32_t)(v>=1000000000000ull)
+ (std::uint32_t)(v>=10000000000000ull)
+ (std::uint32_t)(v>=100000000000000ull)
+ (std::uint32_t)(v>=1000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000ull)
+ (std::uint32_t)(v>=100000000000000000ull)
+ (std::uint32_t)(v>=1000000000000000000ull)
+ (std::uint32_t)(v>=10000000000000000000ull);
}
回答by Alex Martelli
What do you mean "stored freely (int"? Once stored in an int, it has zero decimals left, clearly. A double is stored in a binary form, so no obvious or simple relation to "decimals" either. Why don't you keep the input as a string, just long enough to count those decimals, before sending it on to its final numeric-variable destination?
你是什么意思“自由存储(int”?一旦存储在一个int中,它就剩下零个小数,很明显。double以二进制形式存储,所以与“decimals”也没有明显或简单的关系。为什么不在将输入发送到最终的数字变量目的地之前,您将输入保留为字符串,长度足以计算这些小数点吗?
回答by Sev
Something like this might work as well:
像这样的事情也可能有效:
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();
回答by Shahab Hamid
using the Scientific Notation format (to avoid rounding errors):
使用科学记数法格式(以避免舍入错误):
#include <stdio.h>
#include <string.h>
/* 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]
[5]
回答by Holywa
Years after the fight but as I have made my own solution in three lines :
战斗多年后,但因为我已经在三行中制定了自己的解决方案:
string number = "543.014";
size_t dotFound;
stoi(number, &dotFound));
string(number).substr(dotFound).size()
Of course you have to test before if it is really a float
(With stof(number) == stoi(number)
for example)
当然你必须先测试它是否真的是一个浮点数(stof(number) == stoi(number)
例如)
回答by Zaki Hassan Naqvi
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);
}
回答by Zaki Hassan Naqvi
Here is the complete program
这是完整的程序
#include <iostream.h>
#include <conio.h>
#include <string.h>
#include <math.h>
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<<intstr<<'.'<<fractstr;
getche();
return(0);
}
char* intpart(double f)
{
char retstr[10];
int x,y,z,count1=0;
x=(int)f;
while(x>=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]='##代码##';
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);
}