埃塞俄比亚乘法


17

这个问题的灵感来自这个答案。碰巧的是,我小时候曾经使用埃塞俄比亚乘法,但直到最近才知道该方法的名称。

埃塞俄比亚乘法是仅使用加法,加倍和减半对整数进行乘法的方法。

方法:

  1. 取两个数字相乘,然后将其写下两列的顶部。
  2. 在左列中,将最后一个数字重复减半,舍弃所有余数,然后将结果写在同一列中的最后一个下面,直到写入值1。
  3. 在右侧栏中,重复将最后一个数字加倍,然后将结果写在下面。将结果添加到与左列显示1相同的行时停止。
  4. 检查生成的表,并丢弃左列中的值是偶数的任何行。将右侧列中的值相加,得出将原始两个数字相乘得到的结果。

例如:17 x 34

17    34

将第一列减半:

17    34
 8
 4
 2
 1

将第二列加倍:

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之间的数字并且执行相同布局和算法的Golf代码,并在下面显示产品。

输入法:但是您选择...

输入示例:

19 427

结果输出:

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

请注意数字的对齐方式。这在布局中最重要。另请注意,以等号布置的双线必须比整体答案长两个字符,并且必须居中对齐。

测试中

您将如何测试呢?通过使用两个数字来运行程序。这些号码可以从您的用户ID号码中提取出来(可以通过将光标悬停在顶部窗口的头像上来获得)。取您的数字并取最后三位数字,这将是数字B,取前面剩下的其他任何东西,即数字A。然后测试A乘以B。

测试示例:

我的用户ID号是8555,所以我的数字是8和555。因此我的输出应如下所示:

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

限制条件:

如算法中所述,除使用“加倍”外,不允许任何本机乘法运算符。换句话说,如果您使用*等运算符,则只能将其乘以2。

不遵守此规定的条目将不予考虑,用户将被装满装满物品的纸板箱护送离场。每个条目都有代码,并根据您的用户ID号进行测试。

这是代码高尔夫。最短的字节数将得到同龄人的奖赏,荣耀和钦佩……(也许还有兰博基尼……我说“也许”!)


5
“没有实际的乘法必须发生。” -这是不可观察的。您可以限制使用某些字符(例如*x),但是无法检测是否使用了乘法。除了那部分,挑战很有趣。

也许您应该要求对代码进行完整描述,以证明算法是无乘法实现的,或者是可以提供所需输出的无限制仿真。但这对我来说似乎是两个不同的挑战。
Arnauld

1
如沙箱中所述,相关的可能是欺骗。@FelixPalmen,是的,这是二进制形式的长乘法。
彼得·泰勒

Answers:


8

木炭,91字节

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

在线尝试!链接是详细版本的代码。说明:

≔⟦⟧τ≔⁰σ

设置t为空列表并设置s0。(u已经默认为空列表。)

NθNη

输入两个数字。

Wθ«

q非零时重复。

   ⊞τ⪫  Iθ

包装q填充并将其附加到列表中t

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

h以填充或[]根据是否q为奇数来换行,然后将其附加到列表中u

   ≔⁺σ∧﹪θ²ησ

添加hs,如果q是奇数。

   ≔÷θ²θ

整数除以q2。

   ≔⁺ηηη»

添加h自身。

⊞υ…=⁺²LIσ

=在清单上加上一串合适的符号u

⊞υ⪫  Iσ

将填充后的金额追加s到列表中u

←E⮌τ⮌ι

将列表旋转t180°,然后上下颠倒打印,以使其右对齐。

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

移动光标,以便当u右对齐时,其左上角与我们刚到达的u右上角对齐,然后打印右对齐。


很棒的工作。到目前为止,您已经处于领先地位,@ Neil。在哪里可以找到有关该语言的更多信息,是否有链接?
WallyWest'9

1
@WallyWest标题链接到GitHub页面,从那里您可以阅读Wiki以获取更多信息。
尼尔

8

Python 2中203个 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很好而且很简单,谢谢
Roberto Graham

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  

您可以通过在:) 上使用s=Quotient[s,2]
中止

3

Perl 5 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 '19

3

C,C ++,319个 313 301 299字节

-8字节归功于Zacharý

非常感谢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通过cstdiostring.hcstring,节省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

我想你可以在最后两行更改为#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应该工作。
扎卡里

@Zacharý实际上,我错了,你是对的
HatsuPointerKun

您是否甚至需要包含<cstdio>,您是否可以使用与此处相同的技巧?
扎卡里


3

[击],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,但是最终它会比HatsuPointerKun的版本小,因为它通过省略#include's 来节省字节,而不使用不需要的动态长度来作为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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.