问题描述
如果用户输入不等于0的数字“ n”(整数),则我的程序应检查小数1/n
是否在小数点后具有无穷或有限位数。例如:对于n=2
,我们有1/2=0.5
,因此小数点后有1位数字。我对这个问题的第一个解决方案是:
int n=1;
cin>>n;
if((1.0/n)*n==1)
{
cout<<"fixed number of digits after decimal point";
}
else cout<<"infinite number of digits after decimal point";
由于计算机无法存储像1/3
这样的无限数字,所以我期望(1/3)*3
不会等于1
。第一次运行程序时,结果达到了我的预期,但是今天运行程序时,对于n=3
,我得到了输出(1/3)*3=1
。我对这个结果感到惊讶并尝试了
double fraction = 1.0/n;
cout<< fraction*n;
哪个也返回了1.为什么行为不同,我可以使算法起作用吗?如果我无法使其工作,我将不得不检查n
的除数是否仅为1、2和5,我认为这将很难编程和计算。
我的IDE是Visual Studio,因此我的C ++编译器是VC。
解决方法
您的代码试图利用1.0/n
并非完美精确的事实,这是事实。从理论上将结果乘以n
可以使您获得不等于1的值,这是正确的。
遗憾的是,在代码中与n
的乘积也不是完美的。
使您的概念崩溃的事实是,这两个缺陷可以相互抵消,最终您会得到一个看似完美的1。
是的,是的。除数检查。
,二进制与十进制
您的作业询问您分数1/n
是否可以用十进制表示形式的有限位数来表示。 python中的浮点数使用 binary 表示,它与十进制有一些相似之处和不同之处:
- 如果有理数可以用有限位数的二进制表示,那么它也可以用有限位数的十进制表示;
- 某些数字可以用十进制表示,但数字位数是有限的,但是需要用十进制表示的位数是无限的。
这是因为10 = 2 * 5;对于任何整数p
,p / 2**k == (p * 5**k) / 10**k
。因此1/2==5/10
和1/4 == 25/100
和1/8 == 125/1000
可以用有限的数字或位表示。但是1/5
可以用有限的十进制数字表示,但需要无限的二进制位。
浮点运算和相等性测试
另请参阅:Is floating-point math broken?和What every programmer should know about floating-point arithmetic (pdf paper)。
计算(1.0 / n) * n
得到一个近似值;几乎没有办法知道用1.0
检查是否相等将返回true或false。在使用与python相同的浮点算法的语言C中,如果您尝试测试两个浮点数的相等性,则编译器会发出警告(可以使用选项-Wfloat-equal
启用或禁用此警告)。
算法的不同逻辑
您不能依靠浮点算法来确定您的问题。但这不是必需的。当且仅当数字可以以p / 10**k
的形式写有p和k整数时,才可以用有限的多个数字表示。因此,您的程序应检查n
,以找出是否存在1 / n == 1 / (2**j * 5**k)
这样的j和k,而无需使用浮点算法。