Pomnóż dwie liczby bez używania liczb


30

Jako dane wejściowe podano dwa ciągi reprezentujące dodatnie liczby całkowite w bazie 10, takie jak "12345"i "42". Twoim zadaniem jest "518490"w tym przypadku wyprowadzenie ciągu zawierającego ich produkt .

Rzecz w tym, że nie możesz używać żadnych typów numerycznych w swoim kodzie. Nie ints, floats, unsigned longs itp., Brak wbudowanych typów liczb zespolonych, liczb całkowitych o dowolnej dokładności lub cokolwiek wzdłuż tych linii. Wielu z was nie używa literałów tego typu ani żadnej funkcji, metody, operatora itp., Która je zwraca.

Państwo może używać ciągi, wartości logicznych, tablic, ani niczego innego, co normalnie nie być używane do reprezentowania numer. (Należy jednak pamiętać, że ani indeksowanie do tablicy, ani uzyskanie jej długości prawdopodobnie nie będzie możliwe bez wywołania typu liczbowego.) charS są dozwolone, ale nie można wykonywać na nich żadnych operacji arytmetycznych lub bitowych ani w żaden inny sposób traktować ich jako niczego innego niż token reprezentujący część ciągu. ( charDozwolone jest porównanie leksykograficzne s.)

Nie możesz obejść tego ograniczenia. Obejmuje to (ale nie wyłącznie) używanie typów numerycznych w evalfunkcji typu, niejawne konwersje typów na typy numeryczne, stosowanie operatorów numerycznych lub bitowych na typach nienumerycznych, które je obsługują, używanie typów numerycznych przechowywanych w typach kontenerów lub wywoływanie funkcji lub programy zewnętrzne, które zwracają wyniki liczbowe w postaci łańcucha. (Zastrzegam sobie prawo do dodania do tej listy, jeśli w odpowiedziach pojawią się inne obejścia). Musisz samodzielnie zaimplementować mnożenie, używając tylko typów nienumerycznych.

Wejście i wyjście może odbywać się dowolną dogodną metodą, o ile dane wchodzą i wychodzą z kodu w postaci ciągu. Możesz założyć, że każdy z dwóch argumentów wejściowych zawiera tylko znaki ASCII [0-9]i nie zacznie się od 0. Twój wynik również nie powinien mieć wiodących zer.

Jeszcze jedno: twój kod musi poprawnie obsługiwać dane wejściowe o długości co najmniej 10 znaków i musi działać w niecałą minutę na nowoczesnym komputerze dla wszystkich danych wejściowych w tym zakresie. Przed wysłaniem sprawdź, czy po podaniu danych wejściowych 9999999999i 9999999999program daje wynik 99999999980000000001w ciągu mniej niż minuty. To ograniczenie istnieje specjalnie po to, aby zapobiec odpowiedziom, które przydzielają tablicę rozmiarów, a*ba następnie iterują nad nią, więc pamiętaj, że odpowiedzi tego formularza nie będą mogły wygrać.

To jest , więc wygrywa najkrótsze prawidłowe rozwiązanie (w bajtach).


Czy możemy zaakceptować "12345"zamiast STDIN 12345? Czy możemy zaakceptować obie liczby jako "12345", "42"?
Justin

Moją pierwszą myślą było napisać funkcję biorąc argumenty Łańcuch o maksymalnej długości mi ni powrocie argument długości m*n. Ale ponieważ ciągi muszą dosłownie zawierać reprezentację liczb ASCII, myślę, że jest to niezgodne z regułami.
Level River St

1
@ xnor w wielu językach napisanie wszystkich przypadków może być krótsze. Ale tak znalazłem w Pythonie:a,b="0123456789x".split('0');c=iter(b).next() if c=='x': c='0'
Nataniel

1
lub w Python 3,a,b="0123456789x".split(x);c,*d=b if c=='x': c='0'
Nathaniel

2
@Nanielanield='123456789';I=dict(zip('0'+d,d+'0'))
Justin

Odpowiedzi:


6

Haskell - 180 206 214

r=reverse
f=filter
z=['0'..'9']
a?f|f="1"!a
a?_=a
(a:b)!(c:d)=e:b!d?(e<a)where e=fst$last$zip(f(>=c)z++z)$f(<=a)z
a!c=a++c
a%(b:c)=foldr(!)('0':a%c)$f(<b)z>>[a]
_%b=b
a#b=r$r a%r b

Wprowadza mnożenie poprzez wielokrotne dodawanie, a wszystkie rodzaje cyfrowej magii są obsługiwane przez przesuwanie i filtrowanie ['0'..'9']listy. Definiuje operator #typu String -> String -> String:

*> :set +s
*> "9990123456789"#"9999876543210"
"99900001219316321126352690"
(0.02 secs, 9862288 bytes)

Wygląda na to, że mamy nowego zwycięzcę! (Chociaż tak jak poprzednio, nie potrafię odczytać Haskella o tym stopniu wyrafinowania - czy ktoś może samodzielnie sprawdzić, czy spełnia specyfikację?)
Nathaniel

(Również „0” .. „9”] przypomina trochę niejawne traktowanie znaków jako liczb, które można iterować - czy istnieje krótki sposób na wygenerowanie tej listy z ciągu „0123456789”?)
Nathaniel

@Nanielski Cóż, przede wszystkim ciąg "0123456789" jest listą ['0'..'9']. Po drugie, w Haskell [a..b] znajduje się wyliczenie, typy, które zadeklarowały wystąpienia Enumklasy, mogą być wyliczone w ten sposób, a deklaracja opisuje sposób działania wyliczenia. Bool, typ boolowski ma również instancję, dlatego możesz to zrobić [False..True]. Nie ma w tym prawie żadnych liczb.
mniip

14

sed, 339 338 bajtów

Wiem, że to stary, ale przeglądałem i to wzbudziło moje zainteresowanie. Wystarczy, aby zarejestrować się jako użytkownik! Chyba zachwyciło mnie „ Chciałbym zobaczyć pełne rozwiązanie sed - Nathaniel ” ...

s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g
:o
s/\( .*\)0$/0\1/
/x$/{
x
G
s/ .*/\n/
:a
s/\(.*\)0\(x*\)\n\(.*\)0\(x*\)\n/\1\n\3\n0\2\4/
ta
s/\n//g
:c
s/^x/0x/
s/0xxxxxxxxxx/x0/
tc
x
s/x$//
}
/ 0/bo
g
s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g

Ten skrypt sed oczekuje na wejściu dwóch liczb dziesiętnych oddzielonych jedną spacją

testy:

time test 518490 = $(./40297.sed <<<)"12345 42" || echo fail
time test 99999999980000000001 = $(./40297.sed <<<"9999999999 9999999999") || echo fail
time test 1522605027922533360535618378132637429718068114961380688657908494580122963258952897654000350692006139 = $(./40297.sed <<<"37975227936943673922808872755445627854565536638199 40094690950920881030683735292761468389214899724061") || echo fail
time test 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413 = $(./40297.sed <<<"33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917") || echo fail

Dwa ostatnie można rozpoznać jako RSA-100 (50 x 50 cyfr) i RSA-768 (116 x 116 cyfr).

Używając GNU sed na niezbyt nowoczesnym (Intel Core 2 z ery 2007), ostatni z nich zajmuje ponad minutę, ale na nowszym procesorze jest szybszy:

  • Q6600:> 1 minuta
  • i7-3770: 26 sekund
  • i7-6700: 22 sekundy

Niewielki 10-cyfrowy mnożnik określony w pytaniu zajmuje dokładnie jedną sekundę na dowolnym z nich (pomimo tego, że jest pełen patologicznych dziewiątek).

Uważam, że jest to standardowy sed, bez rozszerzeń. POSIX gwarantuje, że pomieści tylko 8192 bajtów, co ogranicza nas do pomnożenia liczb 400 x 400 cyfr, ale implementacje mogą zapewnić więcej. GNU sed jest ograniczony tylko dostępną pamięcią, więc może zarządzać czymś znacznie większym, jeśli chcesz poczekać.

I jestem pewien, że przestrzegałem zasad - to prawie dane w języku, który nie ma liczb. :-)

Wyjaśnienie

Korzystam z hybrydowej jedności / dziesiętnej, przekształcając liczby dziesiętne w sekwencję jedności:

 42 => _xxxx_xx

W jednostkowym ułamku dziesiętnym dodawanie jest łatwe. Iterujemy od najmniej znaczącej do najbardziej znaczącej cyfry, łącząc x:

   X=965                   Y=106                                 SUM
   _xxxxxxxxx_xxxxxx_xxxxx _x__xxxxxx
   _xxxxxxxxx_xxxxxx       _x_                          _xxxxxxxxxxx
   _xxxxxxxxx              _x                    _xxxxxx_xxxxxxxxxxx
                                      _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx

Następnie usuwamy białe znaki i zajmujemy się przenoszeniem, konwertując 10 kolejnych x na jedną z następnych jednostek:

 _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx       10.6.11
 _xxxxxxxxxx_xxxxxxx_x                10.7.1
 _x__xxxxxxx_x                        1.0.7.1 

Po dodaniu możemy pomnożyć. Mnożymy x * y przez ostatnią cyfrę y. Dodaj x do akumulatora wiele razy, a następnie przejdź do następnej cyfry i przesuń x jedno miejsce po przecinku w lewo. Powtarzaj, aż y wyniesie zero.

Rozszerzony kod

#!/bin/sed -f

# Convert to unary decimal.  We save two or three bytes of code by
# reusing 0 as the digit separator.
s/[1-9]/0&/g
s/[5-9]/4&/g
y/8/4/
s/9/4&/g
s/4/22/g
s/[37]/2x/g
s/[26]/xx/g
s/[1-9]/x/g

# until y==0

:one

# y ends in zero => x *= 10 and y /= 10
s/\( .*\)0$/0\1/

# while y%10, acc += x, y -= 1
/x$/{
x
G
s/ .*/\n/
# Add x
:add
s/\(.*\)0\(x*\)\n\(.*\)0\(x*\)\n/\1\n\3\n0\2\4/
tadd
s/\n//g
:carry
s/^x/0x/
s/0xxxxxxxxxx/x0/
tcarry

# repeat for each unit of y
x
s/x$//
}

# y?
/ 0/bone


# convert hold space to decimal
g
s/0x/-x/g
s/xx/2/g
y/x/1/
s/22/4/g
s/44/8/g
s/81/9/g
s/42/6/g
s/21/3/g
s/61/7/g
s/41/5/g
s/-//g

1
Bardzo satysfakcjonująca odpowiedź, dziękuję!
Nathaniel

9

sed, 379 bajtów

Podziękowania za tę świetną odpowiedź należą się dla @LuigiTiburzi w systemach Unix i Linux.SE: https://unix.stackexchange.com/a/37213/34061 . Kilka dni temu natknąłem się na to:

s/[0-9]/<&/g
s/0//g
s/1/|/g
s/2/||/g
s/3/|||/g
s/4/||||/g
s/5/|||||/g
s/6/||||||/g
s/7/|||||||/g
s/8/||||||||/g
s/9/|||||||||/g
:t
s/|</<||||||||||/g
tt
s/<//g
s/.*\*$/0/
s/^\*.*/0/
s/*|/*/
:m
s/\(|*\)\*|/\1<\1*/
tm
s/*//g
s/<//g
:b
s/||||||||||/</g
s/<\([0-9]*\)$/<0\1/
s/|||||||||/9/
s/||||||||/8/
s/|||||||/7/
s/||||||/6/
s/|||||/5/
s/||||/4/
s/|||/3/
s/||/2/
s/|/1/
s/</|/g
tb

Ogólne wyjaśnienie

  • Oddziel każdą cyfrę. Tak się 12*3staje<1<2*<3
  • Konwertuj każdą cyfrę na tę liczbę |znaków. Tak się <1<2*<3staje<|<||*<|||
  • Wielokrotnie zastąpić |<ze <||||||||||w celu przesunięcia wyższych miejsc po przecinku wszystko w dół do pozycji jednostek. Tak się <|<||*<|||staje<||||||||||||*<|||
  • Usuń <. Tak się <||||||||||||*<|||staje||||||||||||*|||
  • Usuń 1 |z RHS *. Tak się ||||||||||||*|||staje||||||||||||*||
  • Wielokrotnie wymieniaj wszystkie |w RHS na wszystkie |w LHS. Ma to efekt mnożenia liczby LHS i RHS w |otrzymując Produkt Liczba | Zatem ||||||||||||*||staje||||||||||||||||||||||||||||||||||||*
  • Usuń *. Tak się ||||||||||||||||||||||||||||||||||||*staje||||||||||||||||||||||||||||||||||||
  • konwertuj liczbę |wstecz na dziesiętną przez odwrócenie pierwszych kilku kroków. Tak się ||||||||||||||||||||||||||||||||||||staje 36.

Wydajność:

$ echo "04*3
4*3
40*3
42*32
150*20
1*3
3*1
0*3
3*0" | sed -f mult.sed
12
12
120
1344
3000
3
3
0
0
$

Niestety nie udaje mu się to z powodu wymaganego czasu - 200*1000trwa 41 sekund na mojej maszynie Wirtualnej Ubuntu, a środowisko wykonawcze wydaje się iść w górę z kwadratem produktu końcowego.


1
Jest to prawie algorytmicznie równoważne mojej usuniętej odpowiedzi JS, z wyjątkiem konwersji z powrotem na część liczbową.
Optymalizator

@Optimizer Agreed. Różnica polega na tym, że używasz, length()co zwraca liczbę. Ten używa wyłącznie podstawienia wyrażeń regularnych bez typów liczbowych. Myślę, że twoja odpowiedź jest potencjalnie zwycięzcą, jeśli możesz usunąć length()- może zamiast tego możesz wykonać podobne podstawienie wyrażenia regularnego?
Digital Trauma

1
Bardzo fajnie, ale jednominutowe ograniczenie ma na celu przede wszystkim zapobieganie rozwiązaniom, które liczą się do odpowiedzi. Chciałbym jednak zobaczyć pełne rozwiązanie sed.
Nataniel

1
Mam odpowiedź, która działa na duże liczby (np. Większe niż przestrzeń adresowa systemu).
Toby Speight,

@TobySpeight tak, bardzo dobrze. Myślę, że musiałem już kiedyś głosować na pańską :)
Cyfrowa trauma

9

Python - 312 286 273

D={}
e=t=""
N=[e]
for c in"0123456789":D[c]=t;D[t]=c;t+="I";N+=N
B=lambda s:[D[c]for c in reversed(s)]
Y=B(input())+N
for a in B(input())+N:
 for c in a:
    s=[];o=e
    for a,b in zip(N,Y):i=a+b+o;o=t<=i and"I"or e;s+=i.replace(t,e),;N=s
 Y=[e]+Y
print e.join(B(N)).lstrip("0")

Jeśli dozwolone jest (wiele) wiodących zer, ostatnie 12 znaków nie jest potrzebne.

To zasadniczo wykonuje ręczne pomnożenie. Cyfry są reprezentowane jako ciągi powtarzających się Is (jak prymitywne cyfry rzymskie). Liczby są reprezentowane jako listy cyfr w odwrotnej kolejności. Dodawanie pojedynczych cyfr odbywa się przez kokatenowanie łańcuchów i usunięcie dziesięciu Is, jeśli to konieczne.

Oto wersja bez golfa:

N = [""] # zero object: list with a lot of empty strings
D = {}   # dictionary for conversion from and to digits
i = ""   # iterates over digits
for c in "0123456789":
    D[c] = i  # map digit to Roman digit
    D[i] = c  # and vice versa
    i += "I"  # increments Roman digit
    N += N    # add leading zeros to zero

ten = "IIIIIIIIII" # Roman digit ten

# Conversion function
B = lambda s: [D[c] for c in reversed(s)]

def Add(x,y):
    Sum = []
    carryover = ""
    for a,b in zip(x,y):
        increment = a+b+carryover
        carryover = "I" if ten in increment else ""
        increment = increment.replace(ten,"") # take increment modulo ten
        Sum += [increment]
    return Sum

def M(x,y):
    Sum = N[:] # Initiate Sum as zero
    X = B(x)+N # Convert and add leading zeros
    Y = B(y)+N
    for a in X:
        for c in a:
            Sum = Add(Sum,p+Y)
        Y = [""] + Y # multiply Y by 10
    return "".join(B(Sum)).lstrip("0") # Convert back and to string, remove leading zeros.

M(input(),input())

1
Co to za czary! Jak to działa! Łał. Oto kolejny golf, który możesz zrobić: def A(x,y):\n S=[];o=""-> def A(x,y,S=[],o=""):. Niestety, ["","1"][t in i]nie jest dozwolone; używa indeksu bool, traktując go jako liczbę. Myślę jednak, że to t in i and"1"or""powinno zadziałać.
Justin

@Quincunx: Definiowanie Sjako argument z wartością domyślną nie zadziałałoby, ponieważ zawsze byłaby to ta sama lista nawet dla różnych wywołań funkcji, a zatem nie resetuje się do []. Miałeś rację ["","1"][t in i], naprawiłem to. Dodałem także wyjaśnienie.
Wrzlprmft

To jest niesamowite. Na razie robi się zielony. (Zredagowałem pytanie, aby wyjaśnić, że wiodące zera w danych wyjściowych są niedozwolone - przepraszam!)
Nathaniel,

7

Rubin: 752 698

To tylko po to, aby uzyskać odpowiedź, zrobioną z ciekawości. Edytowane: teraz trochę golfa.

$F='0123456789'
$G="#{$F}abcdefghij"
def x(a,b);p(a=~/[13579]$/?b:"",a==""?"":x(Hash[*%w(b0 5 b1 6 b2 7 b3 8 b4 9)].to_a.inject(a.tr($F,'0011223344').chars.zip(a.tr($F,'ababababab').chars).flatten.join("")){|n,q|k,v=q;n.gsub(k,v)}.gsub(/[ab]/,'').sub(/^0*/,''),p(b,b)));end
def p(a,b);j,k=["0#{a}","0#{b}"].map{|c|c.gsub(/./,'0')};c="#{k}#{a}".chars.zip("#{j}#{b}".chars).drop_while{|z|z==%w(0 0)}.map{|m|$G.sub(/#{m.map{|n|"122333444455555666666777777788888888999999999".chars.select{|c|c==n}}.flatten.map{|c|'.'}.join("")}/,"").chars.first}.flatten.join("");d=nil;
while c!=d
 d=c;c="0#{d}".gsub(/[0-9][a-j]/) {|m| m.tr($G,"123456789a#{$F}")}.sub(/^0/,'')
end;c;end
puts x(ARGV.shift,ARGV.shift)

Zastosowanie: Miałem to w pliku o nazwie peasant.rb:

$ time ruby peasant.rb 9999999999 9999999999
99999999980000000001

real    0m0.129s
user    0m0.096s
sys 0m0.027s

Wyjaśnienie: to rozmnażanie wieśniaków, więc wielokrotnie zmniejszam o połowę i podwajam. Przekrawanie odbywa się poprzez zmniejszenie o połowę cyfr i zaznaczenie pozostałych: 1234 -> 0b1a1b2a; następnie znajdź i zamień na b: 06a17a; następnie sprzątanie -> 617.

Dodawanie odbywa się w ten sposób ... po pierwsze, podbijam oba ciągi na tej samej długości i tworzę pary z cyfr. Następnie dodaję cyfry, konstruując ciąg o długości każdej cyfry i łącząc; Usuwam ciąg o tej długości z początku „0123456789abcdefghij”, a następnie zachowuję pierwszy znak. Na przykład „9” + „9” -> „i”. Uwaga: Unikam tutaj używania funkcji długości, aby całkowicie uniknąć typów liczb; usunięcie prefiksu odbywa się za pomocą wyrażenia regularnego.

Więc teraz mam ciąg zawierający mieszankę cyfr i liter. Litery oznaczają cyfry z cyfrą przeniesienia; Wprowadzam 0 do liczby, a następnie wielokrotnie zastępuję wzorce cyfr i liter wynikiem wyniku przenoszenia, aż dodawanie zostanie zakończone.


1
Bardzo sprytna odpowiedź, dokładnie to, co chciałem zobaczyć!
Nathaniel

1
Mam nadzieję, że ktoś opublikuje jeden z cyframi Kościoła!
bazzargh

To byłoby fajne, choć nie jestem pewien, czy zadziałałoby to z wymogiem wydajności - myślę, że konwersja między łańcuchami i cyframi Kościoła wymagałaby skutecznego zliczania do 99999999980080000000001.
Nathaniel

7

Brainfuck (1328 bajtów)

Rozważania na początku:

  • Nie jestem pewien, czy pieprzenie mózgu jest prawidłową odpowiedzią na te pytania, ponieważ nie jestem pewien, czy uznajesz wartości komórek za „typy numeryczne”, czy nie. Nie sądzę, skoro bf nie zna typów, ale to moja własna opinia, popraw mnie, jeśli się mylę.
  • Konieczne jest wdrożenie obsługujące (prawie) nieograniczone wartości.
  • W zależności od implementacji może być o wiele za wolny.

Program przetestowałem tylko z moim własnym tłumaczem, można go znaleźć tutaj .

Dane wejściowe muszą być liczbami oddzielonymi pojedynczą spacją ASCII.

Gra w golfa:

,>++++++[<----->-]<--[>,>++++++[<----->-]<--]>>>+<<<<[>>++++[<<---->>-]<<[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<,[>,]>>>+<<<<[>>+++++++[<<------->>-]<<+[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<<<<<[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Nie golfowany:

,
>++++++[<----->-]<--
[                                           # read input until space
    >,
    >++++++[<----->-]<--                    # decrease cell by 32 to check if it's a space
]
>>>+<<<<                                    # set multiplier to 1

[

    >>++++[<<---->>-]<<                     # decrease by 16 to get cell value of number

    [>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]        # multiply value by multiplier
    >>>>>[<<<<<+>>>>>-]                     # copy value back
    <[>++++++++++<-]>[<<+>>-]               # multiply multiplier by 10
    <<<<<                                   # go back to number

    [->+<]>[-<+>]                           # add value to next cell and move sum to previous cell

    <<                                      # go to next number
]

>>>>[-]<                                    # delete old multiplier

,[>,]                                       # read second number until end of input
>>>+<<<<                                    # set new multiplier

[

    >>+++++++[<<------->>-]<<+              # decrease by 48 to get cell value of number

    [>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]        # multiply value by multiplier
    >>>>>[<<<<<+>>>>>-]                     # copy value back
    <[>++++++++++<-]>[<<+>>-]               # multiply multiplier by 10
    <<<<<                                   # go back to number

    [->+<]>[-<+>]                           # add value to next cell and move sum to previous cell

    <<                                      # go to next number
]

>>>>[-]<<<<<                                # delete multiplier

[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>          # multiply both values

# magical algorithm for printing cell value as number taken from Cedric Mamo's code from a previous question
[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Dzięki autorowi wziąłem kod wyjściowy wartości z tej odpowiedzi !

Program może nie być prawidłowy, ale w każdym razie chciałem się z tobą podzielić ^^

Aktualizacja: Teraz można przetestować (tylko dla małych mnożenia) tutaj, dzięki @ SP3000 za odpowiedzi do tego konkursu i nowe Snippets Stos SE!

var NUM_CELLS = 30000;var ITERS_PER_SEC = 100000;var TIMEOUT_MILLISECS = 5000;function clear_output(){document.getElementById("output").value="";document.getElementById("stderr").innerHTML=""}function stop(){running=false;document.getElementById("run").disabled=false;document.getElementById("stop").disabled=true;document.getElementById("clear").disabled=false;document.getElementById("wrap").disabled=false;document.getElementById("timeout").disabled=false;document.getElementById("eof").disabled=false}function interrupt(){error(ERROR_INTERRUPT)}function error(e){document.getElementById("stderr").innerHTML=e;stop()}function run(){clear_output();document.getElementById("run").disabled=true;document.getElementById("stop").disabled=false;document.getElementById("clear").disabled=true;document.getElementById("wrap").disabled=true;document.getElementById("timeout").disabled=true;document.getElementById("eof").disabled=true;code=document.getElementById("code").value;input=document.getElementById("input").value;wrap=document.getElementById("wrap").value;timeout=document.getElementById("timeout").checked;eof=document.getElementById("eof").value;loop_stack=[];loop_map={};for(var e=0;e<code.length;++e){if(code[e]=="["){loop_stack.push(e)}else if(code[e]=="]"){if(loop_stack.length==0){error(ERROR_BRACKET);return}else{var t=loop_stack.pop();loop_map[t]=e;loop_map[e]=t}}}if(loop_stack.length>0){error(ERROR_BRACKET);return}running=true;start_time=Date.now();code_ptr=0;input_ptr=0;cell_ptr=Math.floor(NUM_CELLS/2);cells={};iterations=0;bf_iter(1)}function bf_iter(e){if(code_ptr>=code.length||!running){stop();return}var t=Date.now();for(var n=0;n<e;++n){if(cells[cell_ptr]==undefined){cells[cell_ptr]=0}switch(code[code_ptr]){case"+":if(wrap=="8"&&cells[cell_ptr]==255||wrap=="16"&&cells[cell_ptr]==65535||wrap=="32"&&cells[cell_ptr]==2147483647){cells[cell_ptr]=0}else{cells[cell_ptr]++}break;case"-":if(cells[cell_ptr]==0){if(wrap=="8"){cells[cell_ptr]=255}if(wrap=="16"){cells[cell_ptr]=65535}if(wrap=="32"){cells[cell_ptr]=2147483647}}else{cells[cell_ptr]--}break;case"<":cell_ptr--;break;case">":cell_ptr++;break;case".":document.getElementById("output").value+=String.fromCharCode(cells[cell_ptr]);break;case",":if(input_ptr>=input.length){if(eof!="nochange"){cells[cell_ptr]=parseInt(eof)}}else{cells[cell_ptr]=input.charCodeAt(input_ptr);input_ptr++}break;case"[":if(cells[cell_ptr]==0){code_ptr=loop_map[code_ptr]}break;case"]":if(cells[cell_ptr]!=0){code_ptr=loop_map[code_ptr]}break}code_ptr++;iterations++;if(timeout&&Date.now()-start_time>TIMEOUT_MILLISECS){error(ERROR_TIMEOUT);return}}setTimeout(function(){bf_iter(ITERS_PER_SEC*(Date.now()-t)/1e3)},0)}var ERROR_BRACKET="Mismatched brackets";var ERROR_TIMEOUT="Timeout";var ERROR_INTERRUPT="Interrupted by user";var code,input,wrap,timeout,eof,loop_stack,loop_map;var running,start_time,code_ptr,input_ptr,cell_ptr,cells,iterations
<div style="font-size:12px;font-family:Verdana, Geneva, sans-serif;"> <div style="float:left; width:50%;"> Code: <br> <textarea id="code" rows="4" style="overflow:scroll;overflow-x:hidden;width:90%;">,>++++++[<----->-]<--[>,>++++++[<----->-]<--]>>>+<<<<[>>++++[<<---->>-]<<[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<,[>,]>>>+<<<<[>>+++++++[<<------->>-]<<+[>>>>[>+>+<<-]>>[<<+>>-]<<<<<<-]>>>>>[<<<<<+>>>>>-]<[>++++++++++<-]>[<<+>>-]<<<<<[->+<]>[-<+>]<<]>>>>[-]<<<<<[>>[>+>+<<-]>>[<<+>>-]<<<<-]>>[-]>[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]</textarea> <br>Input: <br> <textarea id="input" rows="2" style="overflow:scroll;overflow-x:hidden;width:90%;">7 6</textarea> <p> Wrap: <select id="wrap"> <option value="8">8-bit</option> <option value="16">16-bit</option> <option value="32" selected="selected">32-bit</option> </select> &nbsp; Timeout: <input id="timeout" type="checkbox"></input>&nbsp; EOF: <select id="eof"> <option value="nochange">Same</option> <option value="0" selected="selected">0</option> <option value="-1">-1</option> </select> </p> </div> <div style="float:left; width:50%;"> Output: <br> <textarea id="output" rows="6" style="overflow:scroll;width:90%;"></textarea> <p> <input id="run" type="button" value="Run" onclick="run()"></input> <input id="stop" type="button" value="Stop" onclick="interrupt()" disabled="true"></input> <input id="clear" type="button" value="Clear" onclick="clear_output()"></input> &nbsp; <span id="stderr" style="color:red"></span></p></div></div>


Nie wiem też, czy to ważne! Myślę, że albo wszystko jest liczbą w Brainfuck, albo nic nie jest.
Nathaniel

Podoba mi się ta odpowiedź. Ostatnio bałam się bf. w pewien sposób rzuca światło na fakt, że na poziomie maszyny i tak wszystko jest tylko żetonami. Trudno powiedzieć, czy to naprawdę przestrzega zasad, czy nie.
Octopus

6

Python, 394 349 340 znaków

D='0123456789'
R=reversed
U=lambda x:[R for y in D if y<x]
T=U(':')
def A(a,b,r='',c=[]):
 for x,y in map(None,R(a),R(b)):
    d=U(x)+U(y)+c;t=T;c=[R]
    if d<T:t=c=[]
    r=min(k for k in D if U(k)+t>=d)+r
 if c:r='1'+r
 return r
a,b=input()
m=''
while b:
 if list(b).pop()in'13579':m=A(m,a)
 b=list(A(b,A(b,A(b,A(b,b)))));b.pop();a=A(a,a)
print m

Działaj jak:

echo '"9999999999","9999999999"' | ./mulstr.py

Trwa 50 milisekund.

Wykorzystuje rozmnażanie rosyjskiego chłopa . Podczas dodawania cyfr przekształcamy je w jednoargumentowe („5” => [R, R, R, R, R]), łączymy listy, a następnie przekształcamy z powrotem. Ukonwertuje na unarny, używając Rjako cyfry unarnej. Obliczamy b/=2jako b=b*5/10.


Kilka golfów: def A(a,b):\n r='';c=[]-> def A(a,b,r='',c=[]):, podobnie dla def M. Możesz być w stanie zmienić for z in D:d.pop()\n c=['X']na [d.pop()for z in D];c=['X'], w którym to przypadku możesz nawet zwinąć go do poprzedniego if. Ponadto może if list(b).pop()in'13579'być po prostu if b[:].pop()in'13579'?
Justin,

@Quincunx: Dzięki. Ostatni nie zadziała, ponieważ przy pierwszej iteracji bjest ciągiem, a nie listą.
Keith Randall

Możesz pominąć Mi napisać pełny program; a,b=input() jest dozwolone.
Justin

1
b * 5/10 to niezła sztuczka.
bazzargh

Właśnie natknąłem się na to reduce, co pozwala ci na A(b,A(b,A(b,A(b,b))))to reduce(A,[b,b,b,b,b]). Niestety nie wpływa to na liczbę postaci.
Wrzlprmft

5

JavaScript (E6) 375 395 411 449

Edycja golfed
Edit buga: brak rozliczeń flagę carry

Można to zrobić za pomocą manipulacji symbolami w czasie prawie 0.
W tej wersji możesz użyć dowolnego znaku zamiast cyfr, o ile symbol jest w porządku rosnącym.

Uwagi: używanie ciągów, mapa skrótów z kluczem ciągu, tablice używane jako lista. Bez indeksowania, tablice są przesuwane za pomocą „mapy” lub obracane za pomocą push & shift.
Wszystkie znaki „+” są łączeniem łańcuchowym.

M=(x,y,S=a=>a.shift()||z,R=a=>[...a].reverse(),e=R('9876543210'),d=[...e])=>
  R(y)[T='map'](b=>
     R(x)[T](a=>(
       u=R[e[a+=b]+v],
       v=R[S[a]+(u<v?'1':z)],
       p[P](t=R[S(o)+u]),
       t<u?v=R[v+'1']:v
     ),o=p,p=[])
    +(v>z&&p[P](v),x+=v=z),
    d[T](a=>d[T](b=>e[P='push'](R[a+b]=S(e)))+e[P](S(e))),  
    d[T](a=>d[T](b=>e[d[T](c=>v=c<a?(u=R[u+b])<b?R[v+'1']:v:v,v=u=z='0'),S[a+b]=v,a+b]=u)),
    p=[v=z]
  )&&R(p).join(o)

Mniej gra w golfa (może jutro dodam wyjaśnienie)

M=(x,y)=>(
  R=a=>[...a].reverse(),
  // Addition table s 
  s={},
  e=[...'9012345678'],
  [for(a of(d='0123456789'))for(b of(e.push(e.shift()),d))e.push(s[a+b]=c=e.shift())],
  // Multiplication table m,n
  m={},n={},
  [for(a of d)for(b of d)(
     [for(c of(z=u=v='0',d))
     c<a&&(t=s[u+b],t<u?v=s[v+'1']:v,u=t)
     ],m[a+b]=u,n[a+b]=v
  )],
  x=R(x),v=z,o=[],p=[],
  [for(b of R(y))(
     [for(a of x)(
       u=s[m[a+b]+v],v=s[n[a+b]+(u<v?'1':z)],
       p.push(t=s[(o.shift()||z)+u]),
       t<u?v=s[v+'1']:v
     )],
     v>z?p.push(v):o,o=p,p=[],x.unshift(v=z)
  )],
  R(o).join('')
)

Testuj w konsoli FireFox / FireBug

t0=-new Date
r=M('9999999999','9999999999')
t1=-new Date
console.log("Result",r, "time ms", t0-t1)

Wydajność

Result 99999999980000000001 time ms 14

Być może wystąpił niewielki błąd - wynik 9999999999powinien być 99999999980000000001, a nie99999999980000000081
Nathaniel

:( zamiar sprawdzić
edc65

Jeśli używasz tabliczki mnożenia, jak sobie radzisz z tym, że sumowanie jest niedozwolone?
COTO

1
Sumowanie JEST dozwolone przy użyciu tablicy hasht (s w kodzie). Dawny. s [„34”] -> „7”. Tylko symbole, a nie liczby. Może to być s ['cd'] -> 'g'
edc65

5

Haskell, 231 bajtów

Definiuje to operator #, który zwielokrotnia dwa ciągi znaków liczb naturalnych. Działa poprzez zdefiniowanie elementarnej operacji zwiększania / zmniejszania ciągów, a następnie wykorzystuje ją do budowania dodawania i mnożenia. Trochę dodatkowej magii daje wykładnicze przyspieszenia, które sprawiają, że wszystko jest możliwe ...

r=reverse
n="9876543210"
t=True
c&(x:y)|c==x=head y|t=c&y
m%[]="1";m%(c:s)|c==last m=head m:m%s|t=c&m:s
[]!y=y;x![]=x;(x:a)!('0':b)=x:a!b;x!y=(r n%x)!(n%y)
"0"?_="0";x?('0':y)|all(=='0')y="0"|t=('0':x)?y;x?y=x?(n%y)!x
x#y=r$r x?r y

To podejście jest na tyle szybkie, że nawet na laptopie z 2008 roku w niezoptymalizowanym ghci REPL przypadek testowy zajmuje zaledwie ułamek sekundy:

λ> :set +s
λ> let test = replicate 10 '9'
(0.00 secs, 0 bytes)
λ> test
"9999999999"
(0.00 secs, 1069784 bytes)
λ> test # test
"99999999980000000001"
(0.06 secs, 13451288 bytes)

Oto sprawdzenie, czy wszystkie dwucyfrowe produkty są poprawne:

λ> and [ show (x * y) == (show x # show y) | x <- [0..100], y <- [0..100] ]
True

Wygląda na to, że mamy nowego lidera! (Nie umiem jednak czytać Haskella - czy ktoś może samodzielnie potwierdzić, że pasuje do specyfikacji?)
Nathaniel

1
Tak, to doskonale cromulent haskell, pasuje do specyfikacji i działa zgodnie z reklamą. Dobra robota!
bazzargh

4

Bash + ImageMagick: 52

convert -size ${a}x${b} xc:red txt:-|grep -v g|wc -l

Oczekuje, że dane wejściowe będą w zmiennych powłoki ai b. Nie jest to szczególnie sprytne ani wydajne, ale wykonuje zadanie. Prawdopodobnie zostało to zrobione wcześniej.

Zauważ, że xoznacza wymiary obrazu; w tym kontekście nie jest operatorem arytmetycznym.

Nie testowałem tego, ale jestem gotów założyć, że w przypadku nie-ekstremalnych danych wejściowych, zakończy się ono w niecałą minutę. Mogę to przetestować jutro.

W przypadku jakiejkolwiek śmiesznej firmy z wersjami ImageMagick, używam tej: ImageMagick 6.7.7-10


Niezła próba, ale jestem pewien, że to nie zadziała w mniej niż minutę (lub w ogóle na żadnej istniejącej maszynie) dla danych wejściowych 9999999999i 9999999999.
Nathaniel

4
Działa to również: dd if=/dev/zero bs=$a count=$b 2>&-|wc -c.
jimmy23013

1
9999999999x9999999999Obraz w formacie 8bit zajmie wszystkie miejsca na dysku twardym, że obecnie istnieje na Ziemi. Oczywiście png byłby znacznie mniejszy, jeśli można go utworzyć bez uprzedniego utworzenia surowego obrazu. (Chociaż mocno podejrzewam, że miałbyś problemy z przepełnieniem liczb całkowitych w przypadku obrazu o takim rozmiarze). Mimo to, taka metoda prawie na pewno nie działałaby z powodu luki w nazywaniu rzeczy, które zwracają wyniki liczbowe.
Nathaniel

1
Możesz zapisać 2 bajty, używając $bzamiast ${b}.
nyuszika7h

1
Możesz także zapisać 5 bajtów, używając grep -vc gzamiast grep -v g|wc -l.
nyuszika7h

2

Python 2 (dowód koncepcji)

To rozwiązanie działa tylko przy użyciu ciągów i list oraz małego wyrażenia regularnego. Uważam, że pasuje to całkowicie do specyfikacji, z tym, że nie da się tego zrobić 9999999999x9999999999w ciągu minuty. Mimo wystarczającej ilości czasu to zadziała. Może dość szybko pomnożyć 4 cyfry.

Ponieważ jest to technicznie nieważne, nie zadałem sobie trudu, aby całkowicie go zagrać w golfa. Zrobię to, jeśli zasady się zmienią.

import re
D='123456789'
D=dict(zip('0'+D,D+'0'))

def toRlist(s):
    if s:t,h=re.match(r'(\d*)(\d)',s).groups();return[h,toRlist(t)]
    return''

def increment(r):
    if not r:return['1','']
    h,t=r
    return[D[h],increment(t)if h=='9'else t]

def toString(r):
    if not r:return''
    h,t=r
    return h+toString(t)

def listify(r,L):
    if not r:return
    h,t=r
    if h=='1':L.append('')
    if h=='2':L.extend(['',''])
    if h=='3':L.extend(['','',''])
    if h=='4':L.extend(['','','',''])
    if h=='5':L.extend(['','','','',''])
    if h=='6':L.extend(['','','','','',''])
    if h=='7':L.extend(['','','','','','',''])
    if h=='8':L.extend(['','','','','','','',''])
    if h=='9':L.extend(['','','','','','','','',''])
    listify(t,L);listify(t,L);listify(t,L);listify(t,L);listify(t,L)
    listify(t,L);listify(t,L);listify(t,L);listify(t,L);listify(t,L)

def add(r1,r2):
    L=[];listify(r2,L)
    for _ in L:r1=increment(r1)
    return r1

def multiply(a,b):
    total=''
    r=toRlist(a)
    L=[];listify(toRlist(b),L)
    for _ in L:total=r if total=='' else add(total,r)
    return''.join(reversed(toString(total)))

Przykłady:

multiply('12','5') #returns the string 60

multiply('1869','1243') #returns the string 2323167

1
+1, ponieważ spełnia specyfikację (oprócz wymogu wydajności), o ile mogę powiedzieć
Nathaniel

2

Python 2 (555)

Normalnie nie odpowiedziałbym tak szybko (lub wcale) na własne wyzwanie, ale chciałem udowodnić, że da się to zrobić. (Na szczęście niektóre inne odpowiedzi zrobiły to wcześniej, ale nie mogłem powstrzymać się od chęci ukończenia go.) Jest jeszcze trochę golfa, które można zrobić, ale myślę, że jest to uzasadnione. Obsługuje 9999999999x9999999999skrzynkę na moim komputerze w czasie poniżej 0,03 sekundy.

d="123456789";I=dict(zip('0'+d,d+'0'))
def r(x):return reversed(x)
def s(x):return''.join(x)
def i(x):
    try:
        h=I[x.next()]
        if h!='0':h+=s(x)
        else:h+=i(x)
        return h
    except:return'1'
def b(x,y):
    for c in'0'+d:
        if c==y:break
        x=iter(i(x))
    return x
def a(x,y):
    z=''
    for c in y:
        x=b(x,c)
        try:z+=x.next()
        except:z+='0'
    return z+s(x)
def n(x,y):
    z='0'
    for c in'0'+d:
        if c==y:break
        z=a(iter(z),x)
    return z
def o(x,y):
    x=s(x)
    l='';z=''
    for c in y:
        z=a(iter(z),l+s(n(x,c)))
        l+='0'
    return z
def m(x,y):
    return s(r(o(r(x),r(y))))

Przykładowe zastosowanie: m("12345","42")

Działa poprzez długie mnożenie za pomocą manipulacji ciągiem. Czasami zmienne są ciągami, a czasem iteratorami po ciągach, co umożliwia uzyskanie pierwszego elementu bez użycia literału całkowitoliczbowego. Wszystko jest przechowywane z odwróconymi cyframi, dzięki czemu pierwszy element jest najmniej znaczącą cyfrą.

Oto objaśnienie funkcji po funkcji:

  • ri ssą funkcjami księgowymi. ( rto tylko alias dla reversed, który tworzy iterator zwrotny i skonwertuje iteratory na ciągi znaków).

  • izwiększa liczbę w ciągu o 1, włączając przypadki takie jak 39+1=40i 99+1=100.

  • bdodaje xi y, ale ymusi być tylko jedną cyfrą. Działa poprzez zwiększenie x yczasu.

  • adodaje dwie liczby razem, które mogą mieć wiele cyfr, dzwoniąc bdla każdej cyfry w y.

  • nmnoży xi y, ale ymusi być tylko jedną cyfrą. Działa, dodając xdo siebie yczasy.

  • omnoży xi y, gdy oba argumenty mogą mieć wiele cyfr. Wykorzystuje klasyczne długie mnożenie

  • mpo prostu konwertuje wejściowe ciągi znaków na odwrotne iteratory i podaje je o, a następnie odwraca wynik i konwertuje je na ciąg znaków.


Kilka golfów: def a(x,y):-> def a(x,y,z=''):i usuń następną linię; Podobne sztuczki dla innych zadań, def o(x,y):zmień x=s(x)się x=s(x);l='';z='', że dla pętli, podobnie usunąć nowalinia + kroków; zamiast tego użyj ;. Myślę też, że if h!='0':h+=s(x)\nelse:h+=i(x)może po prostu być h+=h!='0'and i(x)or s(x); może nawet h+=(h!='0'and i or s)(x); w przeciwnym razie po prostu zmień na if'0'!=h. Także rzeczy takie jak def r(x):return reversed(x)->r=reversed
Justin

Również zapomniałem wspomnieć o s, m: s=lambda x:''.join(x), m=lambda x,y:s(r(o(r(x),r(y))))zamiast całej deklaracji funkcji. Dzięki tym, co wiem, działa, to zmniejsza liczbę bajtów do 521.
Justin

Aha i jeszcze jedno: dla twoich forpętli: for c in'0'+d:\nif c==y:break\nz=a(iter(z),x)-> for c in'0'+d:\nif c!=y:z=a(iter(z),x), chociaż może to znacznie zmienić szybkość twojego programu.
Justin

@Quincunx dzięki! Widzę też kilka innych ulepszeń dziś rano. (Przeważnie zagnieżdżanie pętli zamiast definiowania funkcji.) Dokonam tych zmian, jeśli pojawią się bardziej konkurencyjne odpowiedzi, co wydaje się prawdopodobne - obecnie dadzą mi przewagę, co wydaje się nieco niesprawiedliwe, ponieważ to było moje pytanie, a ja ” musieliśmy już o tym myśleć.
Nathaniel

2

JavaScript: 3710 3604 bajtów

  • Używanie tablic wyszukiwania ciągów z 1-cyfrowym mnożeniem i dodawanie z przeniesieniem.
  • Mnożenie odbywa się za pomocą cyfry x cyfry zamiast cyfry x linii.

Golf:

var M={
'00':'0','01':'0','02':'0','03':'0','04':'0','05':'0','06':'0','07':'0','08':'0','09':'0',
'10':'0','11':'1','12':'2','13':'3','14':'4','15':'5','16':'6','17':'7','18':'8','19':'9',
'20':'0','21':'2','22':'4','23':'6','24':'8','25':'10','26':'12','27':'14','28':'16','29':'18',
'30':'0','31':'3','32':'6','33':'9','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
'40':'0','41':'4','42':'8','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
'50':'0','51':'5','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
'60':'0','61':'6','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
'70':'0','71':'7','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
'80':'0','81':'8','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
'90':'0','91':'9','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81'
};
var A={
'000':'0','001':'1','002':'2','003':'3','004':'4','005':'5','006':'6','007':'7','008':'8','009':'9',
'010':'1','011':'2','012':'3','013':'4','014':'5','015':'6','016':'7','017':'8','018':'9','019':'10',
'020':'2','021':'3','022':'4','023':'5','024':'6','025':'7','026':'8','027':'9','028':'10','029':'11',
'030':'3','031':'4','032':'5','033':'6','034':'7','035':'8','036':'9','037':'10','038':'11','039':'12',
'040':'4','041':'5','042':'6','043':'7','044':'8','045':'9','046':'10','047':'11','048':'12','049':'13',
'050':'5','051':'6','052':'7','053':'8','054':'9','055':'10','056':'11','057':'12','058':'13','059':'14',
'060':'6','061':'7','062':'8','063':'9','064':'10','065':'11','066':'12','067':'13','068':'14','069':'15',
'070':'7','071':'8','072':'9','073':'10','074':'11','075':'12','076':'13','077':'14','078':'15','079':'16',
'080':'8','081':'9','082':'10','083':'11','084':'12','085':'13','086':'14','087':'15','088':'16','089':'17',
'090':'9','091':'10','092':'11','093':'12','094':'13','095':'14','096':'15','097':'16','098':'17','099':'18',
'100':'1','101':'2','102':'3','103':'4','104':'5','105':'6','106':'7','107':'8','108':'9','109':'10',
'110':'2','111':'3','112':'4','113':'5','114':'6','115':'7','116':'8','117':'9','118':'10','119':'11',
'120':'3','121':'4','122':'5','123':'6','124':'7','125':'8','126':'9','127':'10','128':'11','129':'12',
'130':'4','131':'5','132':'6','133':'7','134':'8','135':'9','136':'10','137':'11','138':'12','139':'13',
'140':'5','141':'6','142':'7','143':'8','144':'9','145':'10','146':'11','147':'12','148':'13','149':'14',
'150':'6','151':'7','152':'8','153':'9','154':'10','155':'11','156':'12','157':'13','158':'14','159':'15',
'160':'7','161':'8','162':'9','163':'10','164':'11','165':'12','166':'13','167':'14','168':'15','169':'16',
'170':'8','171':'9','172':'10','173':'11','174':'12','175':'13','176':'14','177':'15','178':'16','179':'17',
'180':'9','181':'10','182':'11','183':'12','184':'13','185':'14','186':'15','187':'16','188':'17','189':'18',
'190':'10','191':'11','192':'12','193':'13','194':'14','195':'15','196':'16','197':'17','198':'18','199':'19'
} 
Array.prototype.e=function(){return(''+this)==='';}
String.prototype.s=function(){return this.split('').reverse();}
function B(a,b,c) {
var r='',s='';
a=a.s();
b=b.s();
while (!a.e()||!b.e()||c!=='0') {
x=a.e()?'0':a.shift();
y=b.e()?'0':b.shift();
s=A[c+x+y];
s=s.s();
r=s.shift()+r;
c=s.e()?'0':'1';
}
return r;
}
function m(a,b) {
var s='0',m='';
b.split('').reverse().forEach(function(e){
var z=m;
a.split('').reverse().forEach(function(f){s=B(s,M[e+f]+z,'0');z+='0';});
m+='0';
});
return s;
}

Niepoddane testom:

var mul = {
'00':'0','01':'0','02':'0','03':'0','04':'0','05':'0','06':'0','07':'0','08':'0','09':'0',
'10':'0','11':'1','12':'2','13':'3','14':'4','15':'5','16':'6','17':'7','18':'8','19':'9',
'20':'0','21':'2','22':'4','23':'6','24':'8','25':'10','26':'12','27':'14','28':'16','29':'18',
'30':'0','31':'3','32':'6','33':'9','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
'40':'0','41':'4','42':'8','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
'50':'0','51':'5','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
'60':'0','61':'6','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
'70':'0','71':'7','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
'80':'0','81':'8','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
'90':'0','91':'9','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81'
};

var adc = {
'000':'0','001':'1','002':'2','003':'3','004':'4','005':'5','006':'6','007':'7','008':'8','009':'9',
'010':'1','011':'2','012':'3','013':'4','014':'5','015':'6','016':'7','017':'8','018':'9','019':'10',
'020':'2','021':'3','022':'4','023':'5','024':'6','025':'7','026':'8','027':'9','028':'10','029':'11',
'030':'3','031':'4','032':'5','033':'6','034':'7','035':'8','036':'9','037':'10','038':'11','039':'12',
'040':'4','041':'5','042':'6','043':'7','044':'8','045':'9','046':'10','047':'11','048':'12','049':'13',
'050':'5','051':'6','052':'7','053':'8','054':'9','055':'10','056':'11','057':'12','058':'13','059':'14',
'060':'6','061':'7','062':'8','063':'9','064':'10','065':'11','066':'12','067':'13','068':'14','069':'15',
'070':'7','071':'8','072':'9','073':'10','074':'11','075':'12','076':'13','077':'14','078':'15','079':'16',
'080':'8','081':'9','082':'10','083':'11','084':'12','085':'13','086':'14','087':'15','088':'16','089':'17',
'090':'9','091':'10','092':'11','093':'12','094':'13','095':'14','096':'15','097':'16','098':'17','099':'18',
'100':'1','101':'2','102':'3','103':'4','104':'5','105':'6','106':'7','107':'8','108':'9','109':'10',
'110':'2','111':'3','112':'4','113':'5','114':'6','115':'7','116':'8','117':'9','118':'10','119':'11',
'120':'3','121':'4','122':'5','123':'6','124':'7','125':'8','126':'9','127':'10','128':'11','129':'12',
'130':'4','131':'5','132':'6','133':'7','134':'8','135':'9','136':'10','137':'11','138':'12','139':'13',
'140':'5','141':'6','142':'7','143':'8','144':'9','145':'10','146':'11','147':'12','148':'13','149':'14',
'150':'6','151':'7','152':'8','153':'9','154':'10','155':'11','156':'12','157':'13','158':'14','159':'15',
'160':'7','161':'8','162':'9','163':'10','164':'11','165':'12','166':'13','167':'14','168':'15','169':'16',
'170':'8','171':'9','172':'10','173':'11','174':'12','175':'13','176':'14','177':'15','178':'16','179':'17',
'180':'9','181':'10','182':'11','183':'12','184':'13','185':'14','186':'15','187':'16','188':'17','189':'18',
'190':'10','191':'11','192':'12','193':'13','194':'14','195':'15','196':'16','197':'17','198':'18','199':'19'
} 

Array.prototype.isEmpty = function() {
  return (''+this) === '';
}

function add(a, b, c) {
  var r = '', s = '';
  a = a.split("").reverse();
  b = b.split("").reverse();
  while (!a.isEmpty() || !b.isEmpty() || c !== '0') {
    x = a.isEmpty() ? '0' : a.shift();
    y = b.isEmpty() ? '0' : b.shift();
    s = adc[c + x + y];
    s = s.split("").reverse();
    r = (s.shift()) + r;
    c = (s.isEmpty()) ? '0' : '1';
  }
  return r;
}

function mult(a, b) {
  var s = '0';
  var m = '';
  b.split('').reverse().forEach(function(e) {
    var z = m;
    a.split('').reverse().forEach(function(f) {
      s = add(s, mul[e + f] + z, '0');
      z = z + '0';
    });
    m = m + '0';
  } );
  return s;
}

function test(a, b) {
  var t0 = (new Date()).getTime();
  var r = mult(a,b);
  var t1 = (new Date()).getTime();
  var e = t1 - t0;
  console.log('mult ' + a + ' * ' + b + ' = ' + r + " (" + e + " ms)");
}

test('12345', '42');
test('9999999999', '9999999999');

To daje:

mult 12345 * 42 = 518490 (3 ms) 
mult 9999999999 * 9999999999 = 99999999980000000001 (47 ms) 

2

Haskell 507 496

Działa to dla dowolnie dużych liczb całkowitych. Definiuję niestandardowe reprezentacje liczb naturalnych od 0 do 18 (największa liczba naturalna równa sumie dwóch cyfr) i definiuję mnożenie endianu za pomocą mnożenia cyfr * liczby, które definiuję pod względem liczby + dodawania liczb , które definiuję w kategoriach cyfry + dodawania cyfr. Mam funkcję redukcji, która rozszerza wartości 10-18 na ich cyfrowy rozkład. To po prostu czyta i odwraca dwa ciągi, tłumaczy na niestandardowe wiązania, mnoży i tłumaczy z powrotem, odwracając, aby uzyskać właściwy wynik.

Edytuj 2

Zapisałem kilka znaków, tworząc krótkie lokalne aliasy dla poleceń wieloznakowych, których używam więcej niż jeden raz, a także usuwając spacje i nawiasy oraz zastępując (- )parami, $jeśli to możliwe.

data S=Z|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R deriving(Enum, Ord, Eq)
p Z=id
p x=succ.p(pred x)
s Z=id
s x=pred.s(pred x)
z=s J
r[]=[]
r(x:y)|x<J=x:r y
r(x:[])=z x:[A]
r(x:y)=z x:(r$p A a:b)where(a:b)=r y
a x y=r$w(r x)(r y)
m Z _=[]
m _[]=[]
m x y=r$a y(m(pred x)y)
t[]_=[Z]
t _[]=[Z]
t(x:z)y=r$a(m x y)(Z:r(t z y))
i '0'=Z
i x=succ.i.pred$x
b Z='0'
b x=succ.b.pred$x
w[]y=y
w x[]=x
w(x:c)(y:d)=p x y:(w c d)
o=map
v=reverse
f=(o i).v
g=v.o b
main=getLine>>=putStrLn.(\[x,y]->g$t(f x)(f y)).words

Dla porównania, S jest niestandardowym typem danych typu całkowitoliczbowego, pto „plus” (cyfra + dodanie cyfry), sjest odejmowanie (w celu zmniejszenia), rjest zmniejszane (rozszerzanie do rozkładu cyfrowego), ato dodawanie (liczba + dodawanie liczb), mto mnożyć (mnożenie cyfry * liczby), tto razy (mnożenie liczby * liczby), ito „interpretować” (konwertować ciąg znaków na listę S), bto „wstecz” (lista S na ciąg znaków), a f i g to tylko skróty do gry w golfa cele. Nie użyłem liczb, nawet domyślnie; najbliższe mi było użycie następców i poprzedników, które są koncepcjami matematycznymi na wyższym poziomie niż dodawanie i mnożenie liczb naturalnych.

Edytować

Zapomniałem dołączyć profil czasowy.

> time echo "9999999999 9999999999" | runhaskell multnonum.hs
99999999980000000001

real    0m0.246s
user    0m0.228s
sys     0m0.012s

Na wszelki wypadek:

> time echo "99999999980000000001 99999999980000000001" | runhaskell multnonum.hs
9999999996000000000599999999960000000001

real    0m0.244s
user    0m0.224s
sys     0m0.016s

Chodźmy szaleni!

> time echo "9999999996000000000599999999960000000001 9999999996000000000599999999960000000001" | runhaskell multnonum.hs
99999999920000000027999999994400000000699999999944000000002799999999920000000001

real    0m0.433s
user    0m0.424s
sys     0m0.004s

potwierdzenie


1

Python 2 - 1165, 712, 668 664

I,T,V,N,X,J=raw_input,dict,reversed,None,zip,''.join
D='0123456789'
z,o='01'
A,B=I(),I()
r=i=""
K=map(J,X('666622222222911111551111555884444447773333333','678945672389954132987698765898967457989837654'))
P=T(X(K,map(J,X('344501110011800000440000332673322124652202211','628480244668154132507698505422648609367491852'))))
S=T(X(K,'cdef678945abi65243ed87a9cbaghcdab89egfcb6a987'))
for d in D:P[z+d]=z;S[z+d]=d
def Z(A,B,R=r):
 for a,b in V(map(N,V(z+A),V(z+B))):c=(a or z)+(b or z);s=S[min(c)+max(c)];R=Z(R,o)+T(X('abcdefghi',D))[s]if s>"?"else R+s
 return R
for a in V(A):
 j=""
 for b in V(B):r=Z(r,P[min(a+b)+max(a+b)]+i+j).lstrip(z);j+=z
 i+=z
print r if r else z

Zauważ, że nie używam logicznego indeksowania Z = [X, Y][N == "0"], ponieważ może to być interpretowane jako wartość logiczna rzutowana na indeks numeryczny.

Nie golfowany:

A = raw_input()
B = raw_input()

P = {'00':'00','01':'00','02':'00','03':'00','04':'00','05':'00','06':'00','07':'00','08':'00','09':'00',
     '10':'00','11':'01','12':'02','13':'03','14':'04','15':'05','16':'06','17':'07','18':'08','19':'09',
     '20':'00','21':'02','22':'04','23':'06','24':'08','25':'10','26':'12','27':'14','28':'16','29':'18',
     '30':'00','31':'03','32':'06','33':'09','34':'12','35':'15','36':'28','37':'21','38':'24','39':'27',
     '40':'00','41':'04','42':'08','43':'12','44':'16','45':'20','46':'24','47':'28','48':'32','49':'36',
     '50':'00','51':'05','52':'10','53':'15','54':'20','55':'25','56':'30','57':'35','58':'40','59':'45',
     '60':'00','61':'06','62':'12','63':'18','64':'24','65':'30','66':'36','67':'42','68':'48','69':'54',
     '70':'00','71':'07','72':'14','73':'21','74':'28','75':'35','76':'42','77':'49','78':'56','79':'63',
     '80':'00','81':'08','82':'16','83':'24','84':'32','85':'40','86':'48','87':'56','88':'64','89':'72',
     '90':'00','91':'09','92':'18','93':'27','94':'36','95':'45','96':'54','97':'63','98':'72','99':'81',
     }
S = {'00':'0','01':'1','02':'2','03':'3','04':'4','05':'5','06':'6','07':'7','08':'8','09':'9',
     '10':'1','11':'2','12':'3','13':'4','14':'5','15':'6','16':'7','17':'8','18':'9','19':'a',
     '20':'2','21':'3','22':'4','23':'5','24':'6','25':'7','26':'8','27':'9','28':'a','29':'b',
     '30':'3','31':'4','32':'5','33':'6','34':'7','35':'8','36':'9','37':'a','38':'b','39':'c',
     '40':'4','41':'5','42':'6','43':'7','44':'8','45':'9','46':'a','47':'b','48':'c','49':'d',
     '50':'5','51':'6','52':'7','53':'8','54':'9','55':'a','56':'b','57':'c','58':'d','59':'e',
     '60':'6','61':'7','62':'8','63':'9','64':'a','65':'b','66':'c','67':'d','68':'e','69':'f',
     '70':'7','71':'8','72':'9','73':'a','74':'b','75':'c','76':'d','77':'e','78':'f','79':'g',
     '80':'8','81':'9','82':'a','83':'b','84':'c','85':'d','86':'e','87':'f','88':'g','89':'h',
     '90':'9','91':'a','92':'b','93':'c','94':'d','95':'e','96':'f','97':'g','98':'h','99':'i',
     }
L = {'a':'0','b':'1','c':'2','d':'3','e':'4','f':'5','g':'6','h':'7','i':'8'}

def strSum(A, B):
    R = ""
    for a, b in reversed(map(None, reversed("0" + A), reversed("0" + B))):
        if a == None: a = '0'
        if b == None: b = '0'
        s = S[a + b]
        if s.isdigit():
            R += s
        else:
            R = strSum(R, "1") + L[s]
    return R

i = ""
r = "0"
for a in reversed(A):
    j = ""
    for b in reversed(B):
        p = P[a + b] + i + j
        r = strSum(r, p)
        j += "0"
    i += "0"

r = r.lstrip("0")
if r == "":
    r = "0"

print r

Powiedziałbym, że używanie funkcji min () i max () nie powinno być dozwolone, ponieważ porównują one rzeczywiste wartości całkowite, prawda?
WorldSEnder

@WorldSEnder: Powiedziałbym, że porównują postacie, co jest dozwolone w tym wyzwaniu. („Dozwolone jest porównywanie leksykograficzne znaków”.)
Falko,

1

Scala, 470 znaków

( są standardowe scala, ale można je zastąpić, =>jeśli liczymy bajty)

def p(a: String,b: String)={type D=List[Char]
val d="0123456789".toList
def v(s: String)=s.toList.map{c⇒d.takeWhile(c.!=)}
def u(l:D, a:D):(Char,D)=l match {
case _::_::_::_::_::_::_::_::_::_::m⇒u(m,'a'::a)
case _⇒(('a'::l).zip(d).last._2,a)}
val o=(("", List[Char]())/:v(a).tails.toList.init.map{l⇒(v(b) map {_.flatMap(_⇒l.head)})++l.tail.map(_⇒Nil) reverse}.reduce(_.zipAll(_, Nil, Nil).map{t⇒t._1++t._2}))({(t,e)⇒val s=u(t._2++e,Nil);(s._1+t._1,s._2)})
u(o._2, Nil)._1+o._1}

Tutaj emulujemy cyfry na podstawie długości list, uważając, aby nie używać żadnych operacji numerycznych - tylko fałdy, mapy, zamki błyskawiczne i tym podobne. Liczba to lista tych cyfr (kolejność strategicznie odwrócona w połowie obliczeń); mnożymy poszczególne cyfry flatMapi nasze wiersze w górę reduce. uradzi sobie z wykrywaniem przeniesienia (przez bezpośrednie dopasowanie do listy> 10 elementów i rekurencją) i konwertowaniem cyfr z powrotem na znaki, a my używamy do tego, /:aby przejść przez stos. Wymagany przykład kończy się w niecałą sekundę.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.