Etiyopya Çarpımı


17

Bu soru bu cevaptan ilham alıyor . Tesadüfen, çocukken Etiyopya Çarpma yöntemini kullanıyordum, ancak yakın zamana kadar yöntemin adını hiç bilmiyordum.

Etiyopya çarpımı, tamsayıları yalnızca toplama, ikiye katlama ve yarıya bölme ile çarpma yöntemidir.

Yöntem:

  1. İki sayıyı çarpın ve iki sütunun en üstüne yazın.
  2. Sol sütunda son sayıyı art arda yarıya indirir, kalanları atar ve 1 değerini yazana kadar sonucu aynı sütunda sonun altına yazar.
  3. Sağ sütunda son numarayı tekrar tekrar ikiye katlayın ve sonucu aşağıya yazın. sol sütunun 1 ile aynı satırda bir sonuç eklediğinizde durun.
  4. Üretilen tabloyu inceleyin ve sol sütundaki değerin eşit olduğu herhangi bir satırı atın. Orijinal iki sayının birlikte çarpılması sonucunu üretmek için kalan sağ sütundaki değerleri toplayın.

Örneğin: 17 x 34

17    34

İlk sütunu yarıya indirmek:

17    34
 8
 4
 2
 1

İkinci sütunu ikiye katlama:

17    34
 8    68
 4   136 
 2   272
 1   544

İlk hücresi eşit olan dışa vurma satırları, bunu sağdaki sayıları köşeli parantez içine alarak yapacağız:

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

Sağ sütundaki kalan sayıları toplayın:

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

Yani 17, Etiyopya yöntemiyle 34 ile çarpılarak 578'dir.

Görev:

1 ile 1000 arasında iki sayı alan ve aynı düzeni ve algoritmayı gerçekleştiren golf kodu.

Giriş Yöntemi: Bununla birlikte ...

Örnek Giriş:

19 427

Sonuç Çıktı:

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

Lütfen rakamların hizasına dikkat edin. Bu, düzende en önemlisidir. Ayrıca, eşit işaretlerle gösterilen çift satırın, genel yanıttan iki karakter daha uzun olması ve merkeze dayalı olması gerektiğini unutmayın.

Test yapmak

Bunu nasıl test edeceksiniz? İki sayı kullanarak programınızın bir çalışmasını sağlayarak. Bu numaralar kullanıcı kimlik numaranızdan çıkarılabilir (bu, imlecinizi üst penceredeki avatarınızın üzerine getirerek elde edilebilir). Numaranızı alın ve son üç basamağı alın, bu B sayısı, ön tarafta kalan her şeyi alın, bu A sayısı olacaktır. Sonra A kez B'yi test edin.

Test örneği:

Kullanıcı kimlik numaram 8555, bu yüzden sayılarım 8 ve 555. Yani çıktım şöyle görünmeli:

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

Kısıtlamalar:

Algoritmada belirtildiği gibi, "çiftleme" kullanımında hiçbir yerel çarpma operatörü tasarruf etmesine izin verilmemiştir. Başka bir deyişle, * gibi bir işleç kullanıyorsanız, yalnızca 2 ile çarpmak için kullanılabilir.

Buna uymayan girişler değerlendirmeye alınmayacak ve kullanıcı eşyalarıyla dolu bir karton kutu ile tesise refakat edilecektir. Her girişte kodun yanı sıra kullanıcı kimlik numaranıza göre test olacaktır.

Bu kod golf. En az sayıda bayt akranlarının ödülünü, ihtişamını ve hayranlığını alacak ... (Ve belki bir Lamborghini ... "Belki" dedim!)


5
"Gerçek bir çarpma gerçekleşmemelidir." - Bu gözlemlenemez. Bazı karakterlerin ( *veya gibi x) kullanımını kısıtlayabilirsiniz , ancak çarpmanın kullanılıp kullanılmadığını tespit etmek imkansızdır. Bu kısım dışında, meydan okuma ilginç.

Belki algoritmanın çarpma olmadan uygulandığını kanıtlayan kodun tam bir açıklamasını istemelisiniz VEYA istenen çıktıyı sağlayan sınırsız bir simülasyon. Ama bu benim için iki ayrı zorluk gibi görünüyor.
Arnauld

1
Kum havuzunda belirtildiği gibi, ilgili dupe . @FelixPalmen, evet, bu ikili dosyada uzun çarpmadır.
Peter Taylor

Yanıtlar:


8

Kömür , 91 bayt

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

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı versiyonudur. Açıklama:

≔⟦⟧τ≔⁰σ

tBoş listeye ve solarak ayarlar 0. ( uzaten varsayılan olarak boş listedir.)

NθNη

İki sayıyı girer.

Wθ«

qSıfırdan farklı iken tekrarlar .

   ⊞τ⪫  Iθ

Dolguya sarın qve listeye ekleyin t.

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

Dolguya hveya garip []olup olmadığına bağlı olarak sarın qve listeye ekleyin u.

   ≔⁺σ∧﹪θ²ησ

Ekle hiçin seğer qgarip.

   ≔÷θ²θ

Tamsayı bölü q2.

   ≔⁺ηηη»

Kendine ekleyin h.

⊞υ…=⁺²LIσ

=Listeye uygun bir işaret dizesi ekleyin u.

⊞υ⪫  Iσ

Yastıklı toplamı slisteye ekleyin u.

←E⮌τ⮌ι

Listeyi t180 ° döndürün ve baş aşağı yazdırın, böylece sağa yaslayın.

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

İmleci u, sağa yaslandığında sağ üst köşesine az önce ulaştığımız sağ üst köşeye gelecek şekilde hareket ettirin ve sağa yaslanmış olarak yazdırın u.


Harika iş. Şimdiye kadar bir ipucun var, @Neil. Dil hakkında daha fazla bilgiyi nereden bulabilirim, bir bağlantı var mı?
WallyWest

1
@WallyWest Başlık GitHub sayfasına bağlıdır ve oradan daha fazla bilgi için wiki'yi okuyabilirsiniz.
Neil

8

Python 2 , 203 202 187 133 bayt

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)

Çevrimiçi deneyin!

Ben kullanabiliyorsa *dize çoğalması (için '='*R) ve bir 'selektör' (aynı b*(a%2)yerine[0,b][a%2] ), alıyorum:

118 bayt

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)

Çevrimiçi deneyin!


Açıklama:

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 bayt

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

Çevrimiçi deneyin!


1
214 bayt:(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*bgüzel ve basit, teşekkür ederim
Roberto Graham

4

Mathematica, 264 bayt

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


giriş

[19.427]

çıktı

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

Muhtemelen okkalı bir baytını infix gösterimini kullanarak kaydedebilirsiniz s=Quotient[s,2]:)
numbermaniac

3

Perl 5 , 157 bayt

155 bayt kod + 2 komut satırı bayrağı ( -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

Çevrimiçi deneyin!


3

JavaScript 2017, 221 bayt

Çoğunlukla çıktı biçimlendirme sorunu

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

Daha az 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`
}

Ölçek

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>


sadece bu soruyu tekrar gözden geçirmek ... PadStart tam olarak ne yapıyor? Bu yöntemi tanımıyorum ...
WallyWest


IE'de çalışan olmak için emmek! ;)
WallyWest

3

C, C ++, 319 313 301 299 bayt

Zacharý sayesinde -8 bayt

printfDüzenlemeler arasında 60 dakika içinde öğrendiğim sihir sayesinde harika

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

C ++ optimizasyonu, başlığını değiştirin stdio.htarafından cstdiove string.htarafındancstring 2 byte kaydeder,

MSVC ile derleme #pragma warning(disable:4996)kullanmak için eklemeyi gerektirirsprintf

PPCG kimliğimle test etme:

72 x 535 =>

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

Kurallara saygı duyar, basamak hizalanır ve eşit işaretler her zaman son sayıdan 2 karakter daha büyük olacaktır. 17 x 34 => ile örnek

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

Bence son iki satırı değiştirebilirsin #define O printf("%*d %c%*d%c\n",5,a,a%2?' ':'[',9,b,a%2?' ':']');vevoid 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ý

Evet, biliyorum, ama bu neden önemli? Ayrıca reklam, önceliği %ve *aynıdır, bu yüzden r+=a%2*bçalışmalıdır.
Zacharý

@ Zacharý aslında, yanılmışım, haklısın
HatsuPointerKun

<cstdio> eklemeniz gerekiyor mu, burada yaptığınız hileyi kullanamaz mısınız?
Zacharý


3

[Bash], 144 142 140 131 128 bayt

Ekrana daha iyi saygı duyulursa, boşluk karakteri olduğunu unutmayın

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\ 

İlk cevap

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 bayt

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

Çevrimiçi deneyin!

!Operatör, iki listeleri oluşturur ?ürünü hesaplar. %ve #ascii düzeni için kullanılır.


1

Cı, 205 201 190 183 156 150 143 bayt

Bu, C89 gibi uyarılarla derlenecek ve geçerli C99 olduğuna inanmıyorum, ancak HatsuPointerKun'un sürümünden daha küçük olduğu sonucuna varıyor, çünkü gerekmediği gibi yazdırmak #includeiçin dinamik uzunlukları kullanmadan, ommitting 'ile bayt tasarrufu sağlıyor. gerekli log10()sayısını hesaplamak için kullanma =:

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

Numaram olduğu gibi 64586, hesaplamak için bu test programını kullandım 64 * 586:

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

& çıktılar:

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

Düzenle

"örtük int" kuralı ile 4 bayt kaydedildi

düzenleme 2

bir do...while()döngüye geçerek ve printf'i bir makrodan döngüye taşıyarak 11 bayt kaydetti . Ayrıca doğru çalışması gerekir a=1.

düzenleme 3

7 bayt kaydedildi ve kodun doğru çalışmasını sağladı.

düzenleme 4

Bazı printf trickery ile 26 bayt kaydedildi.

düzenleme 5

1 numaraya fazla dolgu daraltarak 6 bayt tasarruf etti.

düzenleme 6

üçlü operatör tarafından printf kandırılmasıyla 7 bayt kaydedildi ve kullanılmayan bir değişken bildirilmedi


Harika iş, Justin! Önümüzdeki haftalarda sizden daha fazlasını görmek için sabırsızlanıyoruz!
WallyWest

Teşekkür ederim. Önümüzdeki haftalarda da daha fazlasını yapmayı umuyorum.
JustinCB

1

Excel VBA, 183 bayt

Aralıktan [A1:B1]ve çıkıştan konsola giriş yapan anonim bir VBE anında pencere işlevi .

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

Çıktı

61   486 
30  [972]
15  1944 
 7  3888 
 3  7776 
 1 15552 
  =======
   29646
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.