我怀疑将其转换为字符串,然后检查字符'0'是耗时的步骤。如果你想避免所有的零,可能会帮助增加
current
,如下所示:
(编辑--感谢Aaron McSmooth)
current++;
for( int i = 10000000; i >= 10; i = i / 10 )
{
if ( current % i ) == 0
{
current = current + ( i / 10 );
}
}
这个还没有经过测试,但是概念应该很清楚:每当你达到10的幂次方的倍数(例如300或20000),你就加上下一个更低的10的幂次方(在我们的例子中分别为10 + 1和1000 + 100 + 10 + 1),直到你的数字中没有更多的零。
相应地改变你的while
循环,看看这是否有助于提高性能,使你的问题变得可管理。
哦,你可能也想限制一下System.out
输出。每十次、每百次或每10000次迭代是否足够?
第二次编辑:
经过一些睡眠,我怀疑我的答案可能有点短视(如果你愿意,可以把它归咎于深夜)。我只是希望,哦,一百万次current
的迭代会让你得到解决方案,并且就此打住,而不是使用log(current)
等来计算修正情况。
仔细想了想,我发现这个问题有两个问题。一个是你的目标数字23.10345对我来说有点太圆了。毕竟,你正在添加成千上万个像“1/17”、“1/11111”等具有无限小数表示的项目,它们很可能不会准确地加起来得到23.10345。如果某个数值数学专家这么说,那就好吧——但我想看看他们是如何得出这个结论的算法。
另一个问题与第一个问题有关,涉及到您的有理数的内存中的二进制表示的限制。您可以使用BigDecimals,但我有所怀疑。
因此,基本上,我建议您重新编写数值算法,而不是采用暴力解决方案。抱歉。
编辑第三个:
出于好奇,我用C++编写了这个程序来测试我的理论。现在已经运行了6分钟,大约是14.5(大约5.5亿次迭代)。我们将看到。
当前版本为
double total = 0;
long long current = 0, currPowerCeiling = 10, iteration = 0;
while( total < 23.01245 )
{
current++;
iteration++;
if( current >= currPowerCeiling )
currPowerCeiling *= 10;
for( long long power = currPowerCeiling; power >= 10; power = power / 10 )
{
if( ( current % power ) == 0 )
{
current = current + ( power / 10 );
}
}
total += ( 1.0 / current );
if( ! ( iteration % 1000000 ) )
std::cout << iteration / 1000000 << " Mio iterations: " << current << "\t -> " << total << std::endl;
}
std::cout << current << "\t" << total << std::endl;
通过手动计算currPowerCeiling
(或者其他可能称之的方式)可以节省每次迭代中一些log10
和pow
计算。每一个小优化都有帮助 - 但仍然需要很长时间...
第四次编辑:
状态约为66,000百万次迭代,总共已达到16.2583,运行时间约为13小时。情况不太乐观,Bobby S. - 我建议采用更数学化的方法。