【问题标题】:Check if 1/n has infinite number of digits after decimal point检查 1/n 小数点后是否有无限位数
【发布时间】:2021-02-12 20:59:56
【问题描述】:

如果用户输入一个不等于 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。

【问题讨论】:

  • 仅仅因为计算机不能存储无限精度并不意味着它不能以有限精度获得数学上正确的结果(但当然不能保证)。另外,您似乎假设浮点数存储为小数,而它们不是(通常)。你将不得不检查除数。这是问题的自然解决方案。
  • 乘法 `n * (1/n)` 不会以无限精度执行。最简单的方法是按照您的建议检查是否存在除 2 和 5 之外的其他除数
  • 它非常接近重复但不准确。但是,如果您阅读本文,您将了解很多需要了解的内容 - stackoverflow.com/questions/588004/… 基本上您无法通过使用浮点数学来回答这个问题。
  • @Yunnosch 我知道 OP 假设除法 1/n 的精度是有限的,然后是乘法的完美选择。这就是为什么我坚持乘法。我可能不清楚,或者 OP 的解释有误。
  • @RichardCritten 感谢您分享这篇文章。

标签: c++ math arithmetic-expressions


【解决方案1】:

您的代码试图利用1.0/n 没有以完美的精度完成的事实,这是真的。将结果乘以 n 理论上应该得到不等于 1 的结果,是的。
遗憾的是,在您的代码中与 n 的乘法也没有以完美的精度完成。
让你的概念出错的事实是,这两个不完美可以相互抵消,最终你会得到一个看似完美的 1。

所以,是的。进行除数检查。

【讨论】:

  • 您正确理解了我的问题,谢谢您的回答。我不会浪费时间尝试修复此代码。 :-)
【解决方案2】:

二进制与十进制

你的作业询问你是否可以用 十进制 表示的有限位数来表示分数 1/n。 python中的浮点数是用binary表示的,它与decimal有一些相似之处和不同之处:

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

这是因为 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 检查是否相等将返回真或假。在使用与 python 相同的浮点运算的语言 C 中,如果您尝试测试两个浮点数的相等性,编译器将发出警告(可以使用选项-Wfloat-equal 启用或禁用此警告)。

算法的不同逻辑

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

【讨论】:

    猜你喜欢
    • 2016-01-12
    • 2021-04-23
    • 1970-01-01
    • 2017-01-26
    • 2010-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多