Я подозреваю, что преобразование в строку с последующей проверкой символа «0» - это этап, который занимает слишком много времени. Если вы хотите избежать всех нулей, может помочь увеличить current
таким образом:
(Отредактировано - спасибо Аарону МакСмуту)
current++;
for( int i = 10000000; i >= 10; i = i / 10 )
{
if ( current % i ) == 0
{
current = current + ( i / 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 (примерно 550 миллионов итераций). Посмотрим.
Текущая версия
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 часов. Не очень хорошо, Бобби С. - Я предлагаю более математический подход.
person
Christian Severin
schedule
02.10.2010