检查 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;对于任何整数 p
、p / 2**k == (p * 5**k) / 10**k
。因此 1/2==5/10
和 1/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 算术。
如果用户输入不等于 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;对于任何整数 p
、p / 2**k == (p * 5**k) / 10**k
。因此 1/2==5/10
和 1/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 算术。