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

Check if 1/n has infinite number of digits after decimal point

如果用户输入不等于 0 的数字“n”(整数),我的程序应检查分数 1/n 的小数点后是无限位数还是有限位数。例如:对于 n=2 我们有 1/2=0.5,因此我们在小数点后有一位数字。我对这个问题的第一个解决方案是:

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是否可以用十进制表示中的有限位数来表示。 Floating-point中的数字python用二进制表示,与十进制有相似之处也有不同:

  • 如果一个有理数可以用有限位数的二进制表示,那么它也可以用有限位数的十进制表示;
  • 有些数字可以用有限位数的十进制表示,但需要无限位数的十进制。

这是因为 10 = 2 * 5;对于任何整数 pp / 2**k == (p * 5**k) / 10**k。因此 1/2==5/101/4 == 25/100 以及 1/8 == 125/1000 可以用有限多个数字或位表示。但是 1/5 可以用有限多位十进制数表示,但需要无限多位二进制数。

Floating-point 算术和相等性测试

另请参阅:Is floating-point math broken? and What every programmer should know about floating-point arithmetic (pdf paper)

计算(1.0 / n) * n得到一个近似值;几乎没有办法知道用 1.0 检查是否相等将 return 是真还是假。在使用与 python 相同的 floating-point 算法的 C 语言中,如果您尝试测试两个 floating-point 数字是否相等,编译器将发出警告(此警告可以启用或禁用选项 -Wfloat-equal).

算法的不同逻辑

你不能依靠 floating-point 算术来决定你的问题。但这不是必需的。一个数可以用有限多位数字表示当且仅当它可以写成 p / 10**k 形式且有 p 和 k 个整数。所以你的程序应该检查 n 来找出是否存在 j 和 k 使得 1 / n == 1 / (2**j * 5**k),而不使用 floating-point 算术。