给定 (a, b) 计算 k 的最大值,使得 a^{1/k} 和 b^{1/k} 是整数

Given (a, b) compute the maximum value of k such that a^{1/k} and b^{1/k} are whole numbers

本文关键字:整数 最大值 计算 给定 使得      更新时间:2023-10-16

我正在编写一个程序,试图找到 k> 1 的最小值,使得 a 和 b 的第 k 个根(都给定)等于整数。

这是我的代码片段,为了澄清,我已经对其进行了注释。

int main()
{
// Declare the variables a and b.
double a;
double b;
// Read in variables a and b.
while (cin >> a >> b) {
int k = 2;
// We require the kth root of a and b to both be whole numbers.
// "while a^{1/k} and b^{1/k} are not both whole numbers..."
while ((fmod(pow(a, 1.0/k), 1) != 1.0) || (fmod(pow(b, 1.0/k), 1) != 0)) {
k++;
}

几乎,我读了 (a, b),我从 k = 2 开始并递增 k,直到 a 和 b 的第 k 个根都与 0 mod 1 全等(这意味着它们可以被 1 整除,因此是整数)。

但是,循环无限运行。我尝试过研究,我认为这可能与精度错误有关;但是,我不太确定。

我尝试过的另一种方法是更改循环条件以检查 a^{1/k} 的下限是否等于 a^{1/k} 本身。但同样,这可能是由于精度误差,这是无限运行的。

有谁知道我该如何解决这个问题?

编辑:例如,当(a,b)= (216,125)时,我希望k = 3,因为216^(1/3)和125^(1/3)都是整数(即5和6)。

这不是一个编程问题,而是一个数学问题:

如果a是实数,k是正整数,如果a^(1./k)是整数,则a是整数。(否则目的是玩弄近似误差)

因此,最快的方法可能是首先检查ab是否是整数,然后进行素数分解,使得 a=p 0 e0*p1e1* ...,其中pi是不同的素数。

请注意,要使1/k 成为整数,每个 ei也必须能被 k 整除。换句话说,k 必须是 ei的公约数。如果 b1/k是整数,则 b 的素幂也必须如此。

因此,最大的kab的所有ei的最大公约数。


使用您的方法,您将遇到大量问题。所有 IIEEE 754 二进制 64 浮点数(x86 上的双精度情况)都有 53 个有效位。这意味着所有大于 253的双精度都是整数。

函数pow(x,1./k)将为两个不同的x产生相同的值,因此使用您的方法,您必须有错误的答案,例如数字 55*290和 35*2120完全可以用双精度表示。算法的结果是k=5.您可能会在这些数字中找到k的值,但您也会找到 55*290-249和 35*2120k=5,因为 pow(55*290-249,1./5)==pow(55*290)。在这里演示

另一方面,由于只有 53 个有效位,双精度的素数分解是微不足道的。

浮点数不是数学实数。计算是"近似的"。请参阅 http://floating-point-gui.de/

你可以用类似fabs(fmod(pow(a, 1.0/k), 1) - 1.0) > 0.0000001的东西替换测试fmod(pow(a, 1.0/k), 1) != 1.0(并使用各种这样的而不是0.0000001;另请参阅std::numeric_limits::epsilon,但要谨慎使用它,因为pow可能会在其计算中给出一些错误,并且1.0/k也会注入不精确性 - 细节非常复杂,深入研究IEEE754规范)。

当然,你可以(并且可能应该)定义你的bool almost_equal(double x, double y)函数(并使用它而不是==,并使用它的否定而不是!=)。

根据经验,切勿测试浮点数的相等性(即==),但请考虑它们之间足够小的距离;也就是说,将像x == y(分别为x != y)这样的测试替换为类似fabs(x-y) < EPSILON(分别为fabs(x-y) > EPSILON),其中EPSILON是一个小的正数,因此测试一个小的 L1距离(对于相等,以及足够大的距离来表示不相等)。

并避免整数问题中的浮点数。

实际上,预测或估计浮点精度是非常困难的。您可能需要考虑像 CADNA 这样的工具。我的同事Franck Védrine是静态程序分析仪估计数值误差的专家(例如,参见他在TERATEC 2017关于Fluctuat的演讲)。这是一个困难的研究课题,另见D.Monniaux的论文《验证浮点计算的陷阱》等。

浮点错误在某些情况下确实造成了人命损失(或损失数十亿美元)。搜索网络以获取详细信息。在某些情况下,计算数字的所有数字都是错误的(因为错误可能会累积,最终结果是通过组合数千个操作获得的)!与混沌理论有一些间接关系,因为许多程序可能有一些数值不稳定。

正如其他人所提到的,比较相等的浮点值是有问题的。如果您找到一种直接使用整数的方法,则可以避免此问题。一种方法是将整数提高到k次幂,而不是取第k个根。细节留给读者作为练习。