Multiplicação Etíope


17

Esta pergunta é inspirada nesta resposta . Coincidentemente, eu costumava usar a Multiplicação Etíope quando era criança, mas nunca conhecia o nome do método até recentemente.

A multiplicação etíope é um método de multiplicar números inteiros usando apenas adição, duplicação e metade.

Método:

  1. Pegue dois números para multiplicar e anote-os na parte superior das duas colunas.
  2. Na coluna da esquerda, reduza pela metade o último número repetidamente, descartando quaisquer restos, e escreva o resultado abaixo do último na mesma coluna, até escrever o valor 1.
  3. Na coluna da direita, dobre repetidamente o último número e escreva o resultado abaixo. para quando você adiciona um resultado na mesma linha em que a coluna da esquerda mostra 1.
  4. Examine a tabela produzida e descarte qualquer linha em que o valor na coluna esquerda seja par. Soma os valores na coluna da direita que restam para produzir o resultado da multiplicação dos dois números originais juntos.

Por exemplo: 17 x 34

17    34

Metade da primeira coluna:

17    34
 8
 4
 2
 1

Dobrar a segunda coluna:

17    34
 8    68
 4   136 
 2   272
 1   544

Linhas de strikeout cuja primeira célula é par, faremos isso colocando os números à direita entre colchetes:

17    34
 8   [68]
 4  [136]
 2  [272]
 1   544

Soma os números restantes na coluna da direita:

17    34
 8   [68]
 4  [136]
 2  [272]
 1   544
    =====
     578

Então 17 multiplicado por 34, pelo método etíope é 578.

A tarefa:

Código de golfe que recebe dois números entre 1 e 1000 e executa o mesmo layout e algoritmo, exibindo o produto abaixo.

Método de entrada: No entanto, você escolhe ...

Exemplo de entrada:

19 427

Resultado resultante:

19   427
 9   854
 4 [1708]
 2 [3416]
 1  6832
   ======
    8113

Observe o alinhamento dos dígitos. Isso é mais importante no layout. Observe também que a linha dupla apresentada por sinais de igual deve ter dois caracteres a mais que a resposta geral e deve ser justificada ao centro.

Teste

Como você estará testando isso? Fornecendo uma execução do seu programa usando dois números. Esses números podem ser extraídos do seu número de identificação do usuário (isso pode ser obtido passando o cursor do mouse sobre o seu avatar na janela superior). Pegue o seu número e pegue os três últimos dígitos, este será o número B, pegue o que restar na frente, o número A. Em seguida, teste A vezes B.

Exemplo de teste:

Meu número de identificação de usuário é 8555, portanto, meus números são 8 e 555. Portanto, minha saída deve ficar assim:

8  [555]
4 [1110]
2 [2220]
1  4440
  ======
   4440

Restrições:

Nenhum operador de multiplicação nativo permitido, exceto no uso de "duplicação", conforme mencionado no algoritmo. Em outras palavras, se você estiver usando um operador como *, ele poderá ser usado apenas para a multiplicação por 2.

As inscrições que não aderem a isso não serão consideradas e o usuário será escoltado para fora das instalações com uma caixa de papelão cheia de seus pertences. Cada entrada terá código, além do teste com base no seu número de ID do usuário.

Isso é código de golfe. O menor número de bytes receberá o prêmio, a glória e a admiração de seus pares ... (E talvez um Lamborghini ... eu disse "talvez"!)


5
"Nenhuma multiplicação real deve ocorrer." - Isso é inobservável. Você pode restringir o uso de alguns caracteres (como *ou x), mas é impossível detectar se a multiplicação é usada ou não. Exceto essa parte, o desafio é interessante.

Talvez você deva pedir uma descrição completa do código que comprove que o algoritmo é implementado sem multiplicação OU uma simulação irrestrita que forneça a saída desejada. Mas isso parece dois desafios distintos para mim.
Arnauld

11
Conforme observado na caixa de areia, relacionado, é possível enganar . @FelixPalmen, sim, é uma multiplicação longa em binário.
Peter Taylor

Respostas:


8

Carvão , 91 bytes

≔⟦⟧τ≔⁰σNθNηWθ«⊞τ⪫  Iθ⊞υ⪫⎇﹪θ²  ¦[]Iη≔⁺σ∧﹪θ²ησ≔÷θ²θ≔⁺ηηη»⊞υ…=⁺²LIσ⊞υ⪫  Iσ←E⮌τ⮌ιM⌈EυLιLυ←E⮌υ⮌ι

Experimente online! Link é a versão detalhada do código. Explicação:

≔⟦⟧τ≔⁰σ

Define tpara a lista vazia e spara 0. (o upadrão já está na lista vazia.)

NθNη

Introduz os dois números.

Wθ«

Repete enquanto qé diferente de zero.

   ⊞τ⪫  Iθ

Embrulhe qem estofamento e anexe-o à lista t.

   ⊞υ⪫⎇﹪θ²  ¦[]Iη

Embrulho h em preenchimento ou []dependendo de qsua aparência e adicione-o à lista u.

   ≔⁺σ∧﹪θ²ησ

Adicionar h a sse qé ímpar.

   ≔÷θ²θ

Número inteiro dividido qpor 2.

   ≔⁺ηηη»

Adicionar h a si mesmo.

⊞υ…=⁺²LIσ

Anexe uma sequência adequada de = sinais à lista u.

⊞υ⪫  Iσ

Anexar a soma acolchoada s à lista u.

←E⮌τ⮌ι

Gire a lista t em 180 ° e imprima-a de cabeça para baixo, justificando-a com a direita.

M⌈EυLιLυ←E⮌υ⮌ι

Mova o cursor para que, quando ujustificado à direita, seu canto superior esquerdo se alinhe ao canto superior direito que acabamos de alcançar e imprima ucom justificação à direita.


Ótimo trabalho. Você tem a liderança até agora, @ Nee. Onde posso descobrir mais sobre o idioma, existe um link?
WallyWest

11
@WallyWest O título está vinculado à página do GitHub e de lá você pode ler o wiki para obter mais informações.
Neil

8

Python 2 , 203 202 187 133 bytes

a,b=input()
s=0
while a:print'%3s%9s'%(a,'[ %%dd] '[a%2::2]%b);s+=[0,b][a%2];a/=2;b*=2
print'%10s==\n%11s'%(''.rjust(len(`s`),'='),s)

Experimente online!

Se eu puder usar *para multiplicação de strings ( '='*R) e como um 'seletor' (b*(a%2) vez de [0,b][a%2]), recebo:

118 bytes

a,b=input()
s=0
while a:print'%3s%9s'%(a,'[ %%dd] '[a%2::2]%b);s+=a%2*b;a/=2;b*=2
print'%10s==\n%11s'%('='*len(`s`),s)

Experimente online!


Explicação:

a,b=input()                   #Get input
L=len(`a`)                    #Get length of first number for adjusting text
l=[]                          #Output list
s=0                           #Sum
while a:
 B=['[%d]',' %d '][a%2]%b     #B is either '[b]' or ' b ' depending on if a is odd/even
 l+=[(`a`,B)]                 #Add a,B to output list
 s+=[0,b][a%2]                #Add b to sum if a is odd
 a/=2;                        #Halve a
 b*=2;                        #Double b
R=len(B)                      #Length of last B for adjusting output
l+=[('',''.rjust(R,'='))]     #Add double line ==== to output list
l+=[('','%d '%s)]             #Add sum to output list
for x,y in l:
 print x.rjust(L),y.rjust(R)  #Print adjusted numbers


4

Java (OpenJDK 8) , 353 316 267 214 210 bytes

(a,b)->{int g=0;for(;a>0;g+=a%2*b,a/=2,b*=2)System.out.printf("%1$8d%2$10s\n",a,a%2<1?"["+b+"]":b+" ");System.out.printf("%1$19s%2$18s","".valueOf(new char[(int)Math.log10(g)+3]).replace("\0","=")+"\n",g+" ");}

Experimente online!


11
214 bytes:(a,b)->{int g=0;for(;a>0;g+=a%2*b,a/=2,b*=2)System.out.printf("%1$8d%2$10s\n",a,a%2<1?"["+b+"]":" "+b+" ");System.out.printf("%1$19s%2$18s","".valueOf(new char[(int)Math.log10(g)+3]).replace("\0","=")+"\n",g+" ");}
Nevay 08/09

@Nevay a%2*bagradável e simples, obrigado
Roberto Graham

4

Mathematica, 264 bytes

(s=#;k=(i=IntegerLength)@s;t=#2;w=0;P=Print;T=Table;While[s>0,If[OddQ@s,P[""<>T[" ",k-i@s],s,"  ",""<>T[" ",i[s(t)]-i@t],t];w=w+t,P[""<>T[" ",k-i@s],s,""<>T[" ",i[s(t)]-i@t]," [",t,"]"]];s=Quotient[s,2];t=2t];P[" "<>T[" ",k],""<>T["=",i@w+2]];P["  "<>T[" ",k],w])&


entrada

[19.427]

resultado

19   427  
 9   854  
 4 [1708]  
 2 [3416]  
 1  6832  
   ======  
    8113  

Você provavelmente poderia salvar um byte impressionante usando a notação infix em s=Quotient[s,2]:) #
1133

3

Perl 5 , 157 bytes

155 bytes de código + 2 sinalizadores de linha de comando ( -nl)

$\=<>;$w=y///c;$y=2+length$\<<((log)/log 2);while($_){$s+=$\if$_%2;printf"%${w}s %${y}s\n",$_,$_%2?$\.$":"[$\]";$_>>=1;$\<<=1}say$"x++$w,'='x$y;say$"x++$w,$s

Experimente online!


3

JavaScript 2017, 221 bytes

Principalmente um problema de formatação de saída

(a,b)=>{for(t=b,r=0,l=[],w=`${a}`.length;a;l.push([a,t]),a>>=1,t+=t)z=`${r+=a&1&&t}`.length+2;P=(s,w)=>`${s}`.padStart(w);return[...l.map(([a,b])=>P(a,w)+P(a&1?b+' ':`[${b}]`,z+1)),P('='.repeat(z),z-~w),P(r,z+w)].join`
`}

Menos golfe

(a, b) => {
  var w=`${a}`.length, r=0, l=[]
  while(a) {
    r += a&1 && b
    l.push([a,b])
    a >>= 1
    b += b
  }
  // algo complete, result in r, now display it and the steps in l[]
  var z=`${r}`.length+2
  var P= (s,w) => `${s}`.padStart(w)
  return [... l.map( ([a,b]) => P(a,w) + P(a&1?b+' ' : `[${b}]`, z+1) )
    , P('='.repeat(z), z+w+1)
    , P(r, z+w)
  ].join`\n`
}

Teste

var F=
(a,b)=>{for(t=b,r=0,l=[],w=`${a}`.length;a;l.push([a,t]),a>>=1,t+=t)z=`${r+=a&1&&t}`.length+2;P=(s,w)=>`${s}`.padStart(w);return[...l.map(([a,b])=>P(a,w)+P(a&1?b+' ':`[${b}]`,z+1)),P('='.repeat(z),z-~w),P(r,z+w)].join`
`}

function update(){
  var i=I.value, [a,b]=i.match(/\d+/g)
  O.textContent=F(+a,+b)
}

update()
<input id=I value='21x348' oninput='update()'><pre id=O></pre>


apenas revisitando esta pergunta ... o que o padStart faz exatamente? Eu não reconheço este método ...
Wally West


Seria péssimo estar executando isso no IE! ;)
WallyWest 24/08/19

3

C, C ++, 319 313 301 299 bytes

-8 bytes graças a Zacharý

Muito obrigado à printfmagia que aprendi em 60 minutos entre as edições

#include<string.h>
#include<stdio.h>
#define O printf("%*d %c%*d%c\n",5,a,a%2?32:91,9,b,a%2?32:93);
void m(int a,int b){int r=0,i=0;O while(a>1){r+=a%2*b;a/=2;b*=2;O}r+=b;char t[20],p[20];memset(t,0,20);memset(p,0,20);sprintf(t,"%d",r);memset(p,61,strlen(t)+2);printf("%*c%*s\n%*d",5,32,12,p,16,r);}

Optimização C ++, substituir cabeçalho stdio.hpor cstdioe string.hpor cstring, salva 2 bytes

A compilação com MSVC requer adição #pragma warning(disable:4996)para usarsprintf

Testando com meu ID PPCG:

72 x 535 =>

   72 [      535]
   36 [     1070]
   18 [     2140]
    9       4280
    4 [     8560]
    2 [    17120]
    1      34240
          =======
           38520

Ele respeita as regras, o dígito está alinhado e os sinais de igual sempre serão 2 caracteres a mais que o número final. Exemplo com 17 x 34 =>

   17         34
    8 [       68]
    4 [      136]
    2 [      272]
    1        544
            =====
             578

Eu acho que você pode mudar as duas últimas linhas de #define O printf("%*d %c%*d%c\n",5,a,a%2?' ':'[',9,b,a%2?' ':']');evoid m(int a,int b){int r=0,i=0;O while(a>1){r+=a%2*b;a/=2;b*=2;O}r+=b;char t[20],p[20];memset(t,0,20);memset(p,0,20);sprintf(t,"%d",r);for(;i<strlen(t)+2;++i)p[i]='=';printf("%*c%*s\n%*d",5,' ',12,p,16,r);}
Zachary

Sim, eu sei disso, mas por que isso importa? Além disso, como a precedência de %e *são os mesmos, r+=a%2*bdeve funcionar.
Zacharý 9/09/17

@ Zachary Na verdade, eu estava errado, você está certo
HatsuPointerKun

Você precisa incluir o <cstdio>, não pode usar o mesmo truque que fez aqui ?
Zacharý


3

[Bash], 144 142 140 131 128 bytes

Melhor respeito à exibição, observe que há um caractere de espaço à direita

read a b;for((;a;));{ ((a%2))&&((r+=b))&&x=$b\ ||x=[$b];printf %3s%9s\\n $a "$x"
((a/=2,b+=b));};printf %12s\\n =${r//?/=}= $r\ 

Primeira resposta

read a b;while((a));do ((a%2))&&((r+=b))&&printf "%6s  %6s
" $a $b||printf "%6s [%6s]
" $a $b;((a/=2,b+=b));done;printf "%6s %7s
" \  ==== \  $r

2

Haskell , 305 bytes

i=iterate
s=show
l=length.s
a!b=zip((takeWhile(>0).i(`div`2))a)(i(*2)b)
a?b=sum[y|(x,y)<-a!b,rem x 2>0]
a%b=l(snd.last$a!b)
a#b=unlines$[(' '<$[1..l a-l x])++s x++(' '<$[-1..a%b-l y])++if mod x 2<1then show[y]else(' ':s y)|(x,y)<-a!b]++map((++)(' '<$[-1..l a+a%b-l(a?b)]))['='<$[1..l a+1+a%b],' ':(s$a?b)]

Experimente online!

O !operador cria as duas listas, ?calcula o produto. %e #são usados ​​para o layout ascii.


1

C, 205 201 190 183 156 150 143 bytes

Isso será compilado com avisos como C89, e eu não acredito que seja válido C99, mas acaba sendo menor que a versão do HatsuPointerKun, pois economiza bytes ao omitir #includeos, não usando comprimentos dinâmicos para printf, pois são desnecessários, & usando log10()para calcular o número =necessário:

r;m(a,b){r=0;while(a){printf(a%2?"%4d%10d\n":"%4d [%8d]\n",a,b);r+=a%2?b:0;a/=2;b<<=1;}printf("%15.*s\n%14d",(int)log10(r)+3,"==========",r);}

Como meu número é 64586, usei este programa de teste para calcular 64 * 586:

#include <stdio.h>
int m(int a, int b);
int main(void)
{
    m(64, 586);
    putchar('\n');
}

& gera:

  64 [     586]
  32 [    1172]
  16 [    2344]
   8 [    4688]
   4 [    9376]
   2 [   18752]
   1     37504
        =======
         37504

editar

salvou 4 bytes pela regra "implícita int"

editar 2

salvou 11 bytes alterando para um do...while()loop e movendo o printf para o loop a partir de uma macro. Também deve funcionar corretamente se a=1.

editar 3

economizou 7 bytes e fez o código funcionar corretamente.

editar 4

Economizou 26 bytes com alguns truques de impressão.

editar 5

economizou 6 bytes recolhendo preenchimento extra em 1 número.

editar 6

salvou 7 bytes imprimindo truques com o operador ternário e não declarando uma variável não utilizada


Bom trabalho, Justin! Ansiosos para ver mais de você nas próximas semanas!
21318 WallyWest

Obrigado. Espero fazer mais nas próximas semanas também.
JustinCB 7/06

1

Excel VBA, 183 bytes

Uma função de janela imediata anônima do VBE que leva as entradas do intervalo [A1:B1]e as saídas para o console.

a=[A1]:b=[B1]:While a:c=a Mod 2=0:?Right(" "& a,2);Right("   "&IIf(c,"["&b &"]",b &" "),7):s=s+IIf(c,0,b):a=Int(a/2):b=b*2:Wend:?Right("     "&String(Len(s)+2,61),9):?Right("    "&s,8)

Ungolfed

Sub EthiopianMultiply(ByVal a As Integer, b As Integer)
    While a
        Let c = a Mod 2 = 0
        Debug.Print Right(" " & a, 2);
        Debug.Print Right("    " & IIf(c, "[" & b & "]", b & " "), 7)
        Let s = s + IIf(c, 0, b)
        Let a = Int(a / 2)
        Let b = Int(b * 2)
    Wend
    Debug.Print Right("     " & String(Len(s) + 2, 61), 9)
    Debug.Print Right("     " & s, 8)
End Sub

Resultado

61   486 
30  [972]
15  1944 
 7  3888 
 3  7776 
 1 15552 
  =======
   29646
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.