Природний генератор основного типу


42

Існує досить велика кількість простих генеруючих функцій. В основному всі вони побудовані і ґрунтуються на ситі Ератостена, функції Мебіуса або теоремі Вілсона, і, як правило, неможливо обчислити на практиці. Але є також генератори, які мають дуже просту структуру і були знайдені випадково.

У 2003 році Стівен Вольфрам дослідив клас вкладених рівнянь рецидивів у ході експерименту на комп'ютері в літній школі NKS. Група людей навколо Метью Френка проводила додаткові експерименти та виявила цікаву властивість просто рецидиву

a(n) = a(n-1) + gcd(n,a(n-1))

із початковим значенням a(1) = 7. Різниця a(n) - a(n-1) = gcd(n,a(n-1))завжди здавалася 1 або простим. Перші кілька відмінностей ( OEIS A132199 ):

1, 1, 1, 5, 3, 1, 1, 1, 1, 11, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 3, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 47, 3, 1, 5, 3, ...

Якщо ми опустимо лише 1s, отримаємо таку послідовність ( OEIS A137613 ):

5, 3, 11, 3, 23, 3, 47, 3, 5, 3, 101, 3, 7, 11, 3, 13, 233, 3, 467, 3, 5, 3, 
941, 3, 7, 1889, 3, 3779, 3, 7559, 3, 13, 15131, 3, 53, 3, 7, 30323, 3, ...

Ерік С. Роуланд довів перевагу кожного елемента в цьому списку через кілька років. Як бачите, прайми змішані, а деякі з них з’являються багаторазово. Також було доведено, що послідовність включає нескінченно багато різних прайменів. Крім того, можна припустити, що з'являються всі непарні прайми.

Оскільки цей основний генератор не був побудований, а просто знайдений випадково, основний генератор називається "природним". Але зауважте, що на практиці цей генератор також досить важко обчислити. Як виявляється, просте p з'являється лише після (p–3)/2послідовних 1-х. Тим не менш, реалізація цього основного генератора стане вашим завданням.

Виклик:

Напишіть функцію або програму, яка друкує перші nелементи послідовності A137613(послідовність без 1s). Ви можете прочитати вхідний номер n >= 0через STDIN, аргумент командного рядка, підказку або аргумент функції. Виведіть перші nелементи в будь-якому читаному форматі в STDOUT або поверніть масив або список з цими значеннями.

Це код-гольф. Тому виграє найкоротший код.

Табло:

Ось фрагмент стека для створення як звичайного табло, так і огляду переможців за мовою. Щоб переконатися, що ваша відповідь відображається, будь ласка, почніть свою відповідь із заголовка, використовуючи наступний шаблон Markdown:

# Language Name, N bytes

де N - розмір вашого подання. Якщо ви покращите свій рахунок, ви можете зберегти старі бали у заголовку, прокресливши їх. Наприклад:

# Ruby, <s>104</s> <s>101</s> 96 bytes


1
Поки основний генератор не побудований, ви ефективно впроваджуєте пробний поділ за допомогою рекурсії.
orlp

Якщо a (1) = 7, чому послідовність не починається з 7?
feersum

3
@feersum, оскільки послідовність, про яку ми маємо справу,a(n)-a(n-1)
Малтісен,

Може nбути нуль?
Sp3000

1
@jrenk Не впевнений. Можливо, порахуйте це як 2 байти (оскільки ви видаляєте 2 символи //) та поясніть це у своєму поданні. Якщо хтось не погоджується з вами, ви завжди можете редагувати свою публікацію.
Якубе

Відповіді:



7

Python 3.5.0b1 +, 95 93 байт

Посилання на Python 3.5.0b1 + випуск

import math
def f(k,n=2,a=7,L=[]):x=math.gcd(n,a);return k and f(k-1%x,n+1,a+x,L+1%x*[x])or L

Пряма реалізація рецидиву, що містить:

  • Наш хороший друг 1%x, і
  • math.gcd, на відміну від fractions.gcd.

Що робить 1%x? Побічне питання: де я можу знайти документацію з історії перегляду Python, що включає бета-версії? Edit: Nevermind, знайдено його внизу історії ревізій .
mbomb007

@ mbomb007 Оскільки x >= 1, 1%xповертає 0, якщо x == 1, 1 інакше (використовується для вирішення, чи потрібно додавати xдо списку)
Sp3000,

5

Джулія, 110 байт

n->(a(n)=(n1&&(n==1?7:a(n-1)+gcd(n,a(n-1))));i=2;j=0;while j<n x=a(i)-a(i-1);x>1&&(j+=1;println(x));i+=1end)

Безголівки:

function a(n::Int)
    n  1 && (n == 1 ? 7 : a(n-1) + gcd(n, a(n-1)))
end

function f(n::Int)
    i = 2;
    j = 0;
    while j < n
        x = a(i) - a(i-1)
        if x > 1
            j += 1
            println(x)
        end
        i += 1
    end
end

Ух, прекрасний 8 к, приємно: D
бета-розпад

1
Використовуйте n<2замість n==1. Крім того, якщо ви дивитесь вперед замість назад, ви можете використовувати i=1і x=a(i)-a(i+=1), і потім, println(-x)і -x>1для виправлення негативу, тим самим уникаючи необхідності окремого приросту i. І це три байти, в той час >=як два ... але тоді, ви можете використовувати, n<1||()а не n>=1&&()... і все ж, це навіть не потрібно в першу чергу (киньте умовне, n ніколи не буде менше 1). Вам також не потрібні самі зовнішні дужки при визначенні (n). За допомогою цих змін вам слід принаймні знизитися до 97 байт.
Глен О

5

PHP, 101 96 99 98 77 72 байт

<?for(;2>$t=gmp_strval(gmp_gcd(~++$i,7+$e+=$t))or$argv[1]-=print"$t ";);


Використання:
Зателефонуйте до сценарію з аргументом: php -d error_reporting=0 script.php 30
Якщо ви хочете перевірити його, вам потрібно відмітити його ;extension=php_gmp.dllв php.ini
-> extension=php_gmp.dll
Чи слід додати розширення до моєї кількості байтів? Будь-які думки?


Журнал:
Збережено 3 байти завдяки Ісмаелю Мігелю.
Збережено 26 байт завдяки приміту.


1
Ви можете скоротити свій початковий тег до <?та вилучити визначення $j.
Ісмаїл Мігель

1
Так, це рахується. Але ви можете видалити цей новий рядок. Що дозволить заощадити 1-2 байти, залежно від того, як ви порахували розмір коду.
Ісмаїл Мігель

1
Незначні вдосконалення: використовувати <в $j<=$argv[1](друкує занадто багато) (-1). Залиште $eнеініціалізовані, використовуйте $e+7натомість (-3). Використовуйте for(;;)замість while(), використовуючи до- і пост-вирази (-2). Замініть echo$t.' ';$j++на $j+=print"$t ", опустіть дужки (-3). Замініть if($t>1)на 2>$t||(-2). Змішайте завдання $tз умовним, перемикачем ||для or, падіння дужки (-5). Перемістіть $argv[1]до $jприросту, перемістіть весь вираз до forумовного (-2). Змініть >=$j+=printна -=print(-3). Крок за кроком: codepad.org/s6LNSPSM
primo

1
@primo дякую за приємне пояснення! Я не знала, що можу все це зробити.
jrenk

1
Ще кілька: комбінуйте $e+7з $e+=$t(-2). Залиште $iнеініціалізовані, використовуйте ~++$iнатомість (-3). codepad.org/fDIImajp
primo

4

Haskell, 51 байт

d=zipWith gcd[2..]$scanl(+)7d
f=($filter(>1)d).take

Зауважте, що fце функція, яка повертає перші n елементів.

Замість того, щоб обчислювати, a(n)а потім опрацьовувати відмінності, ми обчислюємо відмінності d(n)та підсумовуємо їх, щоб отримати a(n). (Незнайомі з Haskell можуть протестувати, що нам потрібно a(n)спочатку для того, щоб отримати d(n), але, звичайно, ледача оцінка обходить нас цією проблемою!)

Безголівки:

a = scanl (+) 7 d        -- yielding a(n) = 7 + d(1) + d(2) + ... + d(n-1)
d = zipWith gcd [2..] a  -- yielding d(n) = gcd(n+1, a(n))

f n = take n $ filter (> 1) d -- get rid of 1s and take the first n

4

Pyth, 30 байт

Дуже погано гольф, може бути значно зменшений. Визначає рекурсивну функцію спереду, фільтрує .first-n, а потім відображає різницю.

L?tb+KytbibK7m-yhdyd.ft-yhZyZQ

Спробуйте це онлайн .


Це дає невірні результати дляn = 0
Sp3000

2
@ Sp3000 - помилка в Pyth. Я поставлю запит на тягу.
Малтісен

Знайдено та виправлено помилку - виправлення буде реалізовано, як тільки github перестане бути DDoS'd.
isaacg

1
Ось воно: meta.codegolf.stackexchange.com/questions/5318 / ... . Особисто я вважаю виправлення помилок у мовах програмування як відповідь
Thomas Weller

2
@ThomasWeller Це свого роду досягло цілої мови ...
isaacg

4

Джулія, 69 67 байт

n->(i=1;a=7;while n>0 x=gcd(i+=1,a);a+=x;x>1&&(n-=1;println(x))end)

Це просте ітеративне рішення проблеми. x- це різниця (яка є gcd), а потім я оновлюю a, додаючи x.


Я думаю, що він друкує A231900 .
алефальфа

@alephalpha - я думаю, я бачу помилку. Легко фіксується. Навіть поголив два байти в процесі.
Глен О

3

JavaScript (ES6), 91

Рекурсивна gcd, ітеративна основна функція. Не так швидко.

Звичайна примітка: протестуйте фрагмент на будь-якому веб-переглядачі, сумісному з EcmaScript 6 (особливо це не Chrome, а не MSIE. Я протестував на Firefox, Safari 9 може піти)

F=m=>{
  for(G=(a,b)=>b?G(b,a%b):a,o=[],p=7,n=1;m;d>1&&(o.push(d),--m))
    p+=d=G(++n,p);
  return o
}

O.innerHTML=F(+I.value)
<input id=I value=10><button onclick='O.innerHTML=F(+I.value)'>-></button>
<pre id=O></pre>


3

Haskell, 74 71 66 байт

f=($filter(>1)$tail>>=zipWith(-)$scanl(\x->(x+).gcd x)7[2..]).take

Скориставшись трюком тут: https://codegolf.stackexchange.com/a/39730/43318 , і зробив безпредметним.

(Попередній: 71 байт)

a=scanl(\x->(x+).gcd x)7[2..]
f m=take m$filter(>1)$zipWith(-)(tail a)a

Спочатку складіть послідовність а, а потім візьміть відмінності.

(Попередній: 74 байти)

f m=take m$filter(>1)$map snd$scanl(\(x,d)->(\y->(x+y,y)).gcd x)(7,1)[2..]

Стандартні функції списку плюс розумне використання лямбда-функції. Зауважте, це на 1 байт коротше, ніж більш очевидно

g m=take m$filter(>1)$map snd$scanl(\(x,d)n->(x+gcd x n,gcd x n))(7,1)[2..]

Якщо ми не зараховуємо імпорт, я можу знизити це до 66.

import Data.List
h m=take m$filter(>1)$snd$mapAccumL(\x->(\y->(x+y,y)).gcd x)7[2..]

3

PARI / GP, 60 байт

a(n)=a=7;i=1;while(n,if(1<d=gcd(i+=1,a),n-=1;print(d));a+=d)

Більш-менш прямо з визначення a (n) - a (n-1) = gcd (n, a (n-1))

Вихід для a(20):

5
3
11
3
23
3
47
3
5
3
101
3
7
11
3
13
233
3
467
3

2

C ++, 193 182 180 172 байт

Спасибі @Jakube - збережено 8 байт на виході.

int g(int a,int b){return a==b?a:a>b?g(b,a-b):g(a,b-a);}void f(int *r,int n){int m=1,i=0,a=7,b;while(i<n){b=g(a,++m);if(b>1){r[i]=b;++i;}a+=b;}}int main(){int r[6];f(r,6);}

Можливо, ви можете зберегти кілька байтів, визначивши функцію f, яка повертає масив з результатами. Таким чином ви можете видалити включення, scanf та друк.
Якубе

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.