Ефіопське множення


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 і виконує однаковий макет і алгоритм, відображаючи продукт нижче.

Спосіб введення: Однак ви виберете ...

Приклад введення:

19 427

Отриманий результат:

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

Зверніть увагу на вирівнювання цифр. Це найважливіше в макеті. Також зауважте, що подвійний рядок, викладений рівними знаками, повинен бути на два символи довше загальної відповіді і повинен бути виправданим у центрі.

Тестування

Як ви будете тестувати це? Забезпечивши запуск програми за допомогою двох номерів. Ці номери можна отримати з вашого ідентифікаційного номера користувача (це можна отримати, якщо навести курсор на аватар у верхньому вікні). Візьміть своє число і візьміть три останні цифри, це буде число B, візьміть все, що залишилося на передній частині, це число A. Потім перевіряйте на A рази B.

Приклад тестування:

Мій ідентифікаційний номер користувача - 8555, тому мої номери - 8 і 555. Отже, мій вихід повинен виглядати так:

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

Обмеження:

Жоден власний оператор множення не дозволяє заощаджувати при використанні "подвоєння", як зазначено в алгоритмі. Іншими словами, якщо ви використовуєте оператор типу *, його можна використовувати лише для множення лише на 2.

Записи, які не дотримуються цього, не будуть враховані, і користувач буде супроводжуватись приміщеннями картонною коробкою, наповненою їхніми речами. Кожен запис матиме код плюс тест на основі вашого ідентифікаційного номера користувача.

Це код гольфу. Найменша кількість байтів отримає приз, славу та захоплення своїх ровесників ... (І, можливо, Ламборгіні ... Я сказав "можливо"!)


5
"Не повинно відбуватися фактичного множення." - Це непомітно. Ви можете обмежити використання деяких символів (наприклад, *або x), але неможливо визначити, чи використовується множення чи ні. Крім тієї частини, цікавий виклик.

Можливо, вам слід або попросити повний опис коду, який підтверджує, що алгоритм реалізований без множення АБО необмеженого моделювання, що забезпечує бажаний вихід. Але це виглядає як два чіткі виклики для мене.
Арнольд

1
Як зазначається в пісочниці, пов'язані, можливі дупи . @FelixPalmen, так, це тривале множення у двійковій формі.
Пітер Тейлор

Відповіді:


8

Вугілля деревне , 91 байт

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

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Пояснення:

≔⟦⟧τ≔⁰σ

Встановлює tв порожній список і sна 0. ( uвже за замовчуванням до порожнього списку.)

NθNη

Вводить два числа.

Wθ«

Повторюється, якщо qце не нульове значення.

   ⊞τ⪫  Iθ

Загорніть qв підкладку і додайте її до списку t.

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

Загорніть hабо в підкладку, або []залежно від того q, непарне, і додайте їх до списку u.

   ≔⁺σ∧﹪θ²ησ

Додати hв, sякщо qнепарно.

   ≔÷θ²θ

Ціле число ділимо qна 2.

   ≔⁺ηηη»

Додайте hдо себе.

⊞υ…=⁺²LIσ

Додайте до списку відповідний рядок =знаків u.

⊞υ⪫  Iσ

Додайте додану суму sдо списку u.

←E⮌τ⮌ι

Поверніть список t на 180 ° та роздрукуйте його догори вниз, таким чином виправдавши його праворуч.

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

Перемістіть курсор так, щоб, коли uвиправдано праворуч, його лівий верхній кут вирівнюється до правого верхнього кута, до якого ми щойно дійшли, і надрукуйте uправоруч праворуч.


Дивовижна робота. Ви маєте перевагу поки що, @Neil. Де я можу дізнатися більше про мову, чи є посилання?
WallyWest

1
@WallyWest Назва пов'язана зі сторінкою GitHub, і звідти ви можете прочитати вікі для отримання додаткової інформації.
Ніл

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 a%2*bприємно і просто, дякую
Роберто Грем

4

Математика, 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]:)
numbermaniac


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:

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

Так, я це знаю, але чому це важливо ?. Оголошення також, пріоритет %і *те саме, так і r+=a%2*bмає працювати.
Zacharý

@ Zacharý насправді я помилявся, ти маєш рацію
HatsuPointerKun

Вам навіть потрібно включити <cstdio>, чи не можете ви використовувати той самий трюк, який ви зробили тут ?
Zacharý


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 , не використовуючи динамічні довжини для printf, оскільки вони не потрібні, & використовуючи log10()для обчислення необхідну кількість ='s:

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

редагувати

збережено 4 байти за правилом "неявна int"

редагувати 2

збережено 11 байт шляхом зміни в do...while()цикл і переміщення printf у цикл з макросу. Також слід правильно працювати, якщоa=1 .

редагувати 3

збережено 7 байт і змусив код працювати правильно.

редагувати 4

Збережено 26 байтів із хитрістю printf.

редагувати 5

збережено 6 байт шляхом згортання додаткової прокладки на 1 число.

редагувати 6

збережено 7 байтів шляхом хитріння printf з потрійним оператором і не оголосивши невикористану змінну


Чудова робота, Джастіне! З нетерпінням чекаємо, що побачимо більше від вас у наступні тижні!
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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.