Liczba obfita to dowolna liczba, w której suma jej właściwych dzielników jest większa niż liczba pierwotna. Na przykład właściwymi dzielnikami 12 są:
1, 2, 3, 4, 6
I sumując te wyniki w 16. Ponieważ 16 jest większe niż 12, 12 jest obfite. Zauważ, że nie obejmuje to „liczb doskonałych”, np. Liczb, które są równe sumie jego właściwych dzielników, takich jak 6 i 28.
Twoim zadaniem na dziś jest napisanie programu lub funkcji, która określa, czy liczba jest duża, czy nie. Twój program powinien przyjąć jedną liczbę całkowitą jako dane wejściowe i wygenerować wartość prawdy / fałszu w zależności od tego, czy jest ona obfita, czy nie. Możesz założyć, że dane wejściowe zawsze będą prawidłowe i większe od 0, więc w przypadku złych danych wejściowych niezdefiniowane zachowanie jest w porządku.
Możesz wziąć swoje dane wejściowe i wyjściowe w dowolnym rozsądnym formacie, na przykład dopuszczalne byłyby STDIN / STDOUT, pliki lub argumenty / zwracane wartości.
Dla porównania, oto obfite liczby do 100:
12,
18,
20,
24,
30,
36,
40,
42,
48,
54,
56,
60,
66,
70,
72,
78,
80,
84,
88,
90,
96,
100
Więcej można znaleźć na A005101
Ponieważ jest to gra w golfa kodowego , standardowe luki są odrzucane i spróbuj napisać możliwie najkrótszy kod w dowolnym języku, który wybierzesz!
źródło
Odpowiedzi:
ECMAScript Regex,
1085855597536511508504 bajtówDopasowywanie obfitych liczb w wyrażeniu regularnym ECMAScript jest zupełnie inną bestią niż w praktycznie każdym innym smaku wyrażenia regularnego. Brak odwołań do przodu / zagnieżdżonych wstecz lub rekurencji oznacza, że nie można bezpośrednio policzyć ani zachować bieżącej sumy czegokolwiek. Brak wyglądu sprawia, że często jest to wyzwanie, nawet mając wystarczająco dużo miejsca do pracy.
Do wielu problemów należy podchodzić z zupełnie innej perspektywy, a będziesz się zastanawiać, czy w ogóle można je rozwiązać. Zmusza cię to do rzucenia znacznie szerszej sieci w celu znalezienia, które matematyczne właściwości liczb, z którymi pracujesz, mogą być wykorzystane do rozwiązania konkretnego problemu.
Na przełomie marca i kwietnia 2014 roku opracowałem rozwiązanie tego problemu w wyrażeniu regularnym ECMAScript. Na początku miałem wszelkie powody, by podejrzewać, że problem jest całkowicie niemożliwy, ale potem matematyk teukon naszkicował pomysł, który zachęcał do tego, by mimo wszystko wyglądał na rozwiązalny - ale wyjaśnił, że nie ma zamiaru tworzyć wyrażenia regularnego ( rywalizował / współpracował ze mną przy konstruowaniu / grze w golfa wcześniejszych wyrażeń regularnych, ale do tego momentu osiągnął swój limit i był zadowolony z ograniczenia dalszego udziału w teoretyzowaniu).
Podobnie jak w przypadku mojego wyrażenia regularnego opublikowanego kilka dni temu, ostrzegam: Bardzo polecam nauczenie się rozwiązywania pojedynczych problemów matematycznych w wyrażeniu regularnym ECMAScript. To była dla mnie fascynująca podróż i nie chcę zepsuć jej nikomu, kto mógłby potencjalnie chcieć spróbować samemu, szczególnie tym, którzy interesują się teorią liczb. Zobacz ten post, aby uzyskać listę zalecanych problemów oznaczonych spoilerem do rozwiązania jeden po drugim.
Więc nie czytaj dalej, jeśli nie chcesz, aby zepsuła ci się jakaś głęboka, jednoargumentowa magia wyrażeń regularnych . Mój poprzedni post był tylko małym gustem. Jeśli chcesz spróbować samodzielnie odkryć tę magię, zdecydowanie polecam zacząć od rozwiązania niektórych problemów z wyrażeniem regularnym ECMAScript, jak opisano w linku powyżej.
Przed wysłaniem mojego ECMAScript regex, myślałem, że dobrze byłoby, aby analizować Martina Endera .NET rozwiązanie czystego regex ,
^(?!(1(?<=(?=(?(\3+$)((?>\2?)\3)))^(1+)))*1$)
. Okazuje się, że zrozumienie tego wyrażenia regularnego jest bardzo proste i jest elegancki w swojej prostocie. Aby zademonstrować kontrast między naszymi rozwiązaniami, oto skomentowana i ładnie wydrukowana (ale niezmodyfikowana) wersja jego wyrażenia regularnego:Wypróbuj .ge regex online
Teraz wróć do mojego wyrażenia regularnego ECMAScript. Po pierwsze, tutaj jest w surowym formacie, bez białych znaków i bez komentarzy:
^(?=(((?=(xx+?)\3+$)(x+)\4*(?=\4$))+(?!\3+$)(?=(xx(x*?))\5*$)x)(x+))(?=\1(x(x*))(?=\8*$)\6\9+$)(?=(.*)((?=\8*$)\5\9+$))(?=(x*?)(?=(x\11)+$)(?=\12\10|(x))(x(x*))(?=\15*$)(?=\11+$)\11\16+$)(?=(x(x*))(?=\17*$)\7\18+$)((?=(x*?(?=\17+$)(?=\17+?(?=((xx(x*))(?=\18+$)\22*$))(x+).*(?=\17$)\24*(?=\24$)(?!(xx+)\25*(?!\22+$)\25$)\22+$)((?=(x\7)+$)\15{2}\14|)))(?=.*(?=\24)x(x(x*))(?=\28*$)\23\29*$)(?=.*(x((?=\28*$)\22\29+$)))(.*(?!\30)\20|(?=.*?(?!x\20)(?=\30*$)(x(x*))(?=\33*$)(?=\31+$)\31\34+$).*(?=\33\21$)))+$
(zmień
\14
na\14?
na kompatybilność z PCRE, .NET i praktycznie każdym innym wyrażeniem regularnym, który nie jest ECMAScript)Wypróbuj online!
Wypróbuj online! (szybsza, 537 bajtowa wersja wyrażenia regularnego)
A teraz krótkie streszczenie tej historii.
Na początku było dla mnie bardzo nieoczywiste, że w ogóle możliwe było dopasowanie liczb pierwszych. I po rozwiązaniu tego, to samo dotyczyło potęg 2., a następnie potęg liczb zespolonych. A potem idealne kwadraty. I nawet po rozwiązaniu tego, generalizacja mnożenia wydawała się początkowo niemożliwa.
W pętli ECMAScript można śledzić tylko jedną zmieniającą się liczbę; liczba ta nie może przekraczać wartości wejściowej i musi maleć z każdym krokiem. Moje pierwsze wyrażenie regularne dla dopasowania poprawnych instrukcji mnożenia A * B = C wynosiło 913 bajtów i pracowałem przez faktoryzację A, B i C w ich liczbach pierwszych - dla każdego czynnika pierwszego, wielokrotnie dzielę parę głównych współczynników mocy A i C przez swoją podstawową podstawę, aż ta odpowiadająca A osiągnie 1; ta odpowiadająca C jest następnie porównywana z pierwszym współczynnikiem mocy B. Te dwie moce tej samej liczby pierwszej zostały „zmultipleksowane” w jedną liczbę poprzez dodanie ich razem; byłoby to zawsze jednoznacznie rozdzielne przy każdej kolejnej iteracji pętli, z tego samego powodu, dla którego działają systemy liczbowe pozycyjne.
Mnożymy do 50 bajtów przy użyciu zupełnie innego algorytmu (do którego Teukon i ja mogliśmy dojść niezależnie, chociaż zajęło mu to tylko kilka godzin i poszedł od razu, podczas gdy zajęło mi to kilka dni, nawet po tym, jak było zwróciłem uwagę, że istnieje krótka metoda): dla A ≥B, A * B = C, jeśli występuje, tylko jeśli C jest najmniejszą liczbą, która spełnia C0 mod A i C≡B mod A-1. (Dogodnie, wyjątek A = 1 nie wymaga specjalnej obsługi w wyrażeniach regularnych, gdzie 0% 0 = 0 daje dopasowanie.) Po prostu nie mogę się pogodzić z tym, jak fajnie jest, że taki elegancki sposób mnożenia istnieje w takim minimalny smak wyrażenia regularnego. (A wymaganie A≥B można zastąpić wymogiem, że A i B są podstawowymi mocami o tej samej mocy. W przypadku A≥B można to udowodnić za pomocą twierdzenia o reszcie chińskiej.)
Gdyby okazało się, że nie ma prostszego algorytmu do mnożenia, znaczna liczba wyrażeń regularnych prawdopodobnie byłaby rzędu dziesięciu tysięcy bajtów (nawet biorąc pod uwagę, że wykorzystałem algorytm 913 bajtów do 651 bajtów). Robi wiele mnożenia i dzielenia, a regex ECMAScript nie ma podprogramów.
Rozpocząłem pracę nad problemem licznej liczby stycznie w 23 marca 2014 r., Konstruując rozwiązanie tego, co w tamtym czasie wydawało się być podproblemem tego problemu: Identyfikowanie czynnika pierwszego o największej krotności, aby można go było podzielić na N na początku pozostawiając miejsce na wykonanie niezbędnych obliczeń. W tym czasie wydawało się, że jest to obiecująca droga. (Moje początkowe rozwiązanie okazało się dość duże przy 326 bajtach, później golfa do 185 bajtów.) Ale reszta metody naszkicowanej przez Teukona byłaby niezwykle skomplikowana, więc jak się okazało, wybrałem inną drogę. Okazało się, że wystarczające jest podzielenie największego głównego współczynnika mocy N odpowiadającego największemu pierwszemu współczynnikowi mocy na N; robienie tego dla liczby największej krotności zwiększyłoby niepotrzebną złożoność i długość wyrażenia regularnego.
Pozostało traktowanie sumy dzielników jako iloczynu sum zamiast sumy prostej. Jak wyjaśnił teukon 14 marca 2014 r .:
Zrozumiałem, że to widzę. Nigdy nie myślałem o tak liczeniu sumy podwielokrotności i to właśnie ta formuła sprawiła, że rozwiązalność obfitego dopasowywania liczb w wyrażeniu regularnym ECMAScript wydaje się wiarygodna.
W końcu zamiast testowania pod kątem dodania lub pomnożenia przekraczającego N lub testowania, że taki wynik podzielony przez M przekracza N / M, przystąpiłem do testowania, jeśli wynik podziału jest mniejszy niż 1. Dotarłem do pierwsza działająca wersja 7 kwietnia 2014 r.
Pełna historia moich optymalizacji golfa tego wyrażenia regularnego znajduje się na github. W pewnym momencie jedna optymalizacja zakończyła się znacznie wolniejszym wyrażeniem regularnym, więc od tego momentu zachowałem dwie wersje. Oni są:
Wyrażenie regularne dla dopasowania licznej liczby.txt
Wyrażenie regularne dla dopasowania licznej liczby - shortest.txt
Te wyrażenia regularne są w pełni kompatybilne zarówno z ECMAScript, jak i PCRE, ale ostatnia optymalizacja wymagała użycia potencjalnie nieuczestniczącej grupy przechwytywania
\14
, więc porzucenie kompatybilności PCRE i przejście\14?
na\14
obie można zmniejszyć o 1 bajt.Oto najmniejsza wersja z zastosowaną optymalizacją (czyniącą ją tylko ECMAScript), sformatowaną tak, aby pasowała do bloku kodu StackExchange bez (głównie) przewijania w poziomie:
źródło
Python 2 ,
4140 bajtówWyjście odbywa się za pomocą kodu wyjścia , więc 0 to prawda, a 1 to fałsz.
Wypróbuj online!
Jak to działa
Po ustawieniu wszystkich n , k oraz j do wejścia ze standardowego wejścia, wchodzimy do while pętli. Wspomniana pętla zostanie przerwana, gdy tylko -k - 1 = ~ k ≥ 0 , tj. K ≤ -1 / k <0 .
W każdej iteracji najpierw zmniejszamy j, aby uwzględnić tylko właściwe dzielniki n . Jeśli j jest dzielnikiem n ,
n%j
daje 0, a j >> n% j * n = j / 2 0 = j jest odejmowane od k . Jednakże, jeśli j czy nie podzielić n ,n%j
jest dodatni, więcn%j*n
jest co najmniej n> log 2 j i j >> n% n * j = j / 2 n% j * n = 0 jest odejmowany od k .Dla liczb obfitych, k osiągnie wartość ujemną przed lub po j staje się 1 , ponieważ suma n „s odpowiednie dzielniki jest większe niż n . W tym przypadku możemy wyrwać się z while pętli i program zakończy się normalnie.
Jeśli jednak n nie jest obfite, j ostatecznie osiąga 0 . W takim przypadku
n%j
zgłasza ZeroDivisionError i program kończy działanie z błędem.źródło
~k<0
jest fantazyjne, ale myślę, że-1<k
robi to samo;)Brachylog , 5 bajtów
Wypróbuj online!
Wyjaśnienie
źródło
Galaretka , 3 bajty
Wypróbuj online!
Jak to działa
źródło
Python , 44 bajty
Wypróbuj online!
źródło
range(n)
. Ten nieznośny moduł zerowyMathematica, 17 bajtów
Wyjaśnienie
źródło
AbundantNumberQ
, więc zaoszczędziłby kilka bajtów :)05AB1E ,
54 bajtów-1 bajtów dzięki scottinet
Wypróbuj online! lub Spróbuj od 0 do 100
źródło
Siatkówka ,
5045 bajtówWpisuj w unary , w
1
przypadku obfitych liczb, w0
przeciwnym razie.W tym rozwiązaniu nie ma nic specyficznego dla siatkówki. Powyżej jest czystym wyrażeniem regularnym .NET, które pasuje tylko do obfitych liczb.
Wypróbuj online! (Pakiet testowy, który filtruje dane dziesiętne z powyższym wyrażeniem regularnym).
źródło
Retina , 34 bajty
Liczba bajtów zakłada kodowanie ISO 8859-1.
Wpisuj w unary , w
1
przypadku obfitych liczb, w0
przeciwnym razie.Wypróbuj online!
Wyjaśnienie
Zaczynamy od uzyskania wszystkich dzielników danych wejściowych. Aby to zrobić, zwracamy (
!
) wszystkie pokrywające się (&
) dopasowania (M
) wyrażenia regularnego(1+)$(?<=^\1+)
. Wyrażenie regularne pasuje do jakiegoś sufiksu wejścia, pod warunkiem, że całe wejście jest wielokrotnością tego sufiksu (co zapewniamy, próbując dotrzeć do początku ciągu przy użyciu tylko kopii sufiksu). Z powodu sposobu, w jaki silnik wyrażeń regularnych szuka dopasowań, spowoduje to wyświetlenie listy dzielników w malejącej kolejności (oddzielonych liniami).Sam etap dopasowuje po prostu linefeeds (
¶
) i usuwa je. Jednak1>
jest granica, która pomija pierwszy mecz. To skutecznie sumuje wszystkie dzielniki z wyjątkiem samego wkładu. Kończymy z danymi wejściowymi w pierwszym wierszu i sumą wszystkich właściwych dzielników w drugim wierszu.Wreszcie, staramy się dopasować co najmniej jeden więcej
1
w drugiej linii niż w pierwszej linii. W takim przypadku suma właściwych dzielników przekracza dane wejściowe. Siatkówka liczy liczbę dopasowań tego wyrażenia regularnego, które będzie1
dla obfitych liczb i0
nie tylko.źródło
8086 Zgromadzenie,
23282524 bajtyNiezmontowane:
Przykładowy program testowy, testujący N = [12..1000]:
Wyjście [2..1000]
Wyjście [12500..12700]
Wyjście [25100..25300]
Aktualizacje:
źródło
JLE
przez,JBE
aby podwoić zakres liczb, które można przetestować, zanim zaczną się przepełnienia, powodując fałszywe negatywy. Następnie zamiast zaczynać niepowodzenie przy 12600 (suma podwielokrotności 35760), zacznie się nie udawać przy 25200 (podwielokrotna suma 74744). Jeszcze lepiej byłoby również wykryć flagę przenoszenia i traktować ją jako dużą liczbę bez konieczności obliczania rzeczywistej sumy> 16 bitów.JC
lubJNC
podjąć decyzję, czy numer jest obfity, czy nie.Właściwie 5 bajtów
Wypróbuj online!
źródło
05AB1E , 4 bajty
Wypróbuj online!
Jak to działa
Przepraszam za stare pytanie, właśnie przeglądałem stare posty i zauważyłem, że moje rozwiązanie jest krótsze niż następne najlepsze rozwiązanie 05AB1E.
źródło
Sorry to post in old question
Nie martw się o to! Zawsze cieszę się, widząc odpowiedzi na moje stare wyzwania, i tutaj jest to zachęcane . :)PARI / GP , 15 bajtów
Wariant
n->sigma(n,-1)>2
jest niestety dłuższy.źródło
Java 8, 53 bajty (znacznie więcej, jeśli podasz kod ceremonialny)
Wypróbuj online
Objaśnienie:
źródło
return
jeśli się nie mylę, więc będzie jeszcze krótsza:n->IntStream.range(1,n).filter(e->n%e<1).sum()>n
(nie 100%, jeśli jest to poprawne, prawie nigdy nie programuję w Javie 8). Witamy w PPCG!n->java.util.stream.IntStream.range(1,n).filter(e->n%e<1).sum()>n
65 bajtów (zakładając, że dostałem paczkę prosto z głowy)PowerShell,
5149 bajtówChciałbym móc usunąć kilka nawiasów.
-2 dzięki AdmBorkBork, zamiast nie zliczać danych wejściowych w początkowym zakresie, po prostu bierzemy to pod uwagę w końcowej kontroli.
Zapętl się przez zakres
1..
do$i
nput, minus 1, znajdź gdzie (?
) odwrotnym modułem wejściowym według bieżącej liczby jest$true
(aka tylko 0) - wtedy-join
wszystkie te liczby razem+
iiex
wynikowy ciąg do obliczenia, a następnie sprawdź, czy suma tych części jest większa niż wkład.źródło
param($i)((1..$i|?{!($i%$_)})-join"+"|iex)-gt2*$i
MATL, 6 bajtów
Wyjścia 1 dla obfitych liczb, w przeciwnym razie 0.
Jak to działa
źródło
QBIC , 22 bajty
Jest to dostosowanie do testu pierwotności QBIC . Zamiast zliczać dzielniki i sprawdzać, czy jest mniejsza niż trzy, sumuje to właściwe dzielniki. Działa to tylko w połowie
1 to n
, gdzie test pierwotności przebiega1 to n
całkowicie.Wyjaśnienie:
źródło
JavaScript (ES6), 33 bajty
źródło
Japt ,
9 76 bajtówZaoszczędzono 2 bajty dzięki produktom ETH. Zaoszczędzono 1 bajt dzięki obarakon.
Wypróbuj online!
źródło
â
ma 1 bajt, przynajmniej w Unicode (0xE2).â
jest to jeden bajt.â
podany zostanie prawdziwy argument, usunie on rzeczywistą liczbę z pozostałej listy, dzięki czemu można zrobić,â1 x >U
aby zapisać kilka bajtów :-)<Uâ1 x
aby zapisać bajt. Japt dodajeU
przed programem.Cubix , 38 bajtów
Wypróbuj tutaj
0I:
- ustawia stos na 0, n, n (s, n, d)^
- początek pętli)?
- zmniejsza d i testuje na 0. 0 kończy pętlę%?
- mod na n i testuje. 0 przyczyn,;rrw+s;rU
które obraca s do góry i dodaje d, obraca s do dołu i dołącza ponownie do pętli;<
- Oczyść i ponownie dołącz do pętli.Przy wyjściu z pętli
;<
- Usuń d ze stosu i przekieruj-?
- Usuń n ze s i przetestuj, 0LOU@
skręca w lewo, wyjścia i wyjścia, negatywy0O@
wypychają zero, wyjścia i wyjścia. pozytywy;O
usuwają różnicę i wyniki n. Ścieżka prowadzi następnie do skrętu w lewo, który przekierowuje do@
wyjściaźródło
Pure Bash, 37 bajtów
Dzięki @Dennis za zmianę układu kodu - oszczędność 6 bajtów i wyeliminowanie przypadkowych danych wyjściowych dla stderr.
Dane wejściowe są przekazywane jako argument.
Dane wyjściowe są zwracane w kodzie wyjścia: 0 dla dużej, 1 dla małej.
Dane wyjściowe do stderr należy zignorować.
Przebiegi testowe:
źródło
RProgN , 8 bajtów
Wyjaśniono
Wypróbuj online!
źródło
Partia, 84 bajtów
Wyjścia
-1
dla dużej liczby, w0
przeciwnym razie. Działa poprzez odjęcie wszystkich czynników,2n
a następnie przesunięcie wyniku o 31 miejsc w celu wyodrębnienia bitu znaku. Alternatywne sformułowanie, również 84 bajty:Wyjścia
1
dla obfitej liczby. Działa odejmując wszystkie czynniki,n
a następnie porównując wynik z-n
. (set/a
jest to jedyny sposób wykonywania arytmetyki przez Batch, więc nie mogę łatwo dopasować pętli).źródło
Perl 6,
7224 bajtów1..a
.a
.a
.Dzięki @ b2gills.
źródło
$^a
po pierwszym można skrócić do sprawiedliwego$a
. ale jest jeszcze krótszy, jeśli napiszesz go jako{$_ <sum grep $_%%*,^$_}
Patrząc również na wcześniejszą wersję,[+](LIST)
działa (bez spacji)J, 19 bajtów
Dzięki Conorowi O'Brienowi za zmniejszenie go do 19 bajtów!
<[:+/i.#~i.e.]%2+i.
Poprzedni: (34 bajty)
f=:3 :'(+/((i.y)e.y%2+i.y)#i.y)>y'
Zwraca 1, jeśli jest obfity, a 0, jeśli nie.
Wynik:
źródło
f=:
jako część liczby bajtów. Ponadto możesz przejść do 19, przechodząc na cichy czasownik:<[:+/i.#~i.e.]%2+i.
(f g h) y' is the same as
(fy) g (hy). When
f` to czapka,([: g h) y
jest mniej więcej taka sama jakg h y
. W przypadku~
przełącza argumenty lewy i prawy. Ważne jest, aby wiedzieć, że~
nie jest to czasownik, ale w rzeczywistości jest przysłówkiem. Zmienia czasownik. Na przykład moglibyśmy mieć coś takiego2 %~ 8
. Tutaj~
modyfikuje się,%
aby zmienić argumenty, więc wyrażenie jest równoważne z8 % 2
.#~
jest oceniany po wykonaniu czasowników po jego prawej stronie, więc jego lewy argument staje się wynikiem po prawejPyth, 11 bajtów
Stary:
Nie mogę użyć
!%
jako pfn#
, ponieważ są to dwie funkcje. Zasmuca mnie :(.źródło
>sPf!%QTS
k ,
19 1615 bajtówZwraca
1
za prawda i0
za fałsz.Wypróbuj online!
źródło
PowerShell , 43 bajty
Wypróbuj online!
źródło
Common Lisp, 63 bajty
Wypróbuj online!
źródło
F #, 51 bajtów
Wypróbuj online!
Filtruje wszystkie liczby, które nie dzielą się równomiernie
n
, a następnie sumuje je i porównuje z nimin
.źródło