25
\$\begingroup\$

Introduction

Let's define a new arithmetical operation, which I call zipper multiplication. To zipper multiply two nonnegative integers, you add leading zeros to make the lengths match, multiply the corresponding base-10 digits of the numbers, add leading zeros to the results to get 2-digit numbers, concatenate them, and finally drop leading zeros.

Here's an example with A = 1276 and 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

The operation is extended to all integers with the usual sign rules: positive times negative is negative, negative times negative is positive and so on.

The task

Your inputs are two integers, and your output is their zipper multiplication. You should be able to handle arbitrarily large inputs. Input and/or output can be in string format (and indeed must be, if your language doesn't support arbitrarily large integers). Note that -0 is not a valid input or output.

Rules and scoring

You can write a full program or a function, and the lowest byte count wins.

Test cases

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
mazzy
7,2292 gold badges13 silver badges23 bronze badges
asked Dec 9, 2016 at 7:50
\$\endgroup\$

22 Answers 22

10
\$\begingroup\$

Jelly, (削除) 11 (削除ここまで) 10 bytes

ƓDUz0P€Uḅ3

Try it online!

I couldn't get this down to 10 bytes by myself, but @Pietu1998 pointed me to an atom I'd missed, this giving this 10-byte solution. Unusually for Jelly, this one takes input from standard input (in the form 1276,933024), not from the command line (this enables the use of the 3 command, which returns the command line argument, defaulting to 100).

Explanation:

ƓDUz0P€Uḅ3
Ɠ 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
 b3 convert from base 100

The use of base 100 is a simple way to implement the "pad to 2 digits, then convert to base 10" technique. The only other subtle thing here is the reversing; we want to pad with zeroes at the start of the number, but Jelly's z command pads at the end, so reversing the lists means that z will pad correctly.

answered Dec 9, 2016 at 8:19
\$\endgroup\$
1
  • 3
    \$\begingroup\$ You can replace b5 with D to get the 10 bytes. :P \$\endgroup\$ Commented Dec 9, 2016 at 9:37
4
\$\begingroup\$

Python 2, 99 bytes

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

A lot of the bytes are there to account for the sign in case of negative input. In Python, n%d is always non-negative if d is positive1. In my opinion this is generally desirable, but here it seems inconvenient: removing the calls to abs would break the above code. Meanwhile p keeps track of the "place value" (ones, hundreds, etc.) and also remembers the desired sign of the output.

The code is basically symmetric in a and b except in the while condition: we keep going until a is zero, and terminate at that time. Of course if b is zero first, then we'll end up adding zeroes for a while until a is zero as well.


1 For example, (-33)%10 returns 7, and the integer quotient of (-33)/10 is -4. This is correct because (-4)*10 + 7 = -33. However, the zipper product of (-33) with 33 must end in 3*3 = 09 rather than 7*3 = 21.

answered Dec 9, 2016 at 15:25
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 44 bytes

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

Conveniently this automatically works for negative numbers.

answered Dec 9, 2016 at 8:57
\$\endgroup\$
2
  • \$\begingroup\$ @Jakube I'm always doing that, although at least I included the f= in the byte count. Also, the |0 is because I need integer division, I don't know how you think you're getting the right answer without it. \$\endgroup\$ Commented Dec 9, 2016 at 10:50
  • \$\begingroup\$ Ah, that makes sense. Now I also get wrong answers when removing |0. Maybe the reassignment of the new function to f didn't work and I still tested the old version with |0. \$\endgroup\$ Commented Dec 9, 2016 at 11:03
2
\$\begingroup\$

C, 77 bytes

-2 bytes for removing redundant braces (* is associative).

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,... is used for padding. As long as a or b is not zero keep multiplicating the last digit %10 with t and accumulate. Then erease the last digit of a and b (/=10) and shift t by 2 digits (*=100).

Ungolfed and usage:

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));
}
answered Dec 10, 2016 at 19:29
\$\endgroup\$
1
  • \$\begingroup\$ Suggest for(r=0;a|b;t*=100)r+=a%10*t*(b%10),a/=10,b/=10 instead of r=0;while(a|b)r+=t*(a%10)*(b%10),a/=10,b/=10,t*=100 \$\endgroup\$ Commented May 2, 2019 at 18:27
2
\$\begingroup\$

R, (削除) 182 (削除ここまで) (削除) 110 (削除ここまで) (削除) 107 (削除ここまで) 86 bytes

No longer the longest answer (thanks, Racket), and in fact shorter than the Python solution (a rare treat)! An anonymous function that takes two integers as input.

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

Here's how it works.

The zipper multiplication involves splitting the input numbers into their constituent digits.We take the absolute value of number and carry out modulo for descending powers of 10:

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

So here we're taking one number, x, and applying modulo with 99 other numbers (10^99 through 10^1). R implicitly repeats x 99 times, returning a vector (list) with 99 elements. (x %% 10^99, x %% 10^98, x %% 10^97, etc.)

We use 10^99 through 10^1. A more efficient implementation would use the value of number of digits in the longest number (check the edit history of this post; previous versions did this), but simply taking 99..1 uses fewer bytes.

For x = 1276 this gives us

1276 1276 1276 ... 1276 276 76 6

Next, we use integer division by descending powers of 10 to round out the numbers:

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

This yields

0 0 0 ... 1 2 7 6

which is exactly the representation we want. In the code, we end up wanting to use 10^(98:0) again later, so we assign it to a variable:

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

(Wrapping an expression in parentheses in R generally evaluates the expression (in this case, assigning the value of 10^(98:0) to e), and then also returns the output of the expression, allowing us to embed variable assignments within other calculations.)

Next, we perform pairwise multiplication of the digits in the input. The output is then padded to two digits and concatenated. The padding to two digits and concatenating is equivalent to multiplying each number by 10^n, where n is the distance from the right edge, and then summing all the numbers.

 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

Notably, because multiplication is commutative, we can perform the multiplication by 10^n before we multiply A by B. So, we take our earlier calculation and multiply by 10^(98:0):

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

which is equivalent to

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

After applying this to A, we would then want to repeat this whole operation on B. But that takes precious bytes, so we define a function so we only have to write it once:

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

We do our embedding-in-parentheses trick to allow us to define and apply a function at the same time, to call this function on A and B and multiply them together. (We could have defined it on a separate line, but because we're eventually going to put all of this into an anonymous function, if we have more than one line of code then everything needs to be wrapped in curly braces, which costs valuable bytes.)

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

And we take the sum of all of this, and we're nearly finished:

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

The only thing to consider now is the sign of the input. We want to follow regular multiplication rules, so if one and only one of A and B is negative, the output is negative. We use the function sign which returns 1 when given a positive number and -1 when given a negative number, to output a coefficient that we multiply our entire calculation by:

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

Finally, the whole thing is wrapped into an anonymous function that takes a and b as input:

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

Remove the whitespace and it's 86 bytes.

answered Dec 12, 2016 at 21:04
\$\endgroup\$
3
  • \$\begingroup\$ It will be great if you could provide an ungolfed, explained version for everyone's benefit. \$\endgroup\$ Commented Dec 13, 2016 at 16:32
  • \$\begingroup\$ I've updated the post with an explanation. \$\endgroup\$ Commented Dec 14, 2016 at 11:39
  • \$\begingroup\$ Great job. Very clever method used. \$\endgroup\$ Commented Dec 15, 2016 at 0:55
2
\$\begingroup\$

Julia, (削除) 70 (削除ここまで) 64 bytes

Big thanx to @MarcMush for his advices!

~=digits∘abs
a\b=evalpoly(big(100),prod.(zip(~a,~b)))sign(a*b)

Attempt This Online!

answered Jul 9, 2022 at 20:24
\$\endgroup\$
2
  • \$\begingroup\$ -3 bytes with ~=digits∘abs instead of !a=... \$\endgroup\$ Commented Jul 11, 2022 at 20:17
  • \$\begingroup\$ and -3 bytes with prod.() instead of map \$\endgroup\$ Commented Jul 11, 2022 at 20:23
2
\$\begingroup\$

Python 3, (削除) 92 (削除ここまで) (削除) 119 (削除ここまで) 113 bytes

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

Try it online!

answered May 2, 2019 at 18:17
\$\endgroup\$
5
  • \$\begingroup\$ Nice answer! I think you can replace the lstrip part by wrapping everything inside int() and returning a number. \$\endgroup\$ Commented May 4, 2019 at 8:16
  • \$\begingroup\$ You're right. Then I felt like keeping a consistent interface. Taking strings as arguments instead of int, then returning an int looks weird to me ;) I rather hoped to change the zip+for loop for a map call, but that would not work :/ \$\endgroup\$ Commented May 4, 2019 at 8:30
  • \$\begingroup\$ I wouldn't worry too much about consistency in code golf, but it's up to you :). Mapping is usually not very golfy in Python if you'd need to make an extra lambda to do it. \$\endgroup\$ Commented May 4, 2019 at 9:05
  • \$\begingroup\$ This function seems to fail for negative inputs \$\endgroup\$ Commented May 4, 2019 at 10:51
  • \$\begingroup\$ You're right :/ The fix is quite expensive, maybe there's more potential for golfing it down. \$\endgroup\$ Commented May 4, 2019 at 11:13
2
\$\begingroup\$

Haskell, 79 bytes

import Data.Digits;r=reverse;d=r.digits 10;f a=unDigits 100.r.zipWith(*)(d a).d

Try it online!

  • We get lists of base ten digits using Data.Digits and reverse them.
  • Then we zipWith(*) to multiply for the length of the shorter list (as leading zeroes can be ignored)
  • Re-reverse the resulting list and convert back in base 100.

Since Data.Digits could be too trivial, here is an implementation without any imports, in 110 bytes:

d=reverse.(read.pure<$>).show.abs;g a=foldr(\d x->x*100+d)0.zipWith(*)(d a).d;f a b|a*b<0=(0-)$g a b|1<2=g a b

It uses read and show to imitate digits, folds for unDigits, and has to handle negatives separately.

answered Nov 10 at 11:58
\$\endgroup\$
1
\$\begingroup\$

Actually, (削除) 23 (削除ここまで) 19 bytes

Input is taken as two strings. Also, apparently attempting to convert from base 100, as ais523 does in their Jelly answer, doesn't work so well in Actually. Would have saved 9 bytes too if it worked :/ Golfing suggestions welcome! Try it online!

Edit: -4 bytes from changing how the result is built up into a new number.

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.
answered Dec 11, 2016 at 17:51
\$\endgroup\$
1
\$\begingroup\$

Mathematica 66 Bytes

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

Ungolfed:

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

where % means the previous output yields

{{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
answered Dec 13, 2016 at 15:15
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 9 bytes

Tвí0ζPRтβ

Port of @user62131's Jelly answer

Try it online or verify all test cases.

Explanation:

Tв # Convert both integers in the (implicit) input-pair to a base-10 list
 í # Reverse each inner list
 ζ # Zip/transpose; swapping rows/columns,
 0 # using 0 as filler for unequal length lists
 P # Take the product of each inner pair
 R # Reverse the list of integers
 тβ # Convert it from a base-100 list to a base-10 integer
 # (after which the result is output implicitly)
answered Jul 11, 2022 at 15:45
\$\endgroup\$
1
\$\begingroup\$

Tcl, 254 bytes

proc S a\ b {expr {(1-2*($a<0^$b<0))*([set f [string triml [join [lmap x [split [format %0[set l [string le [expr max(abs($a),abs($b))]]]lld [expr abs($a)]] ""] y [split [format %0$l\lld [expr abs($b)]] ""] {format %02d [expr $x*$y]}] ""] 0]]==""?0:$f)}}

Try it online!

Forced to increase byte count due to 8.6 old version interpreter parsing 0ddddd... as octal.

When I get an updated online interpreter, I will shrink it.

answered Nov 9 at 10:29
\$\endgroup\$
0
\$\begingroup\$

Pyke, 16 bytes

FY_),FBw�+`t)_sb

Try it here!

Where � is the byte 0x84 or 132

answered Dec 9, 2016 at 9:33
\$\endgroup\$
0
\$\begingroup\$

PHP, 84 bytes

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

slightly longer with string concatenation (86 bytes):

for(list(,$a,$b)=$argv;$a>=1;$a/=10,$b/=10)$r=sprintf("%02d$r",$a%10*($b%10));echo+$r;
answered Dec 9, 2016 at 9:58
\$\endgroup\$
0
\$\begingroup\$

Racket 325 bytes

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

Ungolfed:

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

Testing:

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

Output:

3001424
0
0
1203021800
-1000420803
answered Dec 13, 2016 at 17:05
\$\endgroup\$
0
\$\begingroup\$

PowerShell, (削除) 153 (削除ここまで) 151 bytes

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+$)'

Try it online!

Less golfed:

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
answered May 4, 2019 at 10:45
\$\endgroup\$
0
\$\begingroup\$

Perl 5 -MList::Util=min, 140 bytes

@a=<>=~/\S/g;@F=<>=~/\S/g;$q=1+min$#a,$#F;say+('-'x("@a@F"=~y/-//%2).sprintf'%02d'x$q,map$F[$_]*$a[$_],-$q..-1)=~s/^-?\K0+//r=~s/^-0*$//r||0

Try it online!

answered May 4, 2019 at 6:38
\$\endgroup\$
0
\$\begingroup\$

AWK, 111 bytes

x=1ドル*2ドル<0?-1:1{for(;1ドル!=0||2ドル!=0;2ドル=int(2ドル/10)){t=((1ドル%10*(2ドル%10))^2)^.5;z=(t>9?t:0 t)z;1ドル=int(1ドル/10)}}1,0ドル=z*x

Attempt This Online!

A note that this needs to be called with -M in order to handle the larger numbers, so ATO will report incorrect answers in some cases.

A slightly shorter version that seems to bug out on big numbers regardless (106):

x=1ドル*2ドル<0?-1:1{for(;1ドル!=0||2ドル!=0;2ドル=int(2ドル/10)){t+=x*(((1ドル%10)*(2ドル%10))^2)^.5;x*=100;1ドル=int(1ドル/10)}}1,0ドル=t
answered Nov 10 at 15:41
\$\endgroup\$
0
\$\begingroup\$

Pip, 18 bytes

R$* *Z R*:gTDtFD:h

Attempt This Online!

Explanation

List-of-digits base conversion makes this fairly straightforward.

R$* *Z R*:gTDtFD:h
 g List of command-line args
 TD Convert each to list of digits in base
 t 10
 (using negative digits for negative numbers)
 R*: Reverse each list of digits
 Z Zip the two lists together, discarding extras from
 the longer one
 $* * Fold each pair on multiplication
R Reverse again
 FD: Convert from list of digits in base
 h 100
answered Nov 10 at 22:25
\$\endgroup\$
0
\$\begingroup\$

Ruby, 94 characters

->m,n{(m.abs.digits.zip(n.abs.digits).map{'%02d'.%_1.to_i*_2.to_i}.reverse*'').to_i*(m*n<=>0)}

Sample run:

irb(main):001> ->m,n{(m.abs.digits.zip(n.abs.digits).map{'%02d'.%_1.to_i*_2.to_i}.reverse*'').to_i*(m*n<=>0)}[-4352,448]
=> -122016

Try all test cases online!

answered Nov 11 at 0:58
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 120 + 3 (-pla option) = 123 bytes

$_='';$:=$F[0]*$F[1]<0&&'-';y///c%2&&($_=$[.$_),$==1,(map$=*=s/(.)$//?1ドル:0,@F),$_=$=.$_ while$F[0];s/^0+//;$_=$_?$:.$_:0

Try it online!

answered Nov 11 at 12:51
\$\endgroup\$
0
\$\begingroup\$

Zsh, 108 bytes

a=${1/-};b=${(l:$#a::0:)2/-};for i ({1..$#a})Q+=${(l:2::0:)$((a[i]*b[i]))}
c=`bc<<<1ドル*2ドル`;bc<<<${c//[0-9]}$Q

Try it online!

$a and $b are the two inputs with leading - stripped and then $b is left padded with 0s to the length of $a. We then take the zipped 'product', forming a long string $Q. We get the sign of the final answer from $c and use bc to clean up leading 0s.

answered Nov 11 at 12:38
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.