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
22 Answers 22
Jelly, (削除) 11 (削除ここまで) 10 bytes
ƓDUz0P€Uḅ3
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.
-
3\$\begingroup\$ You can replace
b5withDto get the 10 bytes. :P \$\endgroup\$PurkkaKoodari– PurkkaKoodari2016年12月09日 09:37:32 +00:00Commented Dec 9, 2016 at 9:37
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.
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.
-
\$\begingroup\$ @Jakube I'm always doing that, although at least I included the
f=in the byte count. Also, the|0is because I need integer division, I don't know how you think you're getting the right answer without it. \$\endgroup\$Neil– Neil2016年12月09日 10:50:28 +00:00Commented 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\$Jakube– Jakube2016年12月09日 11:03:03 +00:00Commented Dec 9, 2016 at 11:03
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));
}
-
\$\begingroup\$ Suggest
for(r=0;a|b;t*=100)r+=a%10*t*(b%10),a/=10,b/=10instead ofr=0;while(a|b)r+=t*(a%10)*(b%10),a/=10,b/=10,t*=100\$\endgroup\$ceilingcat– ceilingcat2019年05月02日 18:27:26 +00:00Commented May 2, 2019 at 18:27
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.
-
\$\begingroup\$ It will be great if you could provide an ungolfed, explained version for everyone's benefit. \$\endgroup\$rnso– rnso2016年12月13日 16:32:30 +00:00Commented Dec 13, 2016 at 16:32
-
\$\begingroup\$ I've updated the post with an explanation. \$\endgroup\$rturnbull– rturnbull2016年12月14日 11:39:10 +00:00Commented Dec 14, 2016 at 11:39
-
\$\begingroup\$ Great job. Very clever method used. \$\endgroup\$rnso– rnso2016年12月15日 00:55:15 +00:00Commented Dec 15, 2016 at 0:55
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)
-
\$\begingroup\$ -3 bytes with
~=digits∘absinstead of!a=...\$\endgroup\$MarcMush– MarcMush2022年07月11日 20:17:55 +00:00Commented Jul 11, 2022 at 20:17 -
\$\begingroup\$ and -3 bytes with
prod.()instead ofmap\$\endgroup\$MarcMush– MarcMush2022年07月11日 20:23:53 +00:00Commented Jul 11, 2022 at 20:23
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]))
-
\$\begingroup\$ Nice answer! I think you can replace the
lstrippart by wrapping everything insideint()and returning a number. \$\endgroup\$ArBo– ArBo2019年05月04日 08:16:57 +00:00Commented 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\$movatica– movatica2019年05月04日 08:30:36 +00:00Commented 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\$ArBo– ArBo2019年05月04日 09:05:49 +00:00Commented May 4, 2019 at 9:05
-
\$\begingroup\$ This function seems to fail for negative inputs \$\endgroup\$ArBo– ArBo2019年05月04日 10:51:35 +00:00Commented 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\$movatica– movatica2019年05月04日 11:13:14 +00:00Commented May 4, 2019 at 11:13
Haskell, 79 bytes
import Data.Digits;r=reverse;d=r.digits 10;f a=unDigits 100.r.zipWith(*)(d a).d
- We get lists of base ten digits using
Data.Digitsand 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.
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.
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
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)
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)}}
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.
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;
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
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+$)'
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
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
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
Pip, 18 bytes
R$* *Z R*:gTDtFD:h
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
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
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
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
$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.