Розмноження на блискавці


20

Вступ

Давайте визначимо нову арифметичну операцію, яку я називаю множенням блискавки . Щоб блискавка помножила два невід’ємних цілих числа, ви додаєте провідні нулі, щоб зрівняти довжини, помножувати відповідні базові-10 цифр чисел, додавати провідні нулі до результатів, щоб отримати двоцифрові числа, об'єднати їх і, нарешті, скинути провідні нулі.

Ось приклад з A = 1276 та B = 933024 :

1. Add leading zeros
 A = 001276
 B = 933024

2. Multiply digit-wise
 A = 0  0  1  2  7  6
 B = 9  9  3  0  2  4
 ->  0  0  3  0 14 24

3. Pad to 2 digits
 -> 00 00 03 00 14 24

4. Concatenate
 -> 000003001424

5. Drop leading zeros
 -> 3001424

Операція поширюється на всі цілі числа за звичайними правилами знаків: додатний час негативний - негативний, негативний час - негативний, і так далі.

Завдання

Ваші входи - це два цілих числа, а ваш вихід - їх множення на блискавці. Ви повинні мати можливість обробляти довільно великі входи. Введення та / або вихід можуть бути у рядковому форматі (і справді має бути, якщо ваша мова не підтримує довільно великих цілих чисел). Зверніть увагу, що -0це невірний вхід чи вихід.

Правила та оцінка

Ви можете написати повну програму або функцію, і найнижча кількість байтів виграє.

Тестові кейси

0 0 -> 0
302 40 -> 0
302 -40 -> 0
-4352 448 -> -122016
0 6623 -> 0
0 -6623 -> 0
20643 -56721 -> -1000420803
63196 21220 -> 1203021800
1276 933024 -> 3001424
-1276 933024 -> -3001424
-1276 -933024 -> 3001424
5007204555 350073039 -> 12001545
-612137119 -8088606033 -> 816060042000327
3389903661 -6619166963 -> -18180881090018543603
-23082746128560880381 1116941217 -> -8050600723200060807
-668336881543038127783364011867 896431401738330915057436190556 -> -485448120906320001351224000900090235004021121824000900403042
402878826066336701417493206805490000415 312487283677673237790517973105761463808 -> 120004325656161618004242182118140007280900200921180018080025285400000000320040

Відповіді:


8

Желе , 11 10 байт

ƓDUz0P€Uḅ³

Спробуйте в Інтернеті!

Я не міг звести це до 10 байт самостійно, але @ Pietu1998 вказав мені на атом, який я пропустив, даючи це 10-байтне рішення. Незвично для Jelly, цей приймає дані зі стандартного введення (у формі 1276,933024), а не з командного рядка (це дозволяє використовувати ³команду, яка повертає аргумент командного рядка, за замовчуванням до 100).

Пояснення:

ƓDUz0P€Uḅ³
Ɠ           read standard input
 D          convert to base 10
  U         reverse elements
   z0       transpose, padding the end with zeroes
     P€     take the product of each (€) inner list
       U    reverse elements back
        b³  convert from base 100

Використання бази 100 - це простий спосіб реалізувати техніку "pad до 2 цифр, потім перетворити на базу 10". Єдина інша тонка річ тут - реверс; ми хочемо прокладати нулі на початку числа, але zкомандні колодки Jelly в кінці, тому перевернення списків означає, що zбуде прокладено правильно.


3
Ви можете замінити b⁵на, Dщоб отримати 10 байт. : P
PurkkaKoodari

4

Python 2, 99 байт

a,b=input();o=0;p=1-2*(a*b<0);a,b=abs(a),abs(b)
while a:o+=a%10*(b%10)*p;p*=100;a/=10;b/=10
print o

Дуже багато байтів є для обліку знаку у випадку негативного введення. У Python n%dзавжди є негативним, якщо dє позитивним 1 . На мою думку, це взагалі бажано, але тут здається незручним: видалення викликів absпорушить наведений вище код. Тим часом pвідслідковує "значення місця" (ті, сотні тощо), а також запам'ятовує бажаний знак результату.

Код в основному симетричний aі, bза винятком, за whileумовою: ми продовжуємо рухатися до aнуля і закінчуємо в той час. Звичайно, якщо bспочатку дорівнює нулю, тоді ми закінчимо додавати нулі на деякий час, поки також не aбуде нуля.


1 Наприклад, (-33)%10повернення 7, а ціле коефіцієнт (-33)/10- -4. Це правильно, оскільки (-4)*10 + 7 = -33. Тим НЕ менше, блискавка продукт (-33)з 33повинен закінчитися , 3*3 = 09а не 7*3 = 21.


3

JavaScript (ES6), 44 байти

f=(x,y)=>x&&f(x/10|0,y/10|0)*100+x%10*(y%10)

Зручно, це автоматично працює для від'ємних чисел.


@Jakube Я завжди це роблю, хоча принаймні я включив до f=числа байтів. Крім того, тому |0, що мені потрібен цілий поділ, я не знаю, як ти думаєш, що без нього ти отримаєш правильну відповідь.
Ніл

Ах, це має сенс. Тепер я також отримую неправильні відповіді при видаленні |0. Можливо, переназначення нової функції на f не спрацювало, і я все-таки перевірив стару версію |0.
Якубе

2

C, 77 байт

-2 байти для зняття зайвих брекетів ( *є асоціативним).

r,t;f(a,b){t=1;r=0;while(a|b)r+=t*(a%10)*(b%10),a/=10,b/=10,t*=100;return r;}

t= 1,100,10000, ... використовується для підкладки. Поки aабо bне дорівнює нулю, продовжуйте множувати останню цифру %10на tі накопичувати. Потім зітріть останню цифру aта b( /=10) і змістіть tна 2 цифри ( *=100).

Безголівки та використання:

r,t;
f(a,b){
 t=1;
 r=0;
 while(a|b)
  r+=t*(a%10)*(b%10),
  a/=10,
  b/=10,
  t*=100;
 return r;
}

main(){
 printf("%d\n", f(1276,933024));
}

Запропонувати for(r=0;a|b;t*=100)r+=a%10*t*(b%10),a/=10,b/=10замістьr=0;while(a|b)r+=t*(a%10)*(b%10),a/=10,b/=10,t*=100
roofcat

1

Власне , 23 19 байт

Введення приймається за два рядки. Крім того, мабуть, спроба перетворити з бази 100, як це робить ais523 у своїй відповіді на Jelly, насправді не так добре працює. Врятував би також 9 байт, якби це спрацювало: / Пропозиції з гольфу вітаються! Спробуйте в Інтернеті!

Редагувати: -4 байти від зміни способу формування результату на нове число.

k`♂≈R`M┬ñ`iτ╤@π*`MΣ

Ungolfing

          Implicit input a and b.
k         Wrap a and b into a list.
`...`M    Map over the list of strings.
  ♂≈        Convert each digit to its own int.
  R         Reverse for later.
┬         Transpose to get pairs of digits from a and b.
ñ         enumerate(transpose) to get all of the indices as well.
`...`M    Map over the transpose.
  i         Flatten (index, pair) onto the stack.
  τ╤        Push 10**(2*index) == 100**index to the stack.
  @π        Swap and get the product of the pair of integers.
  *         Multiply the product by 100**index.
Σ         Sum everything into one number.
          Implicit return.

1

Математика 66 байт

i=IntegerDigits;p=PadLeft;FromDigits@Flatten@p[i/@Times@@p[i/@#]]&

Безголівки:

IntegerDigits/@{1276,933024}
PadLeft[%]
Times@@%
IntegerDigits/@%
PadLeft[%]
Flatten@%
FromDigits@%

де% означає попередній вихід

{{1,2,7,6},{9,3,3,0,2,4}}
{{0,0,1,2,7,6},{9,3,3,0,2,4}}
{0,0,3,0,14,24}
{{0},{0},{3},{0},{1,4},{2,4}}
{{0,0},{0,0},{0,3},{0,0},{1,4},{2,4}}
{0,0,0,0,0,3,0,0,1,4,2,4}
3001424

1

R, 182 110 107 86 байт

Більше не найдовша відповідь (спасибі, Ракетка), а насправді коротша за рішення Python (рідкісне лікування)! Анонімна функція, яка приймає в якості двох цілих чисел.

function(a,b)sum((s=function(x)abs(x)%%10^(99:1)%/%(e=10^(98:0))*e)(a)*s(b))*sign(a*b)

Ось як це працює.

Помноження на блискавку включає розділення вхідних чисел на їх складові цифри. Беремо абсолютне значення числа та виконуємо модуль для зменшення потужності 10:

abs(x) %% 10^(99:1)

Отже, тут ми беремо одне число xі застосовуємо модуль з 99 іншими числами ( 10^99через 10^1). R неявно повторюється x99 разів, повертаючи вектор (список) з 99 елементами. ( x %% 10^99, x %% 10^98, x %% 10^97І т.д.)

Ми використовуємо 10^99наскрізь 10^1. Більш ефективна реалізація використовує значення кількості цифр у найдовшій кількості (перевірте історію редагування цієї публікації; попередні версії зробили це), але просто 99..1використовуючи меншу кількість байтів.

Бо x = 1276це нам дає

1276 1276 1276 ... 1276 276 76 6

Далі ми використовуємо ціле ділення шляхом зменшення потужності 10, щоб округлити числа:

abs(x) %% 10^(99:1) %/% 10^(98:0)

Це дає

0 0 0 ... 1 2 7 6

яке саме представлення ми хочемо. У коді ми хочемо використовувати його 10^(98:0)знову пізніше, тому присвоюємо йому змінну:

abs(x) %% 10^(99:1) %/% (e = 10^(98:0))

(Обгортання виразу в дужках в R зазвичай оцінює вираз (у цьому випадку, присвоюючи значення 10^(98:0)до e), а також повертає вихідний вираз, дозволяючи нам вставляти змінні призначення в інші обчислення.)

Далі виконуємо попарне множення цифр у введеному. Потім вихід викладається на дві цифри і з'єднується. Прокладка на дві цифри та об'єднання є еквівалентом множення кожного числа на 10^n, де nвідстань від правого краю, а потім підсумовування всіх чисел.

 A = 0         0         1         2         7         6
 B = 9         9         3         0         2         4
 ->  0         0         3         0        14        24
 -> 00        00        03        00        14        24
 ->  0*10^6 +  0*10^5 +  3*10^4 +  0*10^3 + 14*10^2 + 24*10^1
 =  000003001424

В Зокрема, тому , що множення коммутативно, ми можемо виконати множення , 10^n перш ніж ми множимо A по B . Отже, ми беремо наш попередній розрахунок і множимо на 10^(98:0):

abs(x) %% 10^(99:1) %/% 10^(98:0) * 10^(98:0)

що еквівалентно

abs(x) %% 10^(99:1) %/% (e = 10^(98:0)) * e

Після застосування цього до А , ми б тоді хочемо повторити всю цю операцію B . Але це займає дорогоцінні байти, тому ми визначаємо функцію, тому нам потрібно написати лише один раз:

s = function(x) abs(x) %% 10^(99:1) %/% (e=10^(98:0)) * e

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

(s = function(x) abs(x) %% 10^(99:1) %/% (e=10^(98:0)) * e)(a) * s(b)

І ми беремо суму всього цього, і ми майже закінчили:

sum((s = function(x) abs(x) %% 10^(99:1) %/% (e=10^(98:0)) * e)(a) * s(b))

Єдине, що зараз слід врахувати, - це знак введення. Ми хочемо дотримуватись правил регулярного множення, тому якщо один і лише один з A і B є негативними, вихід буде негативним. Ми використовуємо функцію, signяка повертається, 1коли задається додатне число, а -1коли відводиться від'ємне число, щоб вивести коефіцієнт, на який ми помножимо весь наш обчислення на:

sum((s = function(x) abs(x) %% 10^(99:1) %/% (e=10^(98:0)) * e)(a) * s(b)) * sign(a * b)

Нарешті, вся справа загорнута в анонімну функцію, яка приймає aі bяк вхід:

function(a, b) sum((s = function(x) abs(x) %% 10^(99:1) %/% (e=10^(98:0)) * e)(a) * s(b)) * sign(a * b)

Видаліть пробіл і це 86 байт.


Буде чудово, якщо ви зможете надати необгрунтовану, пояснену версію на благо кожного.
rnso

Я оновив публікацію з поясненням.
rturnbull

Чудова робота. Використовується дуже розумний метод.
rnso

1

Python 3 , 92 байти , 119 байт

lambda m,n:(1-(n*m<0)*2)*int(''.join([f"{int(a)*int(b):02}"for a,b in zip(str(abs(n))[::-1],str(abs(m))[::-1])][::-1]))

Спробуйте в Інтернеті!

Виправлення для обробки негативних чисел вартістю 29 байт: /


Гарна відповідь! Я думаю, ви можете замінити lstripчастину, загорнувши все всередину int()і повернувши номер.
ArBo

Ти маєш рацію. Тоді я відчув, як зберігати послідовний інтерфейс. Приймаючи рядки як аргументи замість int, а потім повернення int виглядає для мене дивно;) Я швидше сподівався змінити zip + для циклу для виклику на карті, але це не спрацює: /
movatica

Я б не переживав надто про послідовність у коді гольфу, але це залежить від вас :). Капірування, як правило, не дуже гнучко в Python, якщо вам потрібно зробити додаткову лямбда, щоб це зробити.
ArBo

Здається, ця функція не справляється з негативними входами
ArBo

Ви маєте рацію: / Виправлення є досить дорогим, можливо, є більший потенціал для того, щоб пограти в нього.
movatica


0

PHP, 84 байти

for(list(,$a,$b)=$argv,$f=1;$a>=1;$a/=10,$b/=10,$f*=100)$r+=$a%10*($b%10)*$f;echo$r;

трохи довше з конкатенацією рядків (86 байт):

for(list(,$a,$b)=$argv;$a>=1;$a/=10,$b/=10)$r=sprintf("%02d$r",$a%10*($b%10));echo+$r;

0

Ракетка 325 байт

(let*((g string-append)(q quotient/remainder)(l(let p((a(abs a))(b(abs b))(ol'()))(define-values(x y)(q a 10))
(define-values(j k)(q b 10))(if(not(= 0 x j))(p x j(cons(* y k)ol))(cons(* y k)ol)))))(*(string->number
(apply g(map(λ(x)(let((s(number->string x)))(if(= 2(string-length s)) s (g "0" s))))l)))(if(<(* a b)0)-1 1)))

Безголівки:

(define (f a b)
  (let* ((sa string-append)
         (q quotient/remainder)
         (ll (let loop ((a (abs a))
                        (b (abs b))
                        (ol '()))
               (define-values (x y) (q a 10))
               (define-values (j k) (q b 10))
               (if (not(= 0 x j))
                   (loop x j (cons (* y k) ol))
                   (cons (* y k) ol)))))
    (*(string->number (apply sa
                             (map (λ (x)
                                    (let ((s (number->string x)))
                                      (if (= 2 (string-length s))
                                          s
                                          (sa "0" s))))
                                  ll)))
      (if (< (* a b) 0) -1 1))))

Тестування:

(f 1276 933024)
(f 302 40)
(f 0 6623)
(f 63196 21220)
(f 20643 -56721)

Вихід:

3001424
0
0
1203021800
-1000420803

0

PowerShell , 153 151 байт

param($a,$b)do{$x,$y=$a[--$i],$b[$i]|%{if($_-eq45){$s+=$_;$_=0}$_}
$r=(+"$x"*"$y"|% t*g "00")+$r}while($x+$y)$s+$r-replace'(?<!\d)0+(?=\d)|--|-(?=0+$)'

Спробуйте в Інтернеті!

Менше гольфу:

param($a,$b)
do{
    $x,$y=$a[--$i],$b[$i]|%{
        if($_-eq45){                                # [char]45 is '-'
            $signs+=$_
            $_=0
        }
        $_                                          # a digit or $null
    }
    $res=(+"$x"*"$y"|% toString "00")+$res          # "00" is the custom format to get 2-digit number
}
while($x+$y)
$signs+$res-replace'(?<!\d)0+(?=\d)|--|-(?=0+$)'    # cleanup and return

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.