Здравствуйте, Seon, Вы писали:
S>Здравствуйте, vadimcher, Вы писали:
S>По одному из вариантов программы (пусть не самый быстрый) на процессоре рейтинга 2000 считается 70 000 000 знаков в секунду.
S>число а17 — это приблизительно миллиардная степень двойки.
S>для расчета 2^1 000 000 000 придется обработать (1000000000 ^ 2) / (2 * 3.31) знаков. (3.31 — коэффициент ширины десятичного представления степени двойки) S>итого это 151 057 401 812 688 821 знаков. S>для их расчета 1-му процессору потребуется 2 157 962 883 секунд S>или 599 434 часов S>или 24 976 суток S>или 68 лет
S>если на эту задачу бросить 70 процессоров, то потребуется почти год.
S>явно, что а17 расчитывалось, либо каким то другим способом (не удвоением), либо на каком то жутко мощном майнфрэйме S>ну или на огромном количестве компов...
Сделал алгоритм, работающий заметно быстрее.
В скобках — реальное кол-во умножений.
Основные моменты, из-за которых получилось быстрее:
— если в N-й степени двойки есть K нулей подряд, то в N+1,N+2,N+3 — не менее (K-1), N+4,N+5,N+6 — не менее (K-2) и т.д.
И обратно: если в N-й степени двойки есть не более K нулей подряд, то в N-1 — не более (K+1), N-2,N-3,N-4 — не более (K+2)
Поэтому скакнув на несколько степеней вперед мы частенько сможем отбросить все промежуточные.
— Число хранится в виде групп десятичных цифр, и быстро можно умножить это число на степень двойки, умещающееся в десятичном представлении в одной группе, кол-во нулей в группе берется из заранее посчитаной таблицы — кол-во нулей в начале, кол-во нулей в конце. Поэтому нули, идущие в середине группы, не определяются, и для i=(ширина группы — 2) a(i) неверно
Здравствуйте, nikholas, Вы писали:
N>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня
Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.
Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)
Здравствуйте, Spiceman, Вы писали:
S>Здравствуйте, nikholas, Вы писали:
N>>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня
S>Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.
S>Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)
Кстати у меня получилось сделать распределенный вариант этой задачи
Сейчас уже приближаюсь к 50 000 000. (а14)
Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами
Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи.
Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут.
Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)
Здравствуйте, Seon, Вы писали:
S>Кстати у меня получилось сделать распределенный вариант этой задачи S>Сейчас уже приближаюсь к 50 000 000. (а14) S>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами
Тоже вот хотел распределенную написать. Но после ответа nikholas, захотелось сначала прикрутить его идею.
S>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи. S>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут. S>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)
У меня на C# многопроцессорный вариант — посчитал до 2^16млн за 8 часов на двухядернике.
Лучше делиться не кодом, а идеями, чтобы их можно было в свой код прикручивать.
Здравствуйте, Spiceman, Вы писали:
S>Здравствуйте, Seon, Вы писали:
S>>Кстати у меня получилось сделать распределенный вариант этой задачи S>>Сейчас уже приближаюсь к 50 000 000. (а14) S>>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами
S>Тоже вот хотел распределенную написать. Но после ответа nikholas, захотелось сначала прикрутить его идею.
S>>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи. S>>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут. S>>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)
S>У меня на C# многопроцессорный вариант — посчитал до 2^16млн за 8 часов на двухядернике. S>Лучше делиться не кодом, а идеями, чтобы их можно было в свой код прикручивать.
Легко.
Вариант мультиматериночный
Что из себя представляет это число?
Треугольник знаков.
После вычисления каждого блока имеем 2 файла результатов:
1
2
4
8
16
32
64
128
256
512
1 024
2 048
4 096
8 192
--6 384
|
| 2 768 - это файл результата по ширине блока
|
|
--> 1 2 4 8 6 - это файл результата по высоте блока
Каждый из файлов будет исходными данными для следующего блока.
Вот основная идея. Можете работать
У меня файл по высоте содержит значение переноса из предыдущего разряда, а не само число, как в примере...
Кроме этого содержит максимальное количество нулей подряд из вычисленного куска числа, и количество нулей в конце этого числа — потому как число нового блока может начаться с нулей и надо знать сколько их было в предыдущем блоке.
Этот файл содержит 1 слово на каждое значение последовательности:
ABBBBBBB 0CCCCCCC
A — бит переноса из предыдущего разряда
B — максимальное количество нулей
C — количество нулей на конце блока
Разбивка вычисления на блоки — это только половина задачи.
Вторая половина — это чтобы N запущенных задач брали блоки по порядку и вычисляли:
Примерно так:
A
AA
AAA
AAAA
AAAAA
AAAAAA
AAAAAAA
111111 - вычисляет экземпляр приложения I
22222 - вычисляет экземпляр приложения II
3333 - вычисляет экземпляр приложения III
444 - вычисляет экземпляр приложения IV
55 - вычисляет экземпляр приложения V
6 - вычисляет экземпляр приложения VI
A — уже посчитанные числа
Жирным показаны текущие вычисляемые блоки
Если вот для этого примера сейчас запустить 7-й экземпляр, программа будет ожидать появления свободной задачи. Он появится как только экземпляр приложения VI перейдет к следующему левому блоку.
Сейчас у меня расчитана уже 35 000 000 степень. Так как размер блока у меня 100000х200000, то имеем уже 175 строку. Количество блоков по ширине = 105.
То есть одновременно можно запустить 105 компов.
В моем варианте программа просто натравливается на расшаренный по сети каталог с файлами результатов, захватывает 2 из них, вычисляет блок, и записывает в этот каталог результаты, затем цикл повторяется.
Но лучше сделать такой вариант: Одна программа — сервер-шедулер, занимается менеджментом заданий, остальные — клиенты: запрашивают у сервера задачи, вычисляют и отдают результаты назад.
Здравствуйте, Seon, Вы писали:
S>Здравствуйте, Spiceman, Вы писали:
S>>Здравствуйте, nikholas, Вы писали:
N>>>Аппроксимация времени — квадратичная, и до арда потребуется примерно 667*(1.000.000.000 / 4.036.338)^2 = 40.000.000 сек = 11.111 час = 462 дня
S>>Круто! Тоже думал про такую оптимизацию, но не думал, что это даст такой прирост производительности.
S>>Чувствую, близок день, когда RSDN BruteForce Team посчитает a(18)
S>Кстати у меня получилось сделать распределенный вариант этой задачи S>Сейчас уже приближаюсь к 50 000 000. (а14) S>Расчет ведется одновременно на 8 компах, при чем по моему медленному, и неоптимизированному всякими такими фичами
S>Задача разбивается на "квадратные" блоки, каждый из которых считает отдельный экземпляр задачи. S>Текущий размер блока 100000х200000 знаков. Считается такой блок около 5 минут. S>Скорость расчета прямо пропорциональна количеству компов, на которых запущена эта задача. Кого интересует могу поделиццо кодом (С++)
Боюсь до конца ты не доживешь
Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
Здравствуйте, nikholas, Вы писали:
N>Боюсь до конца ты не доживешь
N>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
Ну полгода на 100 компах это уже "приемлемое" время. Будем кумекать дальше.
Здравствуйте, nikholas, Вы писали:
N>Боюсь до конца ты не доживешь
N>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
Так вот же и пытаемся придумать оптимальное решение.
Вчера сделал еще одну оптимизацию.
Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!!
Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню
Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают
ЗАТО это дало прирост в скорости пятикратно!
=====================================================
a(9) [2^100823] Time: 0:0:0:10
a(10) [2^559940] Time: 0:0:5:15
a(11) [2^1148303] Time: 0:0:16:38
a(12) [2^4036338] Time: 0:2:51:17
=====================================================
скорость 2.4 * 10^8 знаков в сек
по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, nikholas, Вы писали:
N>>Боюсь до конца ты не доживешь
N>>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
А>Так вот же и пытаемся придумать оптимальное решение.
А>Вчера сделал еще одну оптимизацию. А>Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!! А>Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню А>Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают
А>ЗАТО это дало прирост в скорости пятикратно!
А>===================================================== А>a(9) [2^100823] Time: 0:0:0:10 А>a(10) [2^559940] Time: 0:0:5:15 А>a(11) [2^1148303] Time: 0:0:16:38 А>a(12) [2^4036338] Time: 0:2:51:17 А>===================================================== А>скорость 2.4 * 10^8 знаков в сек А>по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек
Круто!
А каким способом подсчитывается кол-во нулей? 9 делений и 9 if-ов ?
Или это просто вычисление 2-в-нужной-степени?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, nikholas, Вы писали:
N>>Боюсь до конца ты не доживешь
N>>Для a17 надо посчитать 10^9 (кол-во строк) * 3*10^8 (~длина 2^1000000000 в десятичном представлении) / 2 знаков, у тебя считается 10^5 * 2*10^5 за 300 сек, скорость < 10^8 знаков в сек., итого тебе потребуется 10^9 * 3 * 10^8 / ( 2 * 10^8) сек = 17000 дней, даже на 100 компах пол-года
А>Так вот же и пытаемся придумать оптимальное решение.
А>Вчера сделал еще одну оптимизацию. А>Теперь у меня система не десятичная а миллиардичная. Каждый знак теперь не от 0 до 9 а от 0 до 999999999!!! А>Обрабатываем не массив чаров а массив интов. Подобная идея уже кем то тут описывалась... сори не помню А>Конечно пришлось пожертвовать вычислениями от а1 до а8, но их и так все давно знают
А>ЗАТО это дало прирост в скорости пятикратно!
А>===================================================== А>a(9) [2^100823] Time: 0:0:0:10 А>a(10) [2^559940] Time: 0:0:5:15 А>a(11) [2^1148303] Time: 0:0:16:38 А>a(12) [2^4036338] Time: 0:2:51:17 А>===================================================== А>скорость 2.4 * 10^8 знаков в сек А>по старому у меня а(12) считалось около 13 часов — 5 * 10^7 зн/сек
Здравствуйте, nikholas, Вы писали:
N>Круто!
N>А каким способом подсчитывается кол-во нулей? 9 делений и 9 if-ов ? N>Или это просто вычисление 2-в-нужной-степени?
3 ифа
1 деление
int zeros_left(BaseType c)
{
int z;
if (c < 10000)
{
z = 5;
if (c < 100)
{
z += 2;
if (c < 10)
z++;
}
else
if (c < 1000)
z++; }
else
{
if (c < 1000000)
{
z = 3;
if (c < 100000)
z++;
}
else
{
if (c < 100000000)
{
z = 1;
if (c < 10000000)
z++;
}
else
z = 0;
}
}
return z;
}
bool zeros_right(BaseType c, int z)
{
BaseType t;
switch(z)
{
case 1:
t = 10;
break;
case 2:
t = 100;
break;
case 3:
t = 1000;
break;
case 4:
t = 10000;
break;
case 5:
t = 100000;
break;
case 6:
t = 1000000;
break;
case 7:
t = 10000000;
break;
case 8:
t = 100000000;
break;
default:
return false;
}
if ((c % t) == 0)
return true;
return false;
}
А теперь кусок вызывающей функции
BaseType ost = 0;
bool z = false;
int nz = 0;
BaseType res;
BaseType c;
for(int n = 0; n < size; ++n)
{
c = arr[n];
res = c << 1;
if (ost) res++;
if (res > 999999999)
{
c = res - 1000000000;
ost = 1;
}
else
{
c = res;
ost = 0;
}
if (c)
{
if (zeros_right(c, zeros - nz))
z = true;
nz = zeros_left(c);
}
else
nz += 9;
arr[n] = c;
}
if (ost)
arr[size++] = ost;
if (z)
{
// нашли очередное число нулей
}
Где,
Pow2[] = {0, 1, 3, 7, 15,...}, то есть 2^n — 1.
Base5[] = {1, 5, 25, 125, 625, ...}, то есть 5^n
z — вместо степени 10 использовать показатель степени, то есть, вместо 10 использовать 1, вместо 100 — 2, вместо 1000 — 3 и т.д.
Пояснение. Число делится на 100, если делится на 4 и на 25. В данном слечае:
(c & Pow2[2]) == 0 — проверка делимости на 4,
((c >> z) % Base5[2]) == 0 — проверка делимости на 25.
Код становится менее лапшеобразным без потери скорости.
S>Где, S>Pow2[] = {0, 1, 3, 7, 15,...}, то есть 2^n — 1. S>Base5[] = {1, 5, 25, 125, 625, ...}, то есть 5^n S>z — вместо степени 10 использовать показатель степени, то есть, вместо 10 использовать 1, вместо 100 — 2, вместо 1000 — 3 и т.д. S>Пояснение. Число делится на 100, если делится на 4 и на 25. В данном слечае: S>(c & Pow2[2]) == 0 — проверка делимости на 4, S>((c >> z) % Base5[2]) == 0 — проверка делимости на 25.
S>Код становится менее лапшеобразным без потери скорости.
На счет массивов — я как то про них и забыл...
тогда так
BaseType step[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
bool zeros_right(BaseType c, int z)
{
if (z && z < 9)
{
if ((c % step[z]) == 0)
return true;
}
return false;
}