Multiplique dois números sem usar números

30

Você recebe como entrada duas seqüências que representam números inteiros positivos na base 10, como "12345"e "42". Sua tarefa é gerar uma string contendo o produto deles, "518490"neste caso.

A desvantagem é que você não pode usar nenhum tipo numérico no seu código. Não ints, floats, unsigned longs, etc., nenhum tipo de número complexo interno ou números inteiros de precisão arbitrários, ou qualquer coisa nesse sentido. Muitos não usam literais desses tipos, nem qualquer função, método, operador etc. que os retorne.

Você pode usar strings, booleanos, matrizes ou qualquer outra coisa que normalmente não seria usada para representar um número. (Mas observe que nem é provável que seja possível indexar em uma matriz nem obter seu comprimento sem chamar um tipo numérico.) charS são permitidos, mas você não pode executar operações aritméticas ou bit a bit nelas ou tratá-las como qualquer outra coisa além de um token que representa parte de uma sequência. (A comparação lexicográfica de chars é permitida.)

Você não pode contornar a restrição. Isso inclui (sem limitação) o uso de tipos numéricos dentro de uma evalfunção de tipo, conversões implícitas de tipos em tipos numéricos, uso de operadores numéricos ou bit a bit em tipos não numéricos que os suportam, uso de tipos numéricos armazenados em tipos de contêiner ou funções de chamada ou programas externos que retornam resultados numéricos em forma de sequência. (Eu me reservo o direito de adicionar a esta lista se outras soluções alternativas aparecerem nas respostas.) Você deve implementar a multiplicação por conta própria usando apenas tipos não numéricos.

A entrada e a saída podem ser de qualquer método conveniente, desde que os dados entrem e saiam do seu código na forma de uma string. Você pode assumir que cada um dos dois argumentos de entrada contém apenas os caracteres ASCII [0-9]e não será iniciado 0. Sua saída também não deve ter zeros à esquerda.

Só mais uma coisa: o seu código deve lidar corretamente com entradas até , pelo menos, 10 caracteres de comprimento , e deve ser executado em menos de um minuto em um computador moderno para todas as entradas nesse intervalo. Antes de postar, verifique se, ao receber entradas 9999999999e 9999999999, seu programa fornece uma saída de 99999999980000000001, em menos de um minuto. Essa restrição existe especificamente para impedir respostas que funcionem, alocando uma matriz de tamanho a*be, em seguida, repetindo-a; portanto, lembre-se de que as respostas desse formulário não serão elegíveis para vitória.

Isso é , então a solução válida mais curta (em bytes) vence.

Nathaniel
fonte
Podemos aceitar "12345"do STDIN em vez de 12345? Ou podemos aceitar os dois números como "12345", "42"?
24714 Justin
Meu primeiro pensamento foi para escrever uma função que toma argumentos de seqüência de comprimento me ne retornando um argumento de comprimento m*n. Mas como as strings precisam literalmente conter a representação ASCII dos números, acho que isso é contra as regras.
Level River St
1
@xnor em muitos idiomas, pode ser mais curto escrever todos os casos. Mas eu encontrei este caminho em Python:a,b="0123456789x".split('0');c=iter(b).next() if c=='x': c='0'
Nathaniel
1
ou em Python 3,a,b="0123456789x".split(x);c,*d=b if c=='x': c='0'
Nathaniel
2
@Nathanield='123456789';I=dict(zip('0'+d,d+'0'))
Justin

Respostas:

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

Implementa a multiplicação por adição repetida e todos os tipos de magia de dígitos são manipulados deslocando e filtrando a ['0'..'9']lista. Define um operador #do tipo String -> String -> String:

*> :set +s
*> "9990123456789"#"9999876543210"
"99900001219316321126352690"
(0.02 secs, 9862288 bytes)
mniip
fonte
Parece que temos um novo vencedor! (Embora, como antes, eu não posso ler Haskell deste grau de sofisticação - alguém pode verificar de forma independente atende a especificação?)
Nathaniel
(Também o ['0' .. '9'] parece um pouco implicitamente tratar chars como números que podem ser iterados - existe uma maneira curta de gerar essa lista a partir da string "0123456789"?)
Nathaniel
@ Nathaniel Bem, primeiro de tudo, a string "0123456789" é a lista ['0'..'9']. Segundo, em Haskell [a..b] é uma enumeração, os tipos que declararam instâncias da Enumclasse de tipo podem ser enumerados assim, e a declaração descreve como a enumeração funciona. Bool, o tipo booleano também possui uma instância e, portanto, você também pode fazê-lo [False..True]. Quase não há números envolvidos.
Mniip
14

sed, 339 338 bytes

Sei que é antigo, mas estava navegando e isso despertou meu interesse. O suficiente para realmente se registrar como usuário! Eu acho que fiquei impressionado com " eu gostaria de ver uma solução sed completa - 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

Esse script sed espera dois números decimais como entrada, separados por um espaço

testes:

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

Você pode reconhecer os dois últimos como RSA-100 (50 x 50 dígitos) e RSA-768 (116 x 116 dígitos).

Usando o GNU sed em um não-moderno (Intel Core 2 da era de 2007), o último deles demora mais de um minuto, mas é mais rápido em um processador mais recente:

  • Q6600:> 1 minuto
  • i7-3770: 26 segundos
  • i7-6700: 22 segundos

A multiplicidade insignificante de 10 dígitos especificada na pergunta leva bem menos de um segundo em qualquer uma delas (apesar de estar cheia de noves patológicos).

Eu acredito que é sed padrão, sem extensões. As garantias POSIX mantêm apenas 8192 bytes de espaço, o que nos limita à multiplicação de números de 400x400 dígitos, mas as implementações podem fornecer mais. O GNU sed é limitado apenas pela memória disponível; portanto, pode gerenciar algo muito maior, se você estiver disposto a esperar.

E estou confiante de que cumpri as regras - isso é quase um dado em um idioma que não tem números. :-)

Explicação

Eu uso um híbrido unário / decimal, convertendo números decimais em uma sequência de unário:

 42 => _xxxx_xx

Em decimal unário, a adição é fácil. Nós iteramos do dígito menos significativo para o mais significativo, concatenando os x's:

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

Em seguida, removemos o espaço em branco e lidamos com carry convertendo 10 x consecutivos em uma das próximas unidades:

 _xxxxxxxxxx_xxxxxx_xxxxxxxxxxx       10.6.11
 _xxxxxxxxxx_xxxxxxx_x                10.7.1
 _x__xxxxxxx_x                        1.0.7.1 

Uma vez que tenhamos adição, é possível multiplicar. Multiplicamos x * y considerando o último dígito de y. Adicione x ao acumulador várias vezes, depois vá para o próximo dígito e desloque x uma casa decimal à esquerda. Repita até y ser zero.

Código expandido

#!/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
Toby Speight
fonte
1
Resposta muito satisfatória, obrigado!
Nathaniel
9

sed, 379 bytes

O crédito por essa resposta brilhante vai para @LuigiTiburzi no Unix e Linux.SE: https://unix.stackexchange.com/a/37213/34061 . Acabei de tropeçar nisso há alguns dias:

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

Explicação geral

  • Separe cada dígito. Assim 12*3se torna<1<2*<3
  • Converta cada dígito para esse número de |caracteres. Assim <1<2*<3se torna<|<||*<|||
  • Substitua repetidamente |<por <||||||||||para mudar as casas decimais mais altas para a posição das unidades. Assim <|<||*<|||se torna<||||||||||||*<|||
  • Retire <. Assim <||||||||||||*<|||se torna||||||||||||*|||
  • Remova 1 |do RHS do *. Assim ||||||||||||*|||se torna||||||||||||*||
  • Substitua repetidamente cada um |no RHS por todos |no LHS. Isso tem o efeito de multiplicar o número LHS e RHS de |para fornecer o número do produto | Assim, ||||||||||||*||torna-se||||||||||||||||||||||||||||||||||||*
  • Retire *. Assim ||||||||||||||||||||||||||||||||||||*se torna||||||||||||||||||||||||||||||||||||
  • converta o número de |volta para decimal pelo inverso das primeiras etapas. Assim ||||||||||||||||||||||||||||||||||||se torna 36.

Saída:

$ 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
$

Infelizmente, ele falha miseravelmente no requisito de tempo - 200*1000leva 41 segundos na minha VM do Ubuntu, e o tempo de execução parece empírico com o quadrado do produto final.

Trauma Digital
fonte
1
Isso é quase algoritmicamente equivalente à minha resposta JS excluída, exceto pela conversão de volta para a parte numérica.
Optimizer
@Optimizer concordou. A diferença é que o seu usa o length()que retorna um número. Este usa substituição puramente regex sem tipos numéricos. Acho que sua resposta é potencialmente vencedora, se você puder remover a length()- talvez você possa fazer uma substituição de regex semelhante em seu lugar?
Digital Trauma
1
Muito bom, mas a restrição de um minuto destina-se especificamente a impedir soluções que funcionem contando até a resposta. Eu gostaria bastante de ver uma solução sed completa.
Nathaniel
1
Eu tenho uma resposta que funciona em grandes números (por exemplo, maior que o espaço de endereço do sistema).
Toby Speight
@TobySpeight sim, muito bom. Eu acho que deve ter seu já upvoted uma volta, enquanto :)
Trauma Digital
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")

Se (muitos) zeros à esquerda forem permitidos, os últimos 12 caracteres não serão necessários.

Isso essencialmente executa a multiplicação padrão manualmente. Os dígitos são representados como seqüências de caracteres Is repetidos (como números romanos primitivos). Os números são representados como listas de dígitos na ordem inversa. A adição de um dígito é realizada co-codificando cadeias e removendo dez Isegundos, se necessário.

Aqui está uma versão não destruída:

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())
Wrzlprmft
fonte
1
O que é essa feitiçaria! Como funciona! Uau. Além disso, aqui está outro golfe que você poderia fazer: def A(x,y):\n S=[];o=""-> def A(x,y,S=[],o=""):. Além disso, infelizmente, ["","1"][t in i]não é permitido; está usando um bool para indexar, tratando-o como um número. Eu acho que isso t in i and"1"or""deve funcionar, no entanto.
Justin
@ Quincunx: Definir Scomo argumento com um padrão não teria funcionado, pois sempre seria a mesma lista mesmo para chamadas diferentes da função e, portanto, não será redefinida para []. Você estava certo ["","1"][t in i], eu consertei isso. Eu também adicionei uma explicação.
Wrzlprmft
Isso é incrível. Recebe o sinal verde por enquanto. (Eu editei a questão de esclarecer que zeros à esquerda na saída não são permitidos - sorry)
Nathaniel
7

Ruby: 752 698

Isso é apenas para obter uma resposta lá fora, apenas por curiosidade. Editado: agora jogou um pouco de golfe.

$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)

Uso: Eu tinha isso em um arquivo chamado peasant.rb:

$ time ruby peasant.rb 9999999999 9999999999
99999999980000000001

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

Explicação: é uma multiplicação camponesa, então eu repetidamente reduzi pela metade e dobro. A metade é feita pela metade dos dígitos e marcando os restantes itens da seguinte forma: 1234 -> 0b1a1b2a; encontre e substitua nos b: 06a17a; depois limpando -> 617.

A adição é feita assim ... primeiro, eu ponho as duas cordas no mesmo comprimento e faço pares a partir dos dígitos. Então eu adiciono os dígitos construindo uma string que tem o comprimento de cada dígito e concatenando; Eu removo uma sequência desse comprimento desde o início de '0123456789abcdefghij' e mantenho o primeiro caractere. Então, por exemplo, "9" + "9" -> "i". NB: Evito realmente usar funções de comprimento aqui para evitar tipos de números inteiramente; a remoção do prefixo é feita com um regexp.

Então agora eu tenho uma string contendo uma mistura de dígitos e letras. As letras representam números com um dígito de transporte; Anexo 0 ao número e substituo repetidamente os padrões de letras de dígitos pelo resultado do transporte até que a adição esteja completa.

bazzargh
fonte
1
Resposta muito inteligente, exatamente o tipo de coisa que eu esperava ver!
Nathaniel
1
Na verdade, espero que alguém publique um com numerais da Igreja!
bazzargh
Isso seria legal, embora eu não tenho certeza se ele iria trabalhar com o requisito de eficiência - Eu acho que a conversão entre cordas e numerais Igreja seria efetivamente envolver contar até 99999999980000000001.
Nathaniel
7

Brainfuck (1328 bytes)

Considerações a princípio:

  • Não tenho certeza se brainfuck é uma resposta válida para essas perguntas, pois não tenho certeza se você considera os valores das células como 'tipos numéricos' ou não. Acho que não, já que bf não conhece tipos, mas essa é minha opinião, por favor, corrija-me se estiver errado.
  • É necessária uma implementação que suporte valores (quase) ilimitados.
  • Pode ser muito lento, com base na implementação.

Eu só testei o programa com meu próprio intérprete, você pode encontrá-lo aqui .

A entrada deve ser os dois números separados por um único espaço ASCII.

Golfe:

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

Ungolfed:

,
>++++++[<----->-]<--
[                                           # 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
[<+>-]<[>>+>+<<<-]>>>[<<<+>>>-]<[[-]<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<-]>[<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<->>[-]]+>-]<-]<<+>]<[>>+<<-]>>[<<<[>+>+<<-]>>[<<+>>-]>-]<<[<<->>-]<[-]<[>>>>>>>>+<<<<<<<<-]>>>>>>>>>[>>]+[<<]>[>[>>]<+<[<<]>-]<<<<<<<<<<[>>+>+<<<-]>>>[<<<+>>>-]+[<+>-]<<<[-]>>[<<+>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]++++++++++<[>>+<<-]>>[<[>>+>+<<<-]>>>[<<<+>>>-]<[>+<<-[>>[-]>+<<<-]>>>[<<<+>>>-]<[<-[<<<->>>[-]]+>-]<-]<<<+>>]<[-]<<<<[-]>>>[<<<+>>>-]<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[<+>-]<]<[>+>+<<-]>>[<<+>>-]<[>+<[-]]+>[<[-]<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<[[-]>>>>>>>>[>>]<[<[<<]<<<<<+>>>>>>>[>>]<-]<-<<[<<]<<<<<>++++++++++++++++++++++++++++++++++++++++++++++++[<+>-]<.[-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]+[<->-]<<<<<[-]>>>>[<<<<+>>>>-]<<<<[>>>>+>+<<<<<-]>>>>>[<<<<<+>>>>>-]<[<+>-]<]<[-]]<[>>++++++[<++++++++>-]<.[-]<[-]]<[-]<[-]>>>>>>>>>>>>[>[-]>]<<[-<<]<<<<<<<<<<<<<<<<<[-]<[-]

Eu peguei o código para a saída do valor desta resposta , obrigado ao autor por isso!

O programa pode não ser válido, mas de qualquer forma eu queria compartilhar com você ^^

Atualização: Agora você pode testá-lo (apenas para pequenas multiplicações) aqui, graças à resposta do @ Sp3000 a este concurso e aos novos Snippets de pilha do 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>

Cifra
fonte
Também não sei se é válido! Eu acho que ou tudo é um número em Brainfuck, ou nada é.
Nathaniel
Eu gosto desta resposta. Eu tenho mexido comigo ultimamente. meio que lança luz sobre o fato de que, no nível da máquina, tudo é apenas um sinal de qualquer maneira. Difícil dizer se isso realmente segue as regras ou não.
Octopus
6

Python, 394 349 340 caracteres

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

Executar como:

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

Leva 50 milissegundos.

Usa a multiplicação do camponês russo . Ao adicionar dígitos, os convertemos em unários ('5' => [R, R, R, R, R, R]), concatenamos as listas e depois convertemos de volta. Uconverte para unário, usando Rcomo dígito unário. Computamos b/=2como b=b*5/10.

Keith Randall
fonte
Um par de golfe: def A(a,b):\n r='';c=[]-> def A(a,b,r='',c=[]):, da mesma forma para def M. Você pode mudar for z in D:d.pop()\n c=['X']para [d.pop()for z in D];c=['X'], nesse caso, pode até recolocá-lo no anterior if. Além disso, pode if list(b).pop()in'13579'ser apenas if b[:].pop()in'13579'?
Justin
@ Quincunx: Obrigado. O último não funcionará porque, na primeira iteração, bé uma sequência, não uma lista.
Keith Randall
Você pode pular Me escrever um programa completo; a,b=input() é permitido.
Justin
1
b * 5/10 é um bom truque.
bazzargh
Acabei de me reducedeparar A(b,A(b,A(b,A(b,b))))com isso, o que permite que você ame reduce(A,[b,b,b,b,b]). Infelizmente, isso não afeta a contagem de caracteres.
Wrzlprmft
5

JavaScript (E6) 375395 411449

Edit Golfed
Edit Bug corrigido: falta de limpeza de uma bandeira de transporte

Isso pode ser feito apenas com manipulação de símbolos em quase 0 tempo.
Nesta versão, você pode usar qualquer caractere em vez dos dígitos, desde que o símbolo esteja em ordem crescente.

Notas: usando strings, hashmap com chave de string, matrizes usadas como lista. Sem indexação, as matrizes são percorridas usando 'map' ou giradas usando push & shift.
Todos os '+' são concatenações de strings.

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)

Menos golfe (talvez eu adicione uma explicação amanhã)

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('')
)

Teste no console do FireFox / FireBug

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

Saída

Result 99999999980000000001 time ms 14
edc65
fonte
Possivelmente, há um pequeno bug - a saída do 9999999999caso deve ser 99999999980000000001, não #99999999980000000081
Nathaniel
:( indo para verificar
edc65
Se você estiver usando tabelas de multiplicação, como está contornando o fato de que a soma não é permitida?
COTO 24/10
1
A soma É permitida usando uma hashtable (s no código). Ex. s ['34 '] ->' 7 '. Apenas símbolos, não números. Pode ser s ['cd'] -> 'g' #
edc65 24/10
5

Haskell, 231 bytes

Isso define um operador # que multiplica duas representações de string de números naturais. Ele funciona definindo uma operação elementar de incremento / decremento nas strings e, em seguida, utiliza-a para criar adição e multiplicação. Um pouco de mágica extra fornece algumas acelerações exponenciais que tornam tudo isso possível.

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

Essa abordagem é rápida o suficiente para que, mesmo em um laptop de 2008 no ghci REPL não otimizado, o caso de teste leve apenas uma fração de segundo:

λ> :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)

A seguir, verifique se todos os produtos de dois dígitos estão corretos:

λ> and [ show (x * y) == (show x # show y) | x <- [0..100], y <- [0..100] ]
True
Matt Noonan
fonte
Parece que temos um novo líder! (Eu não posso ler Haskell embora - alguém pode confirmar de forma independente que cabe a especificação?)
Nathaniel
1
Sim, é um haskell perfeitamente cromulento, ele se encaixa nas especificações e funciona como anunciado. Bom trabalho!
bazzargh
4

Bash + ImageMagick: 52

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

Espera que a entrada esteja nas variáveis ​​shell ae b. Não é particularmente inteligente ou eficiente, mas faz o trabalho. Provavelmente já foi feito antes.

Observe que xdenota as dimensões da imagem; não é um operador aritmético neste contexto.

Não testei isso, mas estou disposto a supor que, para informações não extremas, ela será concluída em menos de um minuto. Eu posso testar amanhã.

Caso haja algum problema com as versões do ImageMagick, este é o que estou usando: ImageMagick 6.7.7-10

millinon
fonte
Boa tentativa, mas tenho certeza de que isso não funcionará em menos de um minuto (ou mesmo em qualquer máquina existente) para entradas 9999999999e 9999999999.
Nathaniel
4
Isso também funciona: dd if=/dev/zero bs=$a count=$b 2>&-|wc -c.
jimmy23013
1
Uma 9999999999x9999999999imagem no formato 8 bits ocupará todo o espaço do disco rígido que existe atualmente na Terra. Obviamente, um png seria muito menor, se você puder criá-lo sem antes criar a imagem bruta. (Embora eu suspeite fortemente que você tenha problemas de excesso de números inteiros com uma imagem desse tamanho.) Mas, ainda assim, esse método quase certamente prejudicaria a brecha de chamar coisas que retornam resultados numéricos como seqüências de caracteres.
Nathaniel
1
Você pode salvar 2 bytes usando em $bvez de ${b}.
nyuszika7h
1
Além disso, você pode salvar 5 bytes usando em grep -vc gvez de grep -v g|wc -l.
nyuszika7h
2

Python 2 (prova de conceito)

Esta solução funciona usando apenas seqüências de caracteres e listas e um pouco de regex. Acredito que se encaixa totalmente nas especificações, exceto que não há como fazer isso 9999999999x9999999999em um minuto. Embora tivesse tempo suficiente, iria funcionar. Pode multiplicar números de 4 dígitos rapidamente.

Uma vez que é tecnicamente inválido, ainda não me preocupei em jogá-lo completamente. Farei isso se as regras mudarem.

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)))

Exemplos:

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

multiply('1869','1243') #returns the string 2323167
Passatempos de Calvin
fonte
1
+1 porque ele faz cumprir a especificação (além do requisito de eficiência), tanto quanto eu posso dizer
Nathaniel
2

Python 2 (555)

Normalmente, eu não responderia ao meu próprio desafio tão rapidamente (ou nada), mas queria provar que isso poderia ser feito. (Felizmente, outras respostas o fizeram antes desta, mas não pude deixar de querer terminá-la.) Há mais golfe a ser feito, mas acho que isso é razoável. Ele lida com o 9999999999x9999999999caso em menos de 0,03s na minha máquina.

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))))

Exemplo de uso: m("12345","42")

Ele funciona multiplicando por muito tempo usando manipulações de string. Às vezes, as variáveis ​​são strings e, às vezes, são iteradores sobre strings, o que torna possível obter o primeiro elemento sem usar um literal inteiro. Tudo é armazenado com os dígitos invertidos, para que o primeiro elemento seja o dígito menos significativo.

Aqui está uma explicação de função por função:

  • re ssão funções de contabilidade. ( ré apenas um alias para reversed, que cria um iterador reverso e sconverte iteradores em strings.)

  • iincrementa o número em uma string em 1, incluindo casos como 39+1=40e 99+1=100.

  • badiciona xe y, mas ydeve ter apenas um dígito. Funciona aumentando os x ytempos.

  • aadiciona dois números que podem ter vários dígitos, chamando bcada dígito em y.

  • nmultiplica xe y, mas ydeve ter apenas um dígito. Funciona adicionando xa si próprio ytempos.

  • omultiplica xe y, onde ambos os argumentos podem ter vários dígitos. Ele usa multiplicação longa clássica

  • mapenas converte suas entradas de string em iteradores reversos e as entrega o, depois inverte o resultado e o converte em uma string.

Nathaniel
fonte
Par de golfe: def a(x,y):-> def a(x,y,z=''):e remova a próxima linha; truques semelhantes para outras funções, in def o(x,y):, altere o x=s(x)para x=s(x);l='';z='', no loop for, remova similarmente a nova linha + ritmos; em vez disso, use ;. Além disso, acho que o if h!='0':h+=s(x)\nelse:h+=i(x)pode ser simplesmente h+=h!='0'and i(x)or s(x); talvez até h+=(h!='0'and i or s)(x); caso contrário, simplesmente mude para if'0'!=h. Também coisas como def r(x):return reversed(x)->r=reversed
Justin
Além disso, eu esqueci de mencionar para s, m: s=lambda x:''.join(x), m=lambda x,y:s(r(o(r(x),r(y))))em vez de toda a declaração da função. Com apenas as coisas que eu sei o trabalho, isso traz o byte contagem regressiva para o 521.
Justin
Ah, e mais uma: para seus forloops: 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), embora isso possa alterar significativamente a velocidade do seu programa.
Justin
@Quincunx thanks! Eu posso ver outras melhorias também esta manhã. (Principalmente, aninhando os loops em vez de definir funções.) Farei essas alterações se algumas respostas mais competitivas aparecerem, o que parece provável - atualmente elas me colocariam na liderança, o que parece um pouco injusto, pois foi minha pergunta e eu ' tive mais tempo para pensar sobre isso.
Nathaniel
2

JavaScript: 3710 3604 bytes

  • Usando tabelas de pesquisa de cadeia com multiplicação de 1 dígito e adicione com carry.
  • A multiplicação é feita pelo dígito x dígito, em vez do dígito x linha.

Golfe:

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;
}

Sem jogar com testes:

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');

Isso gera:

mult 12345 * 42 = 518490 (3 ms) 
mult 9999999999 * 9999999999 = 99999999980000000001 (47 ms) 
Stephen Quan
fonte
2

Haskell 507 496

Isso funciona para números inteiros arbitrariamente grandes. Defino representações personalizadas para os números naturais de 0 a 18 (o maior número natural igual à soma de dois dígitos) e defino a multiplicação little-endian em termos de multiplicação de dígitos *, que eu defino em termos de adição de número + número , que eu defino em termos de adição de dígito + dígito. Eu tenho uma função de redução que expande 10-18 valores em sua decomposição digital. Isso, então, apenas lê e inverte as duas strings, converte para as vinculações personalizadas, multiplica e converte de volta, revertendo para obter o resultado certo.

Editar 2

Salvei alguns caracteres criando aliases locais curtos para comandos com vários caracteres que uso mais de uma vez, além de remover espaços e parênteses e substituindo (- )pares por $quando possível.

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

Para referência, S é o tipo de dados inteiro personalizado, pé 'mais' (adição de dígito + dígito), sé subtraído (para redução), ré reduzido (expande para decomposição digital), aé adição (adição de número + número), mé multiplicar (dígito * multiplicação de números), té times (número * multiplicação de números), ié 'interpretar' (converter string para lista de S), bé 'back' (lista de S para string), eg são apenas encurtamentos para o golfe propósitos. Eu não usei números, mesmo implicitamente; o mais próximo que cheguei foi do uso de sucessores e predecessores, que são conceitos matemáticos de nível muito superior ao da adição e multiplicação de números naturais.

Editar

Esqueceu de incluir o perfil de horário.

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

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

Apenas para uma boa medida:

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

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

Vamos enlouquecer!

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

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

confirmação

archaephyrryx
fonte
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

Observe que não estou usando indexação lógica como Z = [X, Y][N == "0"], porque isso pode ser interpretado como um booleano convertido em um índice numérico.

Ungolfed:

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
Falko
fonte
Eu diria que o uso de funções min () e max () não deve ser permitido porque elas estão comparando valores inteiros reais, não são?
WorldSEnder
@ WorldSEnder: Eu diria que eles comparam caracteres, o que é permitido neste desafio. ("A comparação lexicográfica de caracteres é permitida.")
Falko
1

Scala, 470 caracteres

(a escala é padrão, mas pode ser substituída de forma equivalente =>se contamos bytes)

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}

Aqui estamos emulando dígitos usando o comprimento das listas, tomando cuidado para não usar nenhuma operação numérica - apenas dobras, mapas, zíperes e similares. Um número é uma lista desses dígitos (ordem estrategicamente revertida na metade do cálculo); multiplicamos dígitos individuais com flatMape nossas linhas com reduce. ulida com a descoberta do carry (correspondendo diretamente a uma lista de> 10 elementos e recorrendo) e convertendo dígitos de volta em caracteres, e usamos a /:para trabalhar o caminho da pilha com isso. O exemplo necessário é concluído em menos de um segundo.

lmm
fonte