我想找到方程式的所有正整数解
a^3 + b^3 = c^3 + d^3
其中a,b,c,d是1到1000之间的整数;
for (int a = 1; a <= 1000; ++a)
{
for (int b = 1; b <= 1000; ++b)
{
for (int c = 1; c <= 1000; ++c)
{
for (int d = 1; d <= 1000; ++d)
{
if (Math.Pow(a, 3) + Math.Pow(b, 3) == Math.Pow(c, 3) + Math.Pow(d, 3))
{
Console.WriteLine("{0} {1} {2} {3}", a,b,c,d);
}
}
}
}
我知道d = Math.Pow(a^3 + b^3 - c^3, 1/3)
,所以
for (int a = 1; a <= 1000; ++a)
{
for (int b = 1; b <= 1000; ++b)
{
for (int c = 1; c <= 1000; ++c)
{
int d = (int)Math.Pow(Math.Pow(a, 3) + Math.Pow(b, 3) - Math.Pow(c, 3), 1/3);
if (Math.Pow(a, 3) + Math.Pow(b, 3) == Math.Pow(c, 3) + Math.Pow(d, 3))
{
Console.WriteLine("{0} {1} {2} {3}", a,b,c,d);
}
}
}
}
但是第二种算法产生的结果数量要少得多。我的代码中的错误在哪里?
我尝试(double)1/3
,但第二个算法仍然给我较少数量的结果,然后是第一个
答案 0 :(得分:10)
这些答案中没有一个是正确的。
你的问题是:
我的代码中的错误在哪里?
如果您使用双精度算法来解决整数问题,那么您做错了。根本不要使用Math.Pow
,特别是不要使用它来提取立方根,并期望得到一个精确的整数答案。
那么你应该如何解决这个问题?
让我们更聪明地做不做不必要的工作。你的程序发现1 3 + 12 3 = 9 3 + 10 3 ,但也是12 3 + 1 3 = 10 3 + 9 3 ,依此类推。如果您知道第一个,那么您可以很容易地知道第二个。
那么我们该怎么做才能提高效率呢?
首先,b
必须大于a
。这样我们就不会浪费任何时间来确定1 3 + 12 3 = 12 3 + 1 3 。
同样,d
必须大于c
。
现在,我们也可以说c
和d
必须在 a
和b
之间。 你知道为什么吗?
一旦我们实施了这些限制:
for (int a = 1; a <= 1000; ++a)
for (int b = a + 1; b <= 1000; ++b)
for (int c = a + 1; c < b; ++c)
for (int d = c + 1; d < b; ++d)
if (a * a * a + b * b * b == c * c * c + d * d * d)
Console.WriteLine($"{a} {b} {c} {d}");
你的程序变得更快。
现在,如果您愿意以更短的时间交换更多内存,还有办法让它更快。你能想到这个节目浪费时间的一些方法吗?一遍又一遍地完成相同计算的次数是多少次?我们怎样才能改善这种状况?
我们可能会注意到,每次通过三个内部循环计算a * a * a
!
for (int a = 1; a <= 1000; ++a)
{
int a3 = a * a * a;
for (int b = a + 1; b <= 1000; ++b)
{
int b3 = b * b * b;
int sum = a3 + b3;
for (int c = a + 1; c < b; ++c)
{
int c3 = c * c * c;
int d3 = sum - c3;
for (int d = c + 1; d < b; ++d)
if (d3 == d * d * d)
Console.WriteLine($"{a} {b} {c} {d}");
}
}
}
但我们可能比那更聪明。例如:如果我们创建了一个将多维数据集映射到多维数据集根的Dictionary<int, int>
怎么办?只有1000个!然后我们可以说:
for (int a = 1; a <= 1000; ++a)
{
int a3 = a * a * a;
for (int b = a + 1; b <= 1000; ++b)
{
int b3 = b * b * b;
int sum = a3 + b3;
for (int c = a + 1; c < b; ++c)
{
int c3 = c * c * c;
int d3 = sum - c3;
if (dict.HasKey(d3))
{
d = dict[d3];
Console.WriteLine($"{a} {b} {c} {d}");
}
}
}
}
现在你不必计算d的立方体或立方根;你只是查看它是否是一个立方体,如果是,它的立方根是什么。
答案 1 :(得分:3)
即使是双精度,也不能用任何IEEE浮点类型精确表示1/3。
因此,您实际上并未计算某个值的多维数据集根,而是将该值提升至0.333333333333333333333333333334或稍微偏离版本的幂。这会引入舍入误差,导致误差因子增加。
考虑a = 995,b = 990,c = 990的情况:你的第一个循环会产生d = 995的匹配,但由于舍入错误,你的计算产生d = 994,这不符合你的条件。这很少会匹配,这可以解释您所看到的结果。
要解决这个问题,你可以完全使用浮点运算,但是这会变得很混乱,因为你必须检查范围,因为代表问题,即使这样,只有在你找到一个可能合适的范围之后,你才需要检查整数版本。另一种解决方案是从数学角度而不是蛮力来解决这个问题,尽管这可能需要内核方法并且变得非常混乱。
答案 2 :(得分:1)
替换
int d = (int)Math.Pow(Math.Pow(a, 3) + Math.Pow(b, 3) - Math.Pow(c, 3), 1/3);
与
int d = (int)Math.Round(Math.Pow(Math.Pow(a, 3) + Math.Pow(b, 3) - Math.Pow(c, 3), 1.0/3), 0);
if(d > 1000) continue; // Restrict solutions as in brute force algorithm
修复了两个错误,
1/3
被计算为整数除法,得到0
。使用1.0/3
强制浮点除法。3.999999994
而不是4
。当强制转换为整数时,会将其截断为3
,从而有效地删除解决方案。使用Math.Round(3.999999994, 0)
将其向上舍入为4.0
,并将其作为整数转换为4
。答案 3 :(得分:0)
您的问题是,此行的结果:int d = (int)Math.Pow(Math.Pow(a, 3) + Math.Pow(b, 3) - Math.Pow(c, 3), 1/3);
可能是非整数值,无法满足您的要求。但是通过将其转换为int
,您可以获得更多的解决方案。
您应该将d更改为double,然后检查d是否为1到1000之间的整数值:
double d = Math.Pow(Math.Pow(a, 3) + Math.Pow(b, 3) - Math.Pow(c, 3), 1.0/3.0);
double epsilon = 0.000000001;
double dint = Math.Round(d, 0);
if (dint<=d+epsilon && dint>=d-epsilon && dint>=1-epsilon && dint<=1000+epsilon)
{
Console.WriteLine("{0} {1} {2} {3}", a,b,c,d);
}
编辑:我添加了一个epsilon以确保您的双重比较可以正常工作