Moltiplicazione etiope


17

Questa domanda è ispirata da questa risposta . Per coincidenza, usavo la moltiplicazione etiope quando ero un bambino, ma non avevo mai conosciuto il nome del metodo fino a poco tempo fa.

La moltiplicazione etiopica è un metodo per moltiplicare numeri interi usando solo addizione, raddoppio e dimezzamento.

Metodo:

  1. Prendi due numeri da moltiplicare e scrivili nella parte superiore di due colonne.
  2. Nella colonna di sinistra dimezzare ripetutamente l'ultimo numero, scartando tutti i resti e scrivere il risultato sotto l'ultimo nella stessa colonna, fino a quando si scrive un valore di 1.
  3. Nella colonna di destra raddoppia ripetutamente l'ultimo numero e scrivi il risultato qui sotto. si interrompe quando si aggiunge un risultato nella stessa riga in cui la colonna di sinistra mostra 1.
  4. Esamina la tabella prodotta e scarta qualsiasi riga in cui il valore nella colonna di sinistra è pari. Somma i valori nella colonna di destra che rimangono per produrre il risultato della moltiplicazione dei due numeri originali insieme.

Ad esempio: 17 x 34

17    34

Dimezzare la prima colonna:

17    34
 8
 4
 2
 1

Raddoppio della seconda colonna:

17    34
 8    68
 4   136 
 2   272
 1   544

Barrare le righe la cui prima cella è pari, lo faremo racchiudendo quei numeri a destra tra parentesi quadre:

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

Somma i numeri rimanenti nella colonna di destra:

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

Quindi 17 moltiplicato per 34, con il metodo etiope è 578.

L'obiettivo:

Codice da golf che accetta due numeri tra 1 e 1000 ed esegue lo stesso layout e lo stesso algoritmo, visualizzando il prodotto di seguito.

Metodo di input: comunque scegli ...

Esempio di input:

19 427

Uscita risultante:

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

Si prega di notare l'allineamento delle cifre. Questo è molto importante nel layout. Si noti inoltre che la doppia linea tracciata da segni di uguale deve essere più lunga di due caratteri rispetto alla risposta generale e deve essere giustificata al centro.

analisi

Come lo proverai? Fornendo un'esecuzione del programma utilizzando due numeri. Questi numeri possono essere estratti dal tuo numero ID utente (questo può essere ottenuto passando il cursore sul tuo avatar nella finestra in alto). Prendi il tuo numero e prendi le ultime tre cifre, questo sarà il numero B, prendi qualsiasi altra cosa rimanga in primo piano, che sarà il numero A. Quindi prova per A volte B.

Esempio di test:

Il mio numero ID utente è 8555, quindi i miei numeri sono 8 e 555. Quindi il mio output dovrebbe apparire così:

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

restrizioni:

Nessun operatore di moltiplicazione nativa ha permesso di risparmiare nell'uso del "raddoppio", come indicato nell'algoritmo. In altre parole, se stai usando un operatore come *, può essere usato solo per moltiplicare per 2.

Le voci che non aderiscono a questo non verranno prese in considerazione e l'utente verrà scortato fuori dai locali con una scatola di cartone piena delle sue cose. Ogni voce avrà un codice, oltre al test basato sul numero ID utente.

Questo è il codice golf. Il minor numero di byte riceverà il premio, la gloria e l'ammirazione dei loro coetanei ... (E forse un Lamborghini ... ho detto "forse"!)


5
"Non deve avvenire una moltiplicazione effettiva." - Questo non è osservabile. È possibile limitare l'utilizzo di alcuni caratteri (come *o x), ma è impossibile rilevare se viene utilizzata la moltiplicazione o meno. Tranne quella parte, la sfida è interessante.

Forse dovresti chiedere una descrizione completa del codice che dimostri che l'algoritmo è implementato senza moltiplicazioni O una simulazione senza restrizioni che fornisce l'output desiderato. Ma a me sembrano due sfide distinte.
Arnauld,

1
Come notato nella sandbox, relativo, possibile dupe . @FelixPalmen, sì, questa è una lunga moltiplicazione in binario.
Peter Taylor,

Risposte:


8

Carbone , 91 byte

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

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

≔⟦⟧τ≔⁰σ

Imposta tsulla lista vuota e ssu 0. (per uimpostazione predefinita è già nell'elenco vuoto).

NθNη

Immette i due numeri.

Wθ«

Si ripete mentre qè diverso da zero.

   ⊞τ⪫  Iθ

Avvolgere qnell'imbottitura e aggiungerlo all'elenco t.

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

Avvolgere hnell'imbottitura o a []seconda che qsia dispari e aggiungerlo all'elenco u.

   ≔⁺σ∧﹪θ²ησ

Aggiungi ha sif qè dispari.

   ≔÷θ²θ

Divisione intera qper 2.

   ≔⁺ηηη»

Aggiungi ha se stesso.

⊞υ…=⁺²LIσ

Aggiungi una stringa di =segni adatta all'elenco u.

⊞υ⪫  Iσ

Aggiungi la somma imbottita sall'elenco u.

←E⮌τ⮌ι

Ruota l'elenco tdi 180 ° e stampalo capovolto, giustificandolo a destra.

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

Sposta il cursore in modo che, quando uè giustificato a destra, l'angolo in alto a sinistra sia allineato con l'angolo in alto a destra che abbiamo appena raggiunto e stampa ugiustificato a destra.


Lavoro fantastico. Finora hai il vantaggio, @Neil. Dove posso trovare maggiori informazioni sulla lingua, c'è un link?
WallyWest,

1
@WallyWest Il titolo è collegato alla pagina GitHub e da lì puoi leggere la wiki per ulteriori informazioni.
Neil,

8

Python 2 , 203 202 187 133 byte

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)

Provalo online!

Se posso usare *per la moltiplicazione di stringhe ( '='*R) e come 'selettore' ( b*(a%2)anziché [0,b][a%2]), ottengo:

118 byte

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)

Provalo online!


Spiegazione:

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 byte

(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+" ");}

Provalo online!


1
214 byte:(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,

@Nevay a%2*bbello e semplice, grazie
Roberto Graham,

4

Mathematica, 264 byte

(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])&


ingresso

[19.427]

produzione

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

Probabilmente si può salvare un enorme uno di byte utilizzando notazione infissa su s=Quotient[s,2]:)
numbermaniac

3

Perl 5 , 157 byte

155 byte di codice + 2 flag della riga di 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

Provalo online!


3

JavaScript 2017, 221 byte

Principalmente un problema di formattazione dell'output

(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`
`}

Meno golf

(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`
}

Test

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>


sto solo rivisitando questa domanda ... cosa fa padStart esattamente? Non riconosco questo metodo ...
WallyWest


Mi farebbe schifo eseguire questo in IE! ;)
WallyWest,

3

C, C ++, 319 313 301 299 byte

-8 byte grazie a Zacharý

Grazie alla printfmagia che ho appena imparato in 60 minuti tra le modifiche

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

Ottimizzazione C ++, sostituire colpo di testa stdio.hda cstdioe string.hper cstring, consente di risparmiare 2 byte

La compilazione con MSVC richiede l'aggiunta #pragma warning(disable:4996)per poter essere utilizzatasprintf

Test con il mio ID PPCG:

72 x 535 =>

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

Rispetta le regole, le cifre sono allineate e i segni di uguale saranno sempre 2 caratteri più grandi del numero finale. Esempio con 17 x 34 =>

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

Penso che puoi cambiare le ultime due righe in #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);}
Zacharý,

Sì, lo so, ma perché è importante? Anche l'annuncio, la precedenza di %e *sono gli stessi, quindi r+=a%2*bdovrebbe funzionare.
Zacharý,

@ Zacharý, infatti, mi sbagliavo, hai ragione
HatsuPointerKun

Devi anche includere <cstdio>, non puoi usare lo stesso trucco che hai fatto qui ?
Zacharý,


3

[Bash], 144 142 140 131 128 byte

Migliore rispetto del display, nota che c'è un carattere spazio finale

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\ 

Prima risposta

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 byte

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

Provalo online!

L' !operatore crea i due elenchi, ?calcola il prodotto. %e #sono usati per il layout ASCII.


1

C, 205 201 190 183 156 150 143 byte

Questo verrà compilato con avvisi come C89, e non credo che sia C99 valido, ma finisce per essere più piccolo della versione di HatsuPointerKun, in quanto salva byte by ommitting #include, non usando lunghezze dinamiche per stampare se non sono necessari, e usando log10()per calcolare il numero di =necessario:

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

Poiché il mio numero è 64586, ho usato questo programma di test per calcolare 64 * 586:

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

e produce:

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

modificare

salvato 4 byte dalla regola "implicit int"

modifica 2

salvato 11 byte passando a un do...while()loop e spostando printf nel loop da una macro. Inoltre dovrebbe funzionare correttamente se a=1.

modifica 3

salvato 7 byte e fatto funzionare correttamente il codice.

modifica 4

Hai salvato 26 byte con qualche trucco di stampa.

modifica 5

salvato 6 byte comprimendo il riempimento extra in 1 numero.

modifica 6

salvato 7 byte con l'inganno printf con l'operatore ternario e non dichiarando una variabile inutilizzata


Ottimo lavoro, Justin! Non vedo l'ora di vedere di più da te nelle prossime settimane!
WallyWest,

Grazie. Spero di fare di più anche nelle prossime settimane.
JustinCB

1

Excel VBA, 183 byte

Una funzione finestra immediata VBE anonima che porta input dalla gamma [A1:B1]e output alla 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

Produzione

61   486 
30  [972]
15  1944 
 7  3888 
 3  7776 
 1 15552 
  =======
   29646
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.