2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1 ... 29, 30, 31, 32, 33, 34, 35 ... 54  След.

А вам пакет PARI/GP интересен?
Да 83%  83%  [ 58 ]
Нет 6%  6%  [ 4 ]
Не уверен(а) 11%  11%  [ 8 ]
Всего голосов : 70
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение24.10.2022, 12:47 
Заслуженный участник


20/08/14
11867
Россия, Москва
Не помню было ли, но пусть даже и повторю.
Иногда бывает удобно/нужно изменить одновременно две (три и т.д.) переменные, например в рекуррентных формулах типа $(x_{i+1},y_{i+1})=(2x_i+3y_i,3x_i+4y_i)$, это можно сделать без введения новых переменных: [x,y]=[2*x+3*y,3*x+4*y].
Справа может стоять и массив или его часть, слева тоже можно массив, но только целиком.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение28.10.2022, 17:37 
Заслуженный участник


20/08/14
11867
Россия, Москва
Ещё небольшой лайфхак: многие функции принимают лишь два аргумента (gcd, lcm, chinese, и т.д.) и в то же время принимают и вектор значений, например:
Код:
? lcm([2,3,5,7])
%1 = 210
? chinese([Mod(1,2),Mod(1,3),Mod(3,7)])
%2 = Mod(31, 42)

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 10:04 
Заслуженный участник
Аватара пользователя


13/08/08
14495
А вот возникла потребность в лайфхаке.
Предположим, некто хочет организовать сплошной перебор по парам натуральных чисел для проверки некоторой однородной функции. То есть результат проверки будет одинаков для пар $(n,m)\sim (kn,km) \;\forall\;n,m,k$
Например, такая последовательность пар:
$(1,1),(1,2),(2,1),(1,3),(3,1),(1,4),(2,3),(3,2),(4,1)...$ по возрастанию суммы элементов. Не нужно проверять пары $(2,2),(2,4),(4,2),(3,3),(6,2),(6,3)$Что бы такое придумать, если проверка функции очень длительная. Нет ли в PARI/GP чего-нибудь этакого?
Типа просто проверки на то, что у пары есть общий множитель?
А если это тройки? Например, для проверки ВТФ :-)

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 13:02 
Заслуженный участник


20/08/14
11867
Россия, Москва
gris
Вот как раз gcd([...]) прекрасно справится. Если я правильно понял.
Код:
? gcd([125,210,75,195])
%1 = 5
Для пары можно и без массива.

Но если перебор долгий, то лучше побольше вариантов исключить руками (да хоть проверкой что оба числа делятся на 2,3,5), не думаю что gcd() сильно быстрая.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 13:31 


05/09/16
12110
Dmitriy40 в сообщении #1568127 писал(а):
не думаю что gcd() сильно быстрая.

Ну у меня на планшете так. Генерация миллиона пар случайных целых чисел в диапазоне до миллиона: 437 мс
? for(i=1,10^6,a=random(10^6);b=random(10^6))
? ##
*** last result computed in 439 ms.

То же, плюс вычисление их НОД: 729 мс
? for(i=1,10^6,a=random(10^6);b=random(10^6);c=gcd(a,b))
? ##
*** last result computed in 729 ms.

То же, но вместо вычисления НОД, вычисление суммы: 631 мс
? for(i=1,10^6,a=random(10^6);b=random(10^6);c=a+b)
? ##
*** last result computed in 631 ms.

То есть, вычисление НОД примерно в полтора раза медленнее вычисления суммы, для чисел в пределах миллиона.
Всё едят оверхеды (вызовы функций, проверки корректности аргументов и т.п.)

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 13:42 
Заслуженный участник
Аватара пользователя


13/08/08
14495
Dmitriy40, спасибо. Но gcd для небольших чисел пригоден, а мне бы что-нибудь типа isvzaimnoprosty :-) от массива трёх чисел из диапазона 1е60 - 1 е80. Хотя может быть это равносильно проверке делимости на последовательные простые, а вдруг более хитрые алгоритмы действуют :?:

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 14:10 
Заслуженный участник


20/08/14
11867
Россия, Москва
gris в сообщении #1568134 писал(а):
Dmitriy40, спасибо. Но gcd для небольших чисел пригоден, а мне бы что-нибудь типа isvzaimnoprosty :-) от массива трёх чисел из диапазона 1е60 - 1 е80.
С чего бы? НОД вычисляется или делением (алгоритм Евклида), или сдвигами (лень смотреть как в PARI, по скорости похоже на сдвиги), и в том и в другом случае величина чисел может быть любой и к простоте (медленная проверка для больших чисел) они не привязаны:
Код:
? gcd([10^8000+13350,10^7000+4450,10^6000+22250])
%1 = 50

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 14:46 
Заслуженный участник
Аватара пользователя


13/08/08
14495
А вот что даже совсем в начале:(
Код:
{M=1000; N=0; for(i=1,M,  for(j=i,M, for(k=j,M,
   if(gcd([i,j,k])==1,N++);
  ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))}
83

И это у меня считалось 140 секунд. Увы... Я уж боюсь посчитать долю упорядоченных троек с не взаимно простыми числами не большими миллиона. Ясно, что она маленькая.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 15:02 


05/09/16
12110
gris в сообщении #1568145 писал(а):
И это у меня считалось 140 секунд. Увы... Я уж боюсь посчитать долю упорядоченных троек с не взаимно простыми числами не большими миллиона. Ясно, что она маленькая.

Я полагаю, вам надо вычислять в два захода. Сначала факторизовать всё до миллиона, а потом работать с факторизациями. Думаю где-то на порядок будет быстрее (два порядка не обещаю).
Вам не надо хранить показатели, только основания. Можно сделать что-то вроде битовой подписи числа: маладший бит равен 1 если четное, следующий равен 1 если делится на три и т.п. У взаимнопростых побитовое И будет ноль. Возможно стоит ограничиться например первой сотней простых, уже на этом этапе почти все отсеется.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 19:55 
Заслуженный участник


20/08/14
11867
Россия, Москва
gris
Реализация идеи wrest с дополнительными оптимизациями:
Код:
? M=1000; N=0; for(i=1,M, for(j=i,M, for(k=j,M, if(gcd([i,j,k])==1, N++;); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\Ваш исходный вариант
83
time = 1min, 18,266 ms.

? M=1000; N=0; for(i=1,M, for(j=i,M, t=gcd(i,j); if(t==1, N+=M-j+1, for(k=j,M, if(gcd(t,k)==1, N++;);); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\Добавим ему оптимизации
83
time = 17,364 ms.

? M=2000; N=0; for(i=1,M, for(j=i,M, t=gcd(i,j); if(t==1, N+=M-j+1, for(k=j,M, if(gcd(t,k)==1, N++;);); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\Увеличим предел вдвое
83
time = 2min, 21,540 ms.

? M=1000; b=vector(M); for(x=2,M, t=0; foreach(factor(x)[,1],p, t=bitor(t,2^p)); b[x]=t;);\\Формирование факторизаций, единицы мс
? N=0; for(i=1,M, for(j=i,M, t=bitand(b[i],b[j]); for(k=j,M, if(bitand(t,b[k])==0, N++;); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\Используем
83
time = 45,959 ms.

? M=1000; b=vector(M); for(x=2,M, t=0; foreach(factor(x)[,1],p, t=bitor(t,2^p)); b[x]=t;);\\Формирование факторизаций, единицы мс
? N=0; for(i=1,M, for(j=i,M, t=bitand(b[i],b[j]); if(t==0, N+=M-j+1, for(k=j,M, if(bitand(t,b[k])==0, N++;);); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\С оптимизацией лишнего цикла
83
time = 14,572 ms.

? M=2000; b=vector(M); for(x=2,M, t=0; foreach(factor(x)[,1],p, t=bitor(t,2^p)); b[x]=t;);\\Формирование факторизаций, единицы мс
? N=0; for(i=1,M, for(j=i,M, t=bitand(b[i],b[j]); if(t==0, N+=M-j+1, for(k=j,M, if(bitand(t,b[k])==0, N++;);); ))); print(floor(100*N/(M*(M+1)*(M+2)/6)))\\Увеличим предел вдвое
83
time = 2min, 5,254 ms.
Выходит смысла в предрасчёте факторизаций в общем и нет, достаточно не делать лишних циклов.
Рост времени от M практически кубический, как и ожидалось (три вложенных цикла). Значит до миллиона не досчитаете, даже до сотни тысяч. И дело не только в медленности gcd или bitand, а в кубической зависимости.

-- 29.10.2022, 20:11 --

gris
С другой стороны, значения N для каждого M уже посчитаны в A015631. :mrgreen: Там и программы на PARI приведены, намного быстрее:
Код:
? M=1000000; N=sum(k=1, M, sumdiv(k, d, moebius(k/d)*binomial(d+1, 2))); print("N=",N);print(floor(100*N/(M*(M+1)*(M+2)/6)));
N=138651542411519020
83
time = 5,836 ms.
Почему работает правильно — меня не спрашивайте.

-- 29.10.2022, 20:13 --

Т.е. в таких случаях полезно найти самому несколько первых (или близких к началу) значений самой простой функции из требуемых — и поискать их в OEIS.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 20:40 
Заслуженный участник
Аватара пользователя


13/08/08
14495
Спасибо! Мне неловко своей ерундой забивать тему, но всё-таки тут есть, чему поучиться именно в ПАРИ. Да, я подробно изучу. Собственно, я уже понял, что общие делители 2,3,5,7 и 11 уже дают немалый отсев троек, по-моему даже независимо от положения проверяемого интервала. Этакое скользящее решето Э:) То есть тройки можно отправлять на финальную проверку. А немного лишних замедлят ненадолго.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 21:14 
Заслуженный участник


20/08/14
11867
Россия, Москва
gris в сообщении #1568184 писал(а):
общие делители 2,3,5,7 и 11 уже дают немалый отсев троек, по-моему даже независимо от положения проверяемого интервала.
Разумеется независимо, по модулю же $\operatorname{lcm}(2,3,5,7,11)=2310$ начиная с любого выбранного числа все свойства делимости (и взаимной простоты соответственно) будут повторяться.

А насчёт троек, возможно 83% вообще предел на бесконечности, раз уж держится от 331 до сотни миллионов без исключений.

Кстати если нужны количества для M больше сотен миллионов (что займёт уже часы счёта), то можно заменить binomial() на выборку из предрасчитанной таблички, ведь оно вызывается много-много раз для достаточно малых аргументов и соответственно прилично тормозит счёт, примерно так: binomial(d+1,2) -> if(d<=#table, table[d], binomial(d+1,2)). Да и moebius() можно аналогично оптимизировать.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение29.10.2022, 22:50 


05/09/16
12110
Dmitriy40 в сообщении #1568176 писал(а):
Значит до миллиона не досчитаете, даже до сотни тысяч. И дело не только в медленности gcd или bitand, а в кубической зависимости.

Да, надо признаться, я крупно погорячился. Просто пустой цикл (N=1000) идет у меня 47 секунд. Т.е. просто перебрать все упорядоченные тройки ничего с ними не делая будет 47 секунд, т.е. где-то 3,6 млн. троек в секунду. Проверка троек на взаимную простоту через gcd() добавляет ещё 40 секунд. Ну это же примерно следует и из моего предыдущего поста с таймингами. Таким образом, перебор всех троек не подходит вне зависимости от того, что с ними делается в переборе, да. Другое дело если чисел немного, но они большие, тогда, возможно именно gcd() будет тормозить. Это я тоже проверил, на тройках от $10^{60}$ до $10^{60}+10^3$, время увеличилось с 90 секунд до 140 секунд. Так что gcd() тут не главное что тормозит. Результат, для справки, тоже 83 процента.

-- 29.10.2022, 22:59 --

Dmitriy40 в сообщении #1568176 писал(а):
Почему работает правильно — меня не спрашивайте.

OMG! Гениальные люди... И правда, хоть бы написали почему.

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение30.10.2022, 10:48 
Заслуженный участник
Аватара пользователя


13/08/08
14495
Вот чисто по PARI вопросы. Как наиболее просто считается модуль числа по основанию? Нет ли другого?
Код:
{print(lift(Mod(15,6)));}
3
Как считается If c || нескольких условий? Они по очереди проверяются до первого выполнения? Равносильно ли в смысле времени выполнения
Код:
if (a==1 || b==2 || c==3, N++)
vs
if(a==1, if (b==2, if (c==3, N++)))

Столкнулся с непонятным замедлением. Переписал программку подсчёта доли выкидываемых троек с однородностью по 2,3,5 без функций со скользящими модулями.
Код:
{MA=1;MB=1000;N=0;
i2=0;i3=0;i5=0;
for (i=MA,MB,i2++;if(i2==2, i2=0);i3++;if(i3==3, i3=0);i5++;if(i5==5, i5=0);j2=0;j3=0; j5=0;
  for (j=1,i,j2++;if(j2==2, j2=0);j3++;if(j3==3, j3=0);j5++;if(j5==5, j5=0);k2=0;k3=0;k5=0;
    for (k=1,j,k2++;if(k2==2, k2=0);k3++;if(k3==3, k3=0);k5++;if(k5==5, k5=0);
       if(i2+j2+k2==0 || i3+j3+k3==0 || i5+j5+k5==0,N++);
)));print(floor(100*N/(MB*(MB+1)*(MB+2)/6)))}
16
Без предварительного расчёта массивов. Конечно, много лишних сложений и if-ов на простое равенство. Это тормозит?
Кстати при М=1000 из
167 167 000 троек
27 530 308 удалено по 2,3,5
28 188 452 по НОДу
Спасибо за 15%6

 Профиль  
                  
 
 Re: интерактивный курс: введение в программирование на PARI/GP
Сообщение30.10.2022, 10:57 


05/09/16
12110
gris в сообщении #1568246 писал(а):
Как наиболее просто считается модуль числа по основанию?

Если "модуль числа по основанию" это остаток от [целочисленного] деления числа на основание, то так
? print(15%6)
3


-- 30.10.2022, 11:31 --

gris в сообщении #1568246 писал(а):
Они по очереди проверяются до первого выполнения? Равносильно ли в смысле времени выполнения

|| это ИЛИ, && это И :) так что написанное вами не эквивалентно логически
По идее, должно идти последовательно и не проверять второе если уже невыполнено первое, но я программистам не доверяю и всегда пишу вложенные if.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 810 ]  На страницу Пред.  1 ... 29, 30, 31, 32, 33, 34, 35 ... 54  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group