检查1 / n小数点后是否有无限位数

问题描述

如果用户输入不等于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;对于任何整数pp / 2**k == (p * 5**k) / 10**k。因此1/2==5/101/4 == 25/1001/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,而无需使用浮点算法。