Повторне! Факторії!


34

Не плутати з Find the faorial!

Вступ

Фактор цілого числа nможе бути обчислений

н!=н×(н-1)×(н-2)×(...)×2×1

Це порівняно просто і нічого нового. Однак факториали можна поширити на подвійні , такі, що для парних чисел, і для непарних чисел. Але ми не обмежені подвійними фабриками. Наприклад, n !!! = n \ раз (n-3) \ раз (n-6) \ раз (...) \ раз6 \ раз 3 або n !!! = n \ раз (n-3) \ раз ( n-6) \ times (...) \ times5 \ times2 or n !!! = n \ times (n-3) \ times (n-6) \ times (...) \ times4 \ times1, залежно від вихідне значення.

н!!=н×(н-2)×(н-4)×(...)×4×2
n!!=n×(n2)×(n4)×(...)×3×1
n!!!=n×(n3)×(n6)×(...)×6×3
n!!!=n×(n3)×(n6)×(...)×5×2
n!!!=n×(n3)×(n6)×(...)×4×1

Підсумовуючи:

н!(к)={1якщо н=0някщо 0<нкн((н-к)!(к))якщо н>к
де
н!(к)=н!!к
Або простою англійською мовою: Віднімайте фактичний підрахунок від базового числа кілька разів і множте всі отримані додатні цілі числа.

Змагання

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

Вхідні дані

Або

  • Рядок, що містить невід'ємне ціле число базового десяти, а потім 1 або більше знаків оклику. Наприклад , "6!"чи "9!!"або "40!!!!!!!!!!!!!!!!!!!!".

або

  • Одні і ті ж значення, представлені двома цілими числами: одне негативне базове значення та одне додатне значення, що представляє фактичне число. Це можна зробити у будь-якому форматі із стандартних правил вводу / виводу.

Вихідні дані

Результат зазначеного розрахунку.

Зауваження виклику

  • 0!дорівнює 1за визначенням. Ваш код повинен це враховувати.
  • Кількість факторів обмежена
    0<fаcтоriал cоунтбасе vалуе
    поза цим діапазоном, ви можете виводити все, що завгодно. Крім того 0!, що є єдиним винятком із цього правила.

Приклади

Input                              Output

3!!!                               3
0!                                 1
6!                                 720
9!!                                945
10!!!!!!!!                         20
40!!!!!!!!!!!!!!!!!!!!             800
420!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  41697106428257280000000000000000

Спробуйте це з невтішленою реалізацією Python: Спробуйте в Інтернеті!

Загальні зауваження


6
Перелік прикладів, 0!але зауваження, що стосуються викликів, говорить про те, що базовий показник буде меншим або рівним базовій.
Джонатан Аллан

1
Чи не 3 !!! бути нулем? n * (n-3) = 3 * (3-3) = 0.
ouflak

2
@ouflak Якщо це працює як 1!, не дуже. Це більше як 1! = 1. 2 !! = 2. 3 !!! = 3. Немає розрахунку, тому що ви в кінці рекурсивності. Ні 0 в продуктах, інакше кожна фабрика знизиться до 0.
В. Куртуа

4
3!!!!!!!не повинно бути невизначеним - він повинен просто дати відповідь 3. Це те саме, що 1!!=1(не визначено). Також ваша специфікація вказує, що завжди буде хоча б одна !, тому перший приклад 3не відповідає специфікації.
Грег Мартін

3
@ FabianRöling: Але це не те, що це. Це не (3!)!натомість це вилучення термінів з факторіалу. Це оманливе ім'я; Я припускав, що припускає, що це функція "Фактор" буде застосовуватися неодноразово в ланцюжку, і мені довелося уважно прочитати, щоб побачити, що це насправді. На щастя, це питання це чітко пояснює. Кращою назвою може бути кроковий факторний або ступінчастий фактор чи щось таке.
Пітер Кордес

Відповіді:



13

ArnoldC , 702 698 634 байт

LISTEN TO ME VERY CAREFULLY f
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE n
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE p
GIVE THESE PEOPLE AIR
HEY CHRISTMAS TREE r
YOU SET US UP 1
HEY CHRISTMAS TREE c
YOU SET US UP 0
STICK AROUND n
GET TO THE CHOPPER r
HERE IS MY INVITATION r
YOU'RE FIRED n
ENOUGH TALK
GET TO THE CHOPPER n
HERE IS MY INVITATION n
GET DOWN p
ENOUGH TALK
GET TO THE CHOPPER c
HERE IS MY INVITATION 0
LET OFF SOME STEAM BENNET n
ENOUGH TALK
BECAUSE I'M GOING TO SAY PLEASE c
GET TO THE CHOPPER n
HERE IS MY INVITATION 0
ENOUGH TALK
YOU HAVE NO RESPECT FOR LOGIC
CHILL
I'LL BE BACK r
HASTA LA VISTA, BABY

Спробуйте в Інтернеті!

Переведено на псевдокод:

f(n,p) {
  r=1;
  c=0;
  while (n) {
    r=r*n;
    n=n-p;
    c=n<0;
    if (c) n=0;
  }
  return r;
}

Примітка: ArnoldC має лише один тип даних: 16-бітове ціле число. Отже, я не можу перевірити цю 420!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!справу.


Просто цікаво про ваш psuedocode. Для чого змінна 'c'?
ouflak

@ouflak я пару разів відредагував свою відповідь і забув її. cМінлива фактично зберігає значення порівняння між nі 0.
Чарлі

+1, і я запозичив його (мінус "c") для своєї відповіді на LUA.
ouflak

12

Желе , 4 байти

RṚmP

Спробуйте в Інтернеті!

Як? Враховуючи і , він спочатку генерує діапазон (with ), потім з ним зберігає кожен елемент цього діапазону (так ), і, нарешті, примножує їх за допомогою .нкн,,1RṚmкгон,н-к,н-2к,,н-н/ккP


Добре працює, і в кінці кінців так просто. Я взагалі не знаю Джеллі, але принаймні це добре виглядає :)
В. Куртуа

1
@ V.Courtois Даючи і , він спочатку генерує діапазон (з ), потім з ним зберігає кожен елемент цього діапазону (так ) і, нарешті, примножує їх за допомогою . Просто прямолінійний підхід. Редагувати: Це пояснення я додав у відповідь. нкн,,1RṚmкгон,н-к,н-2к,,н-н/ккP
Містер Xcoder

Ха-ха, дуже дякую Одного разу я можу захотіти покататися на цій мові, тому мені доведеться вивчити ці монади, діади тощо
В. Куртуа

Альтернативні , який виглядає як CJam: r1mP.
Ерік Аутгольфер

1
@KyeWShi Jelly має свою кодову сторінку , тому кожен із 256 символів, які вона містить, кодується як 1 байт.
Містер Xcoder

8

APL (Dyalog Extended) , 7 байт SBCS

Функція анонімного мовчання. Вважається [n,b]аргументом.

×/-\…1¨

Спробуйте в Інтернеті!

 по одному для кожного елемента аргументу; [1,1]

-\ сукупна різниця; [n,n-b]

 діапазон, використовуючи другий елемент лівого аргументу як індикатор кроку, наприклад, [9,7]продовжує з5

×/ продукт


7

Haskell , 21 байт

n%a=product[n,n-a..1]

Спробуйте в Інтернеті!

Поєднання вбудованої функції продукту із перерахуванням ступінчастого діапазону перемагає те, що я міг кодувати рекурсивно (навіть із недоліками, економлячи байт).

22 байти

n%a|n<1=1|m<-n-a=n*m%a

Спробуйте в Інтернеті!

Ось рішення, яке приймає вклад у такому вигляді рядка 9!!, що, на мою думку, цікавіше.

42 байти

(\[(n,a)]->product[n,n-length a..1]).reads

Спробуйте в Інтернеті!


2
Я думаю, ви могли б скоротити рекурсивне рішення доn%a|n<1=1|m<-n-a=n*m%a
провалу



5

Пробіл , 91 байт

[S S S T    N
Push_1][S N
S _Duplicate_1][S N
S _Duplicate_1][T   N
T   T   _Read_STDIN_as_integer_(base)][T    T   T   _Retrieve_base][S S S N
_Push_0][T  N
T   T   _Read_STDIN_as_integer_(factorial)][N
S S N
_Create_Label_LOOP][S N
S _Duplicate_base][S S S T  N
_Push_1][T  S S T   _Subtract][N
T   T   S N
_If_negative_jump_to_Label_PRINT_RESULT][S N
S _Duplicate_base][S T  S S T   S N
_Copy_0-based_2nd_(result)][T   S S N
_Multiply][S N
T   _Swap_top_two][S S S N
_Push_0][T  T   T   _Retrieve_factorial][T  S S T   _Subtract][N
S N
N
_Jump_to_Label_LOOP][N
S S S N
_Create_Label_PRINT_RESULT][S N
N
_Discard_top][T N
S T _Print_result_as_integer]

Букви S(пробіл), T(вкладка) та N(новий рядок) додаються лише як підкреслення.
[..._some_action]додано лише як пояснення.

Спробуйте його в режимі он-лайн (лише з просторами, вкладками та новими рядками).

Пояснення в псевдокоді:

Integer result = 1
Integer base = STDIN as integer
Integer factorial = STDIN as integer
Start LOOP:
  If(base <= 0):
    Call function PRINT_RESULT
  result = result * base
  base = base - factorial
  Go to next iteration of LOOP

function PRINT_RESULT:
  Print result as integer to STDOUT


4

Perl 6 , 22 байти

{[*] $^a,*-$^b...^1>*}

Спробуйте в Інтернеті!

Анонімний кодовий блок, який повертає добуток діапазону, починаючи з першого вводу, зменшуючи на другий до нижнього 1, виключаючи останнє число. Це працює для 0, оскільки базовий випадок зменшення на продукт дорівнює 1, тому вихід 1.


4

05AB1E , 10 8 7 байт

ݦRIιнP

Введіть як два відокремлені входи: перший вхід base; друге введення factorial.

Спробуйте в Інтернеті або перевірте всі тестові справи .

-2 байти завдяки @ Mr.Xcoder .
-1 байт завдяки @JonathanAllan .

Пояснення:

Ý        # Create a list in the range [0, (implicit) base-input]
 ¦       # And remove the first item to make it the range [1, base]
         # (NOTE: this is for the edge case 0. For the other test cases simply `L` instead
         #  of `ݦ` is enough.)
  R      # Reverse this list so the range is [base, 1]
   Iι    # Uninterleave with the second input as step-size
         #  i.e. base=3, factorial=7: [[3],[2],[1],[],[],[],[]]
         #  i.e. base=10, factorial=8: [[10,2],[9,1],[8],[7],[6],[5],[4],[3]]
         #  i.e. base=420, factorial=30: [[420,390,360,...,90,60,30],[419,389,359,...],...]
     н   # Only leave the first inner list
      P  # And take the product of its values
         # (which is output implicitly as result)

Оригінальна відповідь на 10 байт :

L0KD¤-IÖÏP

Введіть як два відокремлені входи: перший вхід base; друге введення factorial.

Спробуйте в Інтернеті або перевірте всі тестові справи .

Пояснення:

L           # Create a list in the range [1, (implicit) base-input]
 0K         # Remove all 0s (edge case for input 0, which will become the list [1,0])
   D        # Duplicate this list
    ¤       # Get the last value (without popping)
            # (could also be `Z` or `¹` for max_without_popping / first input respectively)
     -      # Subtract it from each item in the list
      IÖ    # Check for each if they're divisible by the second factorial-input
        Ï   # In the list we copied, only leave the values at the truthy indices
         P  # And take the product of those
            # (which is output implicitly as result)

1
Цей 6-byter: LR²ιнP( ! Спробуйте його в Інтернеті ) працює для кожного тестового випадку, за винятком 0.
г Xcoder

Але я здогадуюсь, що 0 випадок можна зафіксувати щонайбільше в 2 байтах. Якщо ви знайдете спосіб виправити це, ви можете скористатися :) РЕДАКТУВАТИ: Можливо, LR²ιн0KPна 8 байт?
Містер Xcoder

@ Mr.Xcoder Приємна відповідь! Ніколи навіть не використовував непереплутування із заданим кроком. :)
Кевін Круїссен

0KПотрібно бути непотрібним, оскільки 0!це недійсне введення специфікацією (навіть якщо це було включено в приклади) - я коментував це.
Джонатан Аллан

1
... а якщо 0! є у вхідному домені, ݦRXιнPзберігається байт.
Джонатан Аллан

4

машинний код x86-64, 12 байт

Цей же машинний код робить те саме, що і в 32-бітному режимі, і для 16-бітних цілих чисел у 16-бітному режимі.

Це функція, яка викликається з арг n=RCX, k=ESI. 32-бітове повернене значення в EAX.

Зателефонувавши з C за допомогою системи V86 x86-64, яка викликає конвенцію з фіктивними аргами, щоб отримати справжні аргументи в потрібні регістри. uint32_t factk(int, uint32_t k, int, uint64_t n); Я не міг просто використовувати Windows x64, оскільки 1- mulоперандний клобує RDX, і ми не хочемо, щоб REX-префікси мали доступ до R8 / R9. nне повинно бути сміття у високих 32 бітах, тому JRCXZ працює, але крім цього, це все 32-розрядні.

Перелік NASM (відносна адреса, код машини, джерело)

 1                         factk:
 2 00000000 6A01             push 1
 3 00000002 58               pop rax             ; retval = 1
 4 00000003 E306             jrcxz  .n_zero      ; if (n==0) return
 5                         .loop:                ; do {
 6 00000005 F7E1              mul   ecx            ; retval *= n  (clobbering RDX)
 7 00000007 29F1              sub   ecx, esi       ; n -= k
 8 00000009 77FA              ja   .loop         ; }while(sub didn't wrap or give zero)
 9                         .n_zero:
10 0000000B C3               ret

0xc = 12 байт


Або 10 байт, якщо нам не потрібно було обробляти n=0спеціальний корпус, залишаючи без уваги jrcxz.

У стандартному факторіалі ви використовуєте loopзамість sub / ja для збереження 2 байтів, але в іншому випадку точно такий же код.


Випробувальний абонент, який проходить argcяк kіз nжорстким кодом.

align 16
global _start
_start:
  mov  esi, [rsp]
;main:
  mov  ecx, 9
  call factk

  mov  esi, eax
  mov  edx, eax
  lea  rdi, [rel print_format]
  xor  eax, eax
extern printf
  call printf
extern exit
  call exit

section .rodata
print_format: db `%#x\t%u\n`

```

3

APL (Dyalog Unicode) , 11 байт SBCS

Функція анонімного мовчазного виправлення. Приймається nяк правий аргумент і bяк лівий аргумент.

×/1⌈⊢,⊢-×∘⍳

Спробуйте в Інтернеті!

×∘⍳ кратно bпо ɩ ntegers 1 черезn

⊢- відняти, що від n

⊢, подавати n

1⌈ максимум один і кожен із них

×/ продукт



3

Мова Вольфрама (Mathematica) , 22 21 байт

1##&@@Range[#,1,-#2]&

Спробуйте в Інтернеті!

-1 спасибі attinat: Times --> 1##&

Пояснення: використовуйте Rangeдля складання списку значень {n, n-k, n-2k, n-3k, ...}, зупиняючись перед тим, як перейти нижче 1 (тобто, зупиняючись прямо праворуч). Потім помножте всі числа в цьому списку на Times(або 1##&).


-1 байт з 1##&замістьTimes
attinat

3

Java 10, 44 байти

f->b->{int r=1;for(;b>0;b-=f)r*=b;return r;}

Приймає факторіал як перший вхід, базу - як другий.

Спробуйте в Інтернеті.

Це вище не працює для найбільшого тестового випадку через обмежений цілий діапазон (32 біт). Щоб виправити це , ми можемо використовувати BigIntegers, який по збігу є саме подвійний розмір - 88 79 байт :

f->b->{var r=f.ONE;for(;b.signum()>0;b=b.subtract(f))r=r.multiply(b);return r;}

-9 байт завдяки @ OlivierGrégoire .

Спробуйте в Інтернеті.

Пояснення:

f->b->{       // Method with two integer parameters and integer return-type
  int r=1;    //  Result-integer, starting at 1
  for(;b>0;   //  Loop as long as the base is still larger than 0
      b-=f)   //    After every iteration: decrease the base by the factorial
    r*=b;     //   Multiply the result by the base
  return r;}  //  Return the result


@ OlivierGrégoire Np, і дякую! :)
Кевін Крейссен



2

MathGolf , 7 6 байт

╙╒x%ε*

Спробуйте в Інтернеті!

Знайшли розумний спосіб впоратися з 0! не змінюючи інших тестових випадків. Приймає дані як k n(зворотний порядок), що допомагає при неявному вискакуванні.

Пояснення

╙        maximum of two elements (pops largest of k and n,
         which is n for every valid case except 0!, where 1 is pushed)
 ╒       range(1,n+1)
  x      reverse int/array/string
   %     slice every k:th element
    ε*   reduce list with multiplication

2

Attache , 21 19 байт

${x<y∨x*$[x-y,y]}

Спробуйте в Інтернеті! Досить пряма рекурсивна реалізація. (Примітка. По trueсуті 1, оскільки його можна використовувати в арифметичних операціях як 1.) Це одна з небагатьох програм, які я написав для цього сайту, де використання оператора unicode зберігає байти (1, якщо бути точним).

Альтернативи

20 байт: ${x<y or x*$[x-y,y]}

21 байт: Prod@${{_%y=x%y}\1:x}

27 байт: ${x*[`1,$][x>y][x-y,y]∨1}

27 байт: ${If[x>y,x*$[x-y,y],_or 1]}

27 байт: ${x*[`1,$][x>y][x-y,y]or 1}

29 байт: ${If[x>y,x*$[x-y,y],_+not _]}


2

Іржа , 92 73 61 байт

fn f(n:i128,k:i128)->i128{if n<=0{return 1}return n*f(n-k,k)}

Я тільки починаю вивчати іржу, тому впевнений, що це може бути коротшим. Буде оновлюватися, коли я дізнаюся. Повертане значення повинно бути таким i128, щоб обчислити останній тест.

Правка: Рекурсія коротша.

Спробуйте в Інтернеті!

Ви можете додати власний тест або відредагувати один із вже існуючих.


2

q , 59 57 55 53 байт

{prd 2+(&)1_i=last i:("J"$x(&)not[n])#(!)sum n:"!"=x}

пояснення:

q)x:"12!!" / let our input be 12!!, assign to x
q)sum n:"!"=x / count "!"s
2i
q)(!)sum n:"!"=x / (!)m -> [0,m)
0 1
q)("J"$x(&)not[n]) / isolate the number in input
12
q)("J"$x(&)not[n])#(!)sum n:"!"=x / x#y means take x items from list y, if x>y, circle around
0 1 0 1 0 1 0 1 0 1 0 1
q)i:("J"$x(&)not[n])#(!)sum n:"!"=x / assign to i
q)i
0 1 0 1 0 1 0 1 0 1 0 1
q)(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / take last elem of i and see which are equal in i
010101010101b
q)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / drop first elem
10101010101b
q)(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / indices of 1b (boolean TRUE)
0 2 4 6 8 10
q)2+(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / add 2 across array
2 4 6 8 10 12
q)prd 2+(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / product across array
46080

тут також є версія в k (така ж логіка), 42 41 байт

{*/2+&1_i=last i:("J"$x@&~:n)#!+/n:"!"=x}

Ласкаво просимо на сайт! До вашої публікації я додав форматування коду, яке можна виконати з чотирьох пробілів перед рядком або додавши його до потрійних зворотних посилань.
Пшеничний майстер

@ SriotchilismO'Zaic спасибо :-)
каракулі

1
Я рекомендую додати пояснення та, можливо, посилання на онлайн-перекладача, наприклад TIO . Відповіді, що стосуються лише коду, зазвичай автоматично позначаються як низька якість.
mbomb007

@ mbomb007 цікаво. чи є відповіді на позначення бота? що відбувається з низькоякісними поданнями? я скоро оновлю!
скраб

Так, є бот. StackExchange використовує ботів для пошуку потенційного спаму та низької якості відповідей. Люди з достатньо високою репутацією можуть переглядати Чергу огляду. meta.stackexchange.com/a/161391/285610
mbomb007


1

Сітківка , 66 байт

^0
1
\d+
*!,
+`(!+)(!+),\1$
$1$2,$2,$1
!+$
1
+`(!+),(\d+)
$.($2*$1

Спробуйте в Інтернеті! Посилання включає більш швидкі тестові випадки. Знімає цифри без знаків оклику. Пояснення:

^0
1

Виправити 0!.

\d+
*!,

Перетворити nв одинарний і додати роздільник.

+`(!+)(!+),\1$
$1$2,$2,$1

Кілька разів відняти kз в nтой час n>k, і зібрати результати.

!+$
1

Замініть kна 1(десятковим).

+`(!+),(\d+)
$.($2*$1

Помножте на кожне проміжне значення по черзі, перетворюючи на десятковий.




1

Четвертий (gforth) , 50 байт

: f 1 1 2over / 1+ 0 do 2over i * - 1 max * loop ;

Спробуйте в Інтернеті!

Пояснення коду

: f                \ start a new word definition
  1 1              \ add placeholder and accumulator to stack
  2over / 1+       \ get the number of times to run the loop (num/factorial + 1)
  0 do             \ start loop from 0 to num/factorial
    2over          \ copy num and factorial to the top of the stack
    i * -          \ get the current number to multiply by (num - factorial * i)
    1 max          \ make sure it can't be 0 or negative [set to 1 if it is]
    *              \ multiply accumulator by result
  loop             \ end loop
;                  \ end the word definition           



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