Я подозреваю, что приведение к строке и проверка на наличие символа '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
. Будет ли достаточно каждой десятой, одной сотой или сотой итерации?
Редактировать второе:
После некоторого сна я подозреваю, что мой ответ может быть немного недальновидным (обвините в позднем часе, если хотите). Я просто надеялся, что один миллион итераций 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 часов. Не очень хорошо выглядит, Бобби С. - Я предлагаю более математический подход.