Pomnóż dwa wielomiany całkowite

14

Twoim zadaniem jest pobranie dwóch wielomianowych wyrażeń całkowitych z jedną zmienną i pomnożenie ich do ich nieskomplikowanego rozszerzenia od lewej do prawej w pierwszym semestrze (AKA FOIL w przypadku dwumianów). Nie łącz podobnych terminów ani nie zmieniaj kolejności wyników. Aby być bardziej precyzyjnym na temat rozwinięcia, pomnóż pierwszy wyraz w pierwszym wyrażeniu przez każdy wyraz w drugim, w kolejności, i kontynuuj w pierwszym wyrażeniu, aż wszystkie wyrażenia zostaną pomnożone przez wszystkie pozostałe wyrażenia. Wyrażenia zostaną podane w uproszczonym wariancie LaTeX.

Każde wyrażenie będzie sekwencją terminów oddzielonych +(z dokładnie jedną spacją po każdej stronie). Każde wyrażenie będzie zgodne z następującym wyrażeniem regularnym: (notacja PCRE)

-?\d+x\^\d+

W prostym języku angielskim termin jest opcjonalnym początkiem, -po którym następuje jedna lub więcej cyfr, a następnie xnieujemna moc całkowita (z ^)

Przykład pełnego wyrażenia:

6x^3 + 1337x^2 + -4x^1 + 2x^0

Po podłączeniu do LaTeX otrzymujesz 6x3+1337x2+4x1+2x0

Dane wyjściowe powinny również być zgodne z tym formatem.

Ponieważ nawiasy nie otaczają wykładników w tym formacie, LaTeX faktycznie renderuje wykładniki wielocyfrowe niepoprawnie. (np. 4x^3 + -2x^14 + 54x^28 + -4x^5renderuje jako 4x3+2x14+54x28+4x5 ) Nie trzeba tego uwzględniać i nie należy umieszczać nawiasów w wynikach.

Przykładowe przypadki testowe

5x^4
3x^23

15x^27

6x^2 + 7x^1 + -2x^0
1x^2 + -2x^3

6x^4 + -12x^5 + 7x^3 + -14x^4 + -2x^2 + 4x^3

3x^1 + 5x^2 + 2x^4 + 3x^0
3x^0

9x^1 + 15x^2 + 6x^4 + 9x^0

4x^3 + -2x^14 + 54x^28 + -4x^5
-0x^7

0x^10 + 0x^21 + 0x^35 + 0x^12

4x^3 + -2x^4 + 0x^255 + -4x^5
-3x^4 + 2x^2

-12x^7 + 8x^5 + 6x^8 + -4x^6 + 0x^259 + 0x^257 + 12x^9 + -8x^7

Zasady i założenia

  • Możesz założyć, że wszystkie dane wejściowe są zgodne z tym dokładnie formatem. Zachowanie dla dowolnego innego formatu jest niezdefiniowane na potrzeby tego wyzwania.
    • Należy zauważyć, że każda metoda pobierania dwóch wielomianów jest poprawna, pod warunkiem, że oba są odczytywane jako ciągi znaków zgodne z powyższym formatem.
  • Kolejność wielomianów ma znaczenie ze względu na oczekiwaną kolejność rozszerzenia produktu.
  • Musisz obsługiwać współczynniki wejściowe od 128 do 127 i wykładniki wejściowe do 255 .
    • W związku z tym należy wspierać współczynniki wyjściowe od 16,256 do 16,384 i wykładniki do 510 .
  • Możesz założyć, że każdy wielomian wejściowy zawiera nie więcej niż 16 terminów
    • Dlatego musisz (przynajmniej) obsługiwać do 256 terminów w danych wyjściowych
  • Terminy o zerowych współczynnikach należy pozostawić bez zmian, a wykładniki należy odpowiednio połączyć
  • Ujemne zero jest dozwolone na wejściu, ale jest nie do odróżnienia semantycznie od zera dodatniego. Zawsze wyprowadzaj dodatnie zero. Nie pomijaj zerowych terminów.

Wesołego golfa! Powodzenia!

Wołowina
źródło
1
powiązane
H.PWiz
2
@LuisfelipeDejesusMunoz Nie wyobrażam sobie. Analiza składniowa jest integralną częścią wyzwania, a OP mówi: „Należy zauważyć, że każda metoda przyjmowania dwóch wielomianów jest poprawna, pod warunkiem, że oba są odczytywane jako ciągi znaków zgodne z powyższym formatem. ” (Podkreślenie dodane)
Giuseppe

Odpowiedzi:

4

R , 159 153 148 bajtów

function(P,Q,a=h(P),b=h(Q))paste0(b[1,]%o%a[1,],"x^",outer(b,a,"+")[2,,2,],collapse=" + ")
h=function(s,`/`=strsplit)sapply(el(s/" . ")/"x.",strtoi)

Wypróbuj online!

Naprawdę chciałem użyć outer, więc prawie na pewno jest bardziej wydajne podejście.

Giuseppe
źródło
4

Haskell , 131 122 bajtów

(%)=drop
f s=do(a,t)<-reads s;(i,u)<-reads$2%t;(a,i):f(3%u)
p!q=3%do(a,i)<-f p;(b,j)<-f q;" + "++shows(a*b)"x^"++show(i+j)

Wypróbuj online!

fanalizuje wielomian z ciągu, !mnoży dwa z nich i formatuje wynik.

H.PWiz zapisał 9 bajtów. Dzięki!

Nie golfił

type Monomial = (Int, Int) -- a^i
type Polynomial = [Monomial]

parse :: String -> Polynomial
parse s = do (a, s')  <- reads s
             (i, s'') <- reads (drop 2 s')
             (a, i) : parse (drop 3 s'')

(!) :: String -> String -> String
p!q = drop 3 (concat terms)
  where terms    = [term (a*b) (i+j) | (a,i) <- p', (b,j) <- q']
        term a i = concat [" + ", show a, "x^", show i]
        p'       = parse p
        q'       = parse q
Lynn
źródło
129 bajtów
H.PWiz
1
jeszcze lepiej
H.PWiz
2

Rubin , 102 100 98 bajtów

->a,b{a.scan(w=/(.*?)x.(\d+)/).map{|x|b.scan(w).map{|y|(eval"[%s*(z=%s;%s),z+%s]"%y+=x)*"x^"}}*?+}

Wypróbuj online!

W jaki sposób?

Pierwszy krok: pobierz wszystkie liczby z obu wielomianów: scanzwraca liczby jako tablicę par ciągów. Następnie zrób kartezjański produkt z 2 list. Teraz mamy wszystkie liczby, w których ich potrzebujemy, ale nadal w niewłaściwej kolejności.

Przykład: jeśli pomnożymy 3x^4przez -5x^2, otrzymamy liczby jako [["3","4"],["-5","2"]], pierwszym pomysłem było skompresowanie i spłaszczenie tej listy, a następnie umieszczenie liczb w wyrażeniu, które będzie oceniane jako [3*-5, 4+2]. W rzeczywistości nie musimy zmieniać kolejności liczb, moglibyśmy to zrobić w wyrażeniu za pomocą zmiennej tymczasowej: wyrażenie staje się [3*(z=4,-5),z+2].

Po ocenie tych wyrażeń otrzymujemy współczynnik i wykładnik, musimy połączyć je za pomocą "x^", a następnie połączyć wszystkie tem za pomocą "+".

GB
źródło
2

Haskell, 124 121 bajtów

import Data.Lists
f!x=map f.splitOn x
z=read!"x^"!"+"
a#b=drop 3$do[u,v]<-z a;[p,q]<-z b;" + "++shows(u*p)"x^"++show(v+q)

Uwaga: brakuje TIO Data.Lists, więc importuję Data.Lists.Spliti Data.List: Wypróbuj online!

Edycja: -3 bajty dzięki @Lynn.

nimi
źródło
To w rzeczywistości 123 bajty! f!x=map f.splitOn xa następnie z=read!"x^"!"+"zapisuje bajt; do ostatniego wiersza drop 3$do[u,v]<-z a;[p,q]<-z b;" + "++shows(u*p)"x^"++show(v+q)zapisuje dwa kolejne. 120 bajtów
Lynn,
1
@ Lynn: Data.Listzamiast tego importuje się wersja TIO Data.Lists, więc ma +1 bajt.
nimi
1

JavaScript (węzeł Babel) , 118 bajtów

Pobiera dane wejściowe jako (a)(b).

a=>b=>(g=s=>[...s.matchAll(/(-?\d+)x.(\d+)/g)])(a).flatMap(([_,x,p])=>g(b).map(([_,X,P])=>x*X+'x^'+-(-p-P))).join` + `

Wypróbuj online!

Arnauld
źródło
1

Python 2 , 193 bajtów

import re
f=re.finditer
lambda a,b:' + '.join(' + '.join(`int(m.group(1))*int(n.group(1))`+'x^'+`int(m.group(2))+int(n.group(2))`for n in f('(-?\d+)x\^(\d+)',b))for m in f('(-?\d+)x\^(\d+)',a))

Wypróbuj online!

Uwaga dodatkowa: po raz pierwszy wykonuję wyzwanie w golfa kodem, więc przepraszam, jeśli próba jest do bani

GotCubes
źródło
3
Witamy w PPCG! Nie jestem zbytnio programistą pythonowym, ale prawdopodobnie jest miejsce na ulepszenia. Być może znajdziesz pomoc w Poradach do gry w golfa w Pythonie lub Poradnikach do gry w golfa w <wszystkich językach> ! Mam nadzieję, że spodoba ci się czas, który tu spędzasz :-)
Giuseppe
1
Szybka gra w golfa za 161 bajtów . Chociaż patrząc na inne odpowiedzi pytona, re.finditermoże nie być najkrótszym podejściem
Jo King
1

Siatkówka , 110 bajtów

\S\S+(?=.*\n(.+))
 $1#$&
|" + "L$v` (-?)(\d+)x.(\d+).*?#(-?)(\d+)x.(\d+)
$1$4$.($2*$5*)x^$.($3*_$6*
--|-(0)
$1

Wypróbuj online! Wyjaśnienie:

\S\S+(?=.*\n(.+))
 $1#$&

Przed każdym terminem na pierwszym wejściu wpisz prefiks #, kopię drugiego wejścia i spację. Oznacza to, że wszystkie warunki w kopiach drugiego wejścia są poprzedzone spacją i żaden z terminów z pierwszego wejścia nie jest.

|" + "L$v` (-?)(\d+)x.(\d+).*?#(-?)(\d+)x.(\d+)
$1$4$.($2*$5*)x^$.($3*_$6*

Dopasuj wszystkie kopie terminów z drugiego wejścia i odpowiadający im termin z pierwszego wejścia. Połącz wszystkie -znaki, pomnóż współczynniki i dodaj wskaźniki. Na koniec połącz wszystkie powstałe podstawienia z łańcuchem  + .

--|-(0)
$1

Usuń wszystkie pary -si przekonwertuj -0na 0.

Neil
źródło
1

SNOBOL4 (CSNOBOL4) , 192 176 bajtów

	P =INPUT
	Q =INPUT
	D =SPAN(-1234567890)
P	P D . K ARB D . W REM . P	:F(O)
	B =Q
B	B D . C ARB D . E REM . B	:F(P)
	O =O ' + ' K * C 'x^' W + E	:(B)
O	O ' + ' REM . OUTPUT
END

Wypróbuj online!

	P =INPUT				;* read P
	Q =INPUT				;* read Q
	D =SPAN(-1234567890)			;* save PATTERN for Digits (or a - sign); equivalent to [0-9\\-]+
P	P D . K ARB D . W REM . P	:F(O)	;* save the Koefficient and the poWer, saving the REMainder as P, or if no match, goto O
	B =Q					;* set B = Q
B	B D . C ARB D . E REM . B	:F(P)	;* save the Coefficient and the powEr, saving the REMainder as B, or if no match, goto P
	O =O ' + ' K * C 'x^' W + E	:(B)	;* accumulate the output
O	O ' + ' REM . OUTPUT			;* match ' + ' and OUTPUT the REMainder
END
Giuseppe
źródło
1

Perl 6 , 114 bajtów

{my&g=*.match(/(\-?\d+)x\^(\d+)/,:g)».caps».Map;join " + ",map {"{[*] $_»{0}}x^{[+] $_»{1}}"},(g($^a)X g $^b)}

Wypróbuj online!

bb94
źródło
1
86 bajtów
Jo King
1

Python 2 , 130 bajtów

lambda a,b:' + '.join([`v*V`+'x^'+`k+K`for V,K in g(a)for v,k in g(b)])
g=lambda s:[map(int,t.split('x^'))for t in s.split(' + ')]

Wypróbuj online!

Chas Brown
źródło
1

C # (interaktywny kompilator Visual C #) , 192 190 bajtów

n=>m=>string.Join(g=" + ",from a in n.Split(g)from b in m.Split(g)select f(a.Split(p="x^")[0])*f(b.Split(p)[0])+p+(f(a.Split(p)[1])+f(b.Split(p)[1])));Func<string,int>f=int.Parse;string p,g;

Składnia zapytania wydaje się być bajtem krótszym niż składnia metody.

Wypróbuj online!

Wcielenie ignorancji
źródło
Każde wyrażenie będzie sekwencją terminów oddzielonych znakiem + (z dokładnie jedną spacją po każdej stronie) 190 bajtów
Data wygasła
1

Galaretka , 28 bajtów

ṣ”+ṣ”xV$€)p/ZPSƭ€j⁾x^Ʋ€j“ + 

Wypróbuj online!

Pełny program Traktuje dwa wielomiany jako listę dwóch ciągów.

Wyjaśnienie (forma rozszerzona)

ṣ”+ṣ”xV$€µ€p/ZPSƭ€j⁾x^Ʋ€j“ + ” Arguments: x
         µ                     Monadic chain.
          €                    Map the monadic link over the argument.
                               Note that this will "pop" the previous chain, so
                               it will really act as a link rather than a
                               sub-chain.
ṣ”+                             ṣ, right = '+'.
                                Split the left argument on each occurrence of
                                the right.
                                Note that strings in Jelly are lists of
                                single-character Python strings.
        €                       Map the monadic link over the argument.
       $                         Make a non-niladic monadic chain of at least
                                 two links.
   ṣ”x                            ṣ, right = 'x'.
                                  Split the left argument on each occurrence of
                                  the right.
      V                           Evaluate the argument as a niladic link.
            /                  Reduce the dyadic link over the argument.
           p                    Cartesian product of left and right arguments.
                       €       Map the monadic link over the argument.
                      Ʋ         Make a non-niladic monadic chain of at least
                                four links.
             Z                   Transpose the argument.
                 €               Map the monadic link over the argument.
                ƭ                 At the first call, call the first link. At the
                                  second call, call the second link. Rinse and
                                  repeat.
              P                    Product: ;1×/$
               S                   Sum: ;0+/$
                  j⁾x^           j, right = "x^".
                                 Put the right argument between the left one's
                                 elements and concatenate the result.
                        j“ + ” j, right = " + ".
                               Put the right argument between the left one's
                               elements and concatenate the result.

Aliasing

)jest taki sam jak µ€.
Końcowe jest implikowane i można je pominąć.

Algorytm

Powiedzmy, że mamy następujące dane wejściowe:

["6x^2 + 7x^1 + -2x^0", "1x^2 + -2x^3"]

Pierwszą procedurą jest analiza składniowa, zastosowana do każdego z dwóch wielomianów. Zajmijmy się pierwszym "6x^2 + 7x^1 + -2x^0":

Pierwszym krokiem jest podzielenie łańcucha '+' , aby oddzielić warunki. To skutkuje:

["6x^2 ", " 7x^1 ", " -2x^0"]

Następnym krokiem jest podzielenie każdego łańcucha 'x' , aby oddzielić współczynnik od wykładnika. Rezultat jest następujący:

[["6", "^2 "], [" 7", "^1 "], [" -2", "^0"]]

Obecnie wygląda na to, że w tych ciągach jest dużo śmieci, ale śmieci te są w rzeczywistości nieistotne. Wszystkie te ciągi będą oceniane jako niladowe ogniwa galaretowe. Trywialnie, spacje są nieistotne, ponieważ nie znajdują się między cyframi liczb. Więc moglibyśmy równie dobrze ocenić poniższe i nadal uzyskać ten sam wynik:

[["6", "^2"], ["7", "^1"], ["-2", "^0"]]

Do ^s wyglądać nieco bardziej niepokojące, ale w rzeczywistości nic nie robić albo! Cóż, ^jest bitowym atomem XOR, jednak łańcuchy niladyczne działają jak łącza monadyczne, z tym wyjątkiem, że pierwsze łącze faktycznie staje się argumentem, zamiast brać argument, jeśli jest ono zerowe. Jeśli nie, link będzie miał argument 0. Wykładniki mają ^s jako swój pierwszy znak i ^nie są niladyczne, więc zakłada się, że argument jest taki 0. Reszta ciągu, tj. Liczba, jest właściwym argumentem ^. Tak na przykład ^2jest0 XOR 2)=2). Oczywiście,0 XOR n=n. Wszystkie wykładniki są liczbami całkowitymi, więc nic nam nie jest. Dlatego ocena tego zamiast powyższego nie zmieni wyniku:

[["6", "2"], ["7", "1"], ["-2", "0"]]

No to ruszamy:

[[6, 2], [7, 1], [-2, 0]]

Ten krok zostanie również przekonwertowany "-0"na 0.

Ponieważ analizujemy oba dane wejściowe, wynik po analizie będzie następujący:

[[[6, 2], [7, 1], [-2, 0]], [[1, 2], [-2, 3]]]

Analiza jest teraz zakończona. Następną procedurą jest mnożenie.

Najpierw bierzemy produkt kartezjański z tych dwóch list:

[[[6, 2], [1, 2]], [[6, 2], [-2, 3]], [[7, 1], [1, 2]], [[7, 1], [-2, 3]], [[-2, 0], [1, 2]], [[-2, 0], [-2, 3]]]

Powstaje wiele par, każda z jednym elementem z lewej listy i jedną z prawej, w kolejności. Jest to również zamierzona kolejność danych wyjściowych. To wyzwanie naprawdę wymaga od nas zastosowania multiplikatywnej dystrybucji, ponieważ jesteśmy proszeni o dalsze przetwarzanie wyniku po tym.

Pary w każdej parze reprezentują warunki, które chcemy pomnożyć, przy czym pierwszy element jest współczynnikiem, a drugi wykładnikiem. Aby pomnożyć warunki, mnożymy współczynniki i dodajemy wykładniki razem (zaxdobxre=zabxdoxre=zab(xdoxre)=(zab)xdo+re). Jak to zrobimy? Powiedzmy sobie drugą parę, [[6, 2], [-2, 3]].

Najpierw transponujemy parę:

[[6, -2], [2, 3]]

Następnie bierzemy iloczyn pierwszej pary i sumę drugiej:

[-12, 5]

Odpowiednia część kodu, PSƭ€tak naprawdę, nie resetuje swojego licznika dla każdej pary terminów, ale ponieważ są to pary, nie musi.

Obsługując wszystkie pary warunków, mamy:

[[6, 4], [-12, 5], [7, 3], [-14, 4], [-2, 2], [4, 3]]

Tutaj mnożenie odbywa się, ponieważ nie musimy łączyć podobnych terminów. Ostatnią procedurą jest Całowanie.

Najpierw łączymy każdą parę z "x^":

[[6, 'x', '^', 4], [-12, 'x', '^', 5], [7, 'x', '^', 3], [-14, 'x', '^', 4], [-2, 'x', '^', 2], [4, 'x', '^', 3]]

Następnie dołączamy do listy " + ":

[6, 'x', '^', 4, ' ', '+', ' ', -12, 'x', '^', 5, ' ', '+', ' ', 7, 'x', '^', 3, ' ', '+', ' ', -14, 'x', '^', 4, ' ', '+', ' ', -2, 'x', '^', 2, ' ', '+', ' ', 4, 'x', '^', 3]

Zauważ, że wciąż mamy liczby na liście, więc tak naprawdę nie jest to ciąg znaków. Jednak Jelly ma proces zwany „strucyfikacją”, uruchamiany zaraz po zakończeniu programu do wydrukowania wyniku. Aby uzyskać listę głębokości 1, tak naprawdę po prostu konwertuje każdy element na jego reprezentację ciągu i konkatenuje ciągi razem, więc otrzymujemy pożądany wynik:

6x^4 + -12x^5 + 7x^3 + -14x^4 + -2x^2 + 4x^3
Erik the Outgolfer
źródło
1

JavaScript, 112 110 bajtów

Znalazłem dwie alternatywy o tej samej długości. Wywołanie ze składnią curry:f(A)(B)

A=>B=>(P=x=>x.split`+`.map(x=>x.split`x^`))(A).flatMap(a=>P(B).map(b=>a[0]*b[0]+'x^'+(a[1]- -b[1]))).join` + `

A=>B=>(P=x=>x.split`+`.map(x=>x.split`x^`))(A).flatMap(([c,e])=>P(B).map(([C,E])=>c*C+'x^'+(e- -E))).join` + `

-2 bajty ( Luis ): Usuń spacje wokół splitogranicznika.


JavaScript, 112 bajtów

Korzystanie String.prototype.matchAll.

A=>B=>(P=x=>[...x.matchAll(/(\S+)x.(\S+)/g)])(A).flatMap(a=>P(B).map(b=>a[1]*b[1]+'x^'+(a[2]- -b[2]))).join` + `

darrylyeo
źródło
1
split' + ' => split'+'zaoszczędzić 2 bajty
Luis felipe De Jesus Munoz
@Arnauld Wydaje się bez nich w porządku
of Ignorance
@EmbodimentofIgnorance Mój zły, źle odczytałem komentarz Luisa. Myślałem, że chodzi o join.
Arnauld,