エチオピアの乗算


17

この質問は、この答えに触発されています。偶然にも、私は子供の頃エチオピア乗法を使用していましたが、最近までその方法の名前を知りませんでした。

エチオピアの乗算は、加算、倍増、および半分だけを使用して整数を乗算する方法です。

方法:

  1. 乗算する2つの数値を取得し、2つの列の上部に書き留めます。
  2. 左側の列では、値1を書き込むまで、最後の数値を繰り返し半分にし、残りをすべて破棄し、同じ列の最後の結果の下に結果を書き込みます。
  3. 右側の列で、最後の数字を繰り返し2倍にして、以下の結果を書きます。左側の列に1が表示されているのと同じ行に結果を追加すると停止します。
  4. 作成されたテーブルを調べて、左側の列の値が偶数である行を破棄します。残っている右側の列の値を合計して、元の2つの数値を乗算した結果を生成します。

例:17 x 34

17    34

最初の列を半分にする:

17    34
 8
 4
 2
 1

2列目を2倍にするには:

17    34
 8    68
 4   136 
 2   272
 1   544

最初のセルが偶数の取り消し線は、これらの数値を角括弧で囲んで右側に配置します。

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

右側の列の残りの数値を合計します。

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

17に34を掛けると、エチオピアの方法では578です。

タスク:

1〜1000の2つの数字を受け取り、同じレイアウトとアルゴリズムを実行するゴルフコード。以下の製品を表示します。

入力方法:ただし、選択する...

入力例:

19 427

結果の出力:

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

数字の配置に注意してください。これはレイアウトで最も重要です。また、等号で配置される二重線は、全体の回答よりも2文字長く、中央揃えにする必要があることに注意してください。

テスト中

これをどのようにテストしますか?2つの数字を使用してプログラムの実行を提供する。これらの番号は、ユーザーID番号から抽出できます(これは、トップウィンドウのアバターにカーソルを合わせると取得できます)。あなたの番号を取り、最後の3桁を取ります。これは番号Bになり、前に残っているものはすべて番号Aになります。その後、A倍Bをテストします。

テスト例:

ユーザーID番号は8555なので、番号は8と555です。したがって、出力は次のようになります。

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

制限事項:

アルゴリズムで言及されているように、「倍加」の使用を節約するためのネイティブの乗算演算子は許可されていません。つまり、*などの演算子を使用している場合、2で乗算する場合にのみ使用できます。

これに準拠していないエントリは考慮されず、ユーザーは所有物でいっぱいの段ボール箱で施設からエスコートされます。各エントリには、コードと、ユーザーID番号に基づくテストが含まれます。

これはコードゴルフです。最短バイト数は、仲間の賞、栄光、賞賛を受けます...(そして、おそらくランボルギーニ...私は「たぶん」と言いました!)


5
「実際の乗算は行わないでください。」-これは観察できません。一部の文字(*またはなどx)の使用を制限できますが、乗算が使用されているかどうかを検出することはできません。その部分を除いて、挑戦は興味深いです。

アルゴリズムが乗算なしで実装されていることを証明するコードの完全な説明、または目的の出力を提供する無制限のシミュレーションを要求する必要があるかもしれません。しかし、それは私にとって2つの明確な課題のように見えます。
アーナルド

1
サンドボックスに記載されているように、関連する可能性のあるdu。@FelixPalmen、はい、これはバイナリの長い乗算です。
ピーターテイラー

回答:


8

、91バイト

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

オンラインでお試しください!リンクは、コードの詳細バージョンです。説明:

≔⟦⟧τ≔⁰σ

t空のリストとsに設定し0ます。(uデフォルトではすでに空のリストになっています。)

NθNη

2つの数字を入力します。

Wθ«

qがゼロ以外である間に繰り返します。

   ⊞τ⪫  Iθ

qパディングでラップして、リストに追加しますt

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

hパディングまたは奇数[]かどうかに応じてラップqし、リストに追加しますu

   ≔⁺σ∧﹪θ²ησ

追加hするs場合はq奇数です。

   ≔÷θ²θ

q2による整数除算。

   ≔⁺ηηη»

h自分自身に追加します。

⊞υ…=⁺²LIσ

適切な=記号の文字列をリストに追加しuます。

⊞υ⪫  Iσ

sリストにパディングされた合計を追加しuます。

←E⮌τ⮌ι

リストtを180° 回転させて上下逆さまに印刷し、右揃えにします。

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

カーソルを移動して、右揃えになったときにu、その左上隅が直前に到達した右上隅と揃うようにし、u右揃えで印刷します。


素晴らしい仕事。これまでのところ、@ Neilがリードしています。言語の詳細はどこで確認できますか?リンクはありますか?
WallyWest

1
@WallyWestタイトルはGitHubページにリンクされており、そこから詳細についてはwikiを読むことができます。
ニール

8

パイソン2203の 202 187 133バイト

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)

オンラインでお試しください!

私が使用することができた場合は*、文字列の乗算(のため'='*R)と「セレクタ」(としてb*(a%2)の代わりに、[0,b][a%2])に、次のようになります。

118バイト

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)

オンラインでお試しください!


説明:

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バイト

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

オンラインでお試しください!


1
214バイト:(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*b素敵でシンプル、ありがとう
ロベルトグラハム

4

Mathematica、264バイト

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


入力

[19,427]

出力

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

:)で中置表記法を使用することにより、おそらく1バイトを節約できますs=Quotient[s,2]
-numbermaniac

3

Perl 5、157バイト

155バイトのコード+ 2つのコマンドラインフラグ(-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

オンラインでお試しください!


3

JavaScript 2017、221バイト

主に出力フォーマットの問題

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

少ないゴルフ

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

テスト

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>


この質問を再検討するだけです... padStartは正確に何をしますか?私はこの方法を認識しません
...-WallyWest


IEでこれを実行するのは残念です!;)
WallyWest

3

C、C ++、319の 313 301 299バイト

ザカリーのおかげで-8バイト

printf編集の合間に60分で学んだ魔法のおかげで

#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 ++の最適化、ヘッダを置き換えるstdio.hことにより、cstdioおよびstring.hによりcstring、2バイトを保存します

MSVCでコンパイル#pragma warning(disable:4996)するには、使用するために追加する必要がありますsprintf

PPCG IDを使用したテスト:

72 x 535 =>

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

規則を順守し、数字が整列され、等号は常に最終的な数字よりも2文字大きくなります。17 x 34の例=>

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

私はあなたが最後の2行を変更することができると思う#define O printf("%*d %c%*d%c\n",5,a,a%2?' ':'[',9,b,a%2?' ':']');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);for(;i<strlen(t)+2;++i)p[i]='=';printf("%*c%*s\n%*d",5,' ',12,p,16,r);}
ザカリー

ええ、私はそれを知っていますが、なぜそれが重要なのですか?また、優先度の広告%とは*同じなので、r+=a%2*b動作するはずです。
ザカリー

ザカリー@実際には、私が間違っていた、あなたは正しい
HatsuPointerKun

<cstdio>を含める必要もありますが、ここで行ったのと同じトリックを使用できませんか?
ザカリー


3

[Bash]、144 142 140 131 128バイト

表示のより良い尊重、末尾にスペース文字があることに注意してください

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\ 

最初の答え

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バイト

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

オンラインでお試しください!

!オペレータは、二つのリストを作成し、?積を計算します。%および#asciiレイアウトに使用されます。


1

C、205の 201 190 183 156 150 143バイト

これはC89として警告付きでコンパイルされますが、有効なC99であるとは思いません#includeが、不要な場合はprintfに動的な長さを使用せずに、を使用log10()して=必要なの数を計算します。

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

私の番号は64586、このテストプログラムを使用して計算しました64 * 586

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

&それは出力します:

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

編集する

「暗黙のint」ルールによって4バイトを節約しました

編集2

do...while()ループに変更し、printfをマクロからループに移動することで11バイトを節約しました。場合も正しく動作するはずですa=1

編集3

7バイトを節約し、コードを正しく機能させました。

編集4

いくつかのprintfトリックを使用して26バイトを保存しました。

編集5

追加のパディングを1つの数値に折り畳むことで6バイトを節約しました。

編集6

三項演算子を使用したprintfトリックによって未使用の変数を宣言せずに7バイトを保存しました


素晴らしい仕事、ジャスティン!今後数週間であなたからもっと多くのものを見るのを楽しみにしています!
WallyWest

ありがとうございました。今後数週間でもっと多くのことをしたいと思っています。
JustinCB

1

Excel VBA、183バイト

範囲から入力を受け取る匿名VBEイミディエイトウィンドウ関数 [A1:B1]し、コンソールに出力。

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)

非ゴルフ

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

出力

61   486 
30  [972]
15  1944 
 7  3888 
 3  7776 
 1 15552 
  =======
   29646
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.