Multiply without multiply

8

3

Write the fastest (best big-O) and smallest multiplication algorithm for positive integers, without using multiplication operators. You are only allowed addition, subtraction, logical functions (AND, OR, XOR, NOT), bit shift, bit rotate, bit flip/set/clear and bit test. Your program should be capable of multiplying 16-bit numbers to produce a 32-bit result. Take input on stdin, separated by commas, spaces or new lines (your choice), but make it clear how to input the data.

Example input/output:

734 929
681886

Thomas O

Posted 2011-02-07T13:37:57.427

Reputation: 3 044

Question was closed 2015-12-10T08:05:23.623

1What about the division operator? – st0le – 2011-02-07T13:57:46.600

3Is this codegolf or a challenge? :-\ – st0le – 2011-02-07T14:05:57.037

@st0le you are only allowed the ops I name. – Thomas O – 2011-02-07T16:53:25.820

@st0le It is a combination of both - a challenge to figure it out, as well as the smallest being considered best. – Thomas O – 2011-02-07T16:53:59.377

3I marked for closing as "not a real question", since there still isn't given a solution, how to compare the fastest and the shortest code. Which is of priority? Or in what relation is the trade off? It could be healed if a some comparison algo in a portable lang was given - for example: if the std-algo reaches 500k operations in C, and your algo reaches 50k, you have to multiply the codelength *10. That way everybody could choose whether to shorten the code or to make it faster. The winner needn't be winner in both categories, but the winning criteria would be far more objective. – user unknown – 2012-05-16T03:22:30.927

@Thomas, You should specify if negative numbers are also to be handled...i don't think anyone is handling it at the moment. – st0le – 2011-02-08T06:58:00.877

@st0le from the question: "smallest multiplication algorithm for positive integers" – Thomas O – 2011-02-08T08:03:18.397

2

This question is insane as stated. The asymptotically fastest known multiplication algorithm for positive integers is Fürer's algorithm (http://en.wikipedia.org/wiki/F%C3%BCrer%27s_algorithm) and it's ridiculously complex and would take thousands of lines to implement in any language. I assume he actually just means your algorithm has to be O(n^2) (long multiplication).

– D Coetzee – 2012-07-16T01:16:53.917

4Fastest OR smalles - you can't have both, or you need a translation formular to calculate the trade off. – user unknown – 2012-01-11T02:57:08.337

Answers

11

C, 84 83 78 Characters

m;main(a,b){for(scanf("%d%d",&a,&b);a;b+=b)a&1?m+=b:0,a>>=1;printf("%d\n",m);}

In a more readable form

m;main(a,b)
{
    scanf("%d%d",&a,&b);
    while (a)
    {
        if (a&1)
           m+=b;
        a>>=1;
        b+=b;
    }
    printf("%d\n",m);
}

The algorithm is better known as the Ethiopian Multiplication or the Russian Peasant Multiplication.Here’s the algorithm :

  1. Let the two numbers to be multiplied be a and b.
  2. If a is zero then break and print the result.
  3. If a is odd then add b to the result.
  4. Half a, Double b. Goto Step 2.

fR0DDY

Posted 2011-02-07T13:37:57.427

Reputation: 4 337

not working without initializing m=0 (atleast for me) – st0le – 2011-02-07T14:04:35.463

@st0le It will work now, I have moved 'm' to begining in the main function. See here: http://www.ideone.com/XCz8C

– fR0DDY – 2011-02-07T14:09:00.013

Forgot about this one, here's a shorter one for(;(a&1&&m+=b)|a;a>>=1,b<<=1); Yes, i'm very ashamed. :) – st0le – 2011-02-07T14:10:39.900

for(m=0;(a&1&&m+=b)|a;a/=2,b*=2); why use shift,right? – st0le – 2011-02-07T14:14:17.787

@st0le It's written in the question not to use / and * operator. – fR0DDY – 2011-02-07T14:16:52.480

@fR0DDY, true, doh! – st0le – 2011-02-07T14:20:28.527

@st0le for(;(a&1&&m+=b)|a;a>>=1,b<<=1); won't work I think. – fR0DDY – 2011-02-07T14:40:26.030

2@fR0DDY: You could say b+=b instead of b*=2 . Of course, you'll still need the right shift. – Joey Adams – 2011-02-07T22:01:05.403

Doesn't work - m is initialized to 1, not 0. This version fixes it, and saves 5 chars as well: m;main(a,b){for(scanf("%d%d",&a,&b);a;b+=b)a&1?m+=b:0,a>>=1;printf("%d\n",m);} – ugoren – 2012-05-15T06:36:35.327

@ugoren Thanks for the tip. – fR0DDY – 2012-05-30T06:26:09.860

Also you might consider editing 'more readable form' :) – Quixotic – 2012-07-13T14:04:40.497

@Quixotic Probably the division operator is not allowed. – fR0DDY – 2012-07-14T05:46:27.873

The division I don't know, but the b*=2 look suspiciously like a multiplication. – Florian F – 2014-09-03T21:43:19.010

@fR0DDY very good answer with explanation. – Imran Ali – 2014-09-12T01:21:31.440

7

APL (5)

Takes input on standard input separated by newlines.

+/⎕⍴⎕

marinus

Posted 2011-02-07T13:37:57.427

Reputation: 30 224

5

Golfscript - 12 characteres

~0\{1$+}*\;

Please note that * here is not the multiplication operator, it's instead a repetition operator, see the second use here.

Juan

Posted 2011-02-07T13:37:57.427

Reputation: 2 738

4

Golfscript - 27 chars

Peasants multiplication. There first * in there is a multiply, but only by 0 or 1

~2base-1%{1&\..+\@*}%{+}*\;

Here's on at 31 chars that doesn't multiply at all

~2base-1%{1&\..+\[0\]@=}%{+}*\;

gnibbler

Posted 2011-02-07T13:37:57.427

Reputation: 14 170

4

Python, 64 chars

Probably not the most efficient though (or the most compliant, but I'm "adding", aren't I?):

a=int(raw_input())
print sum(a for i in range(int(raw_input())))

user468

Posted 2011-02-07T13:37:57.427

Reputation:

7You could use input() in place of int(raw_input()) to save 18 characters. You might consider this cheating, but print sum([input()]*input()) also works (* is being used for repetition, not multiplication). – James – 2012-04-16T10:23:59.987

r=input;a=r();print sum(map(lambda x:a,range(r()))) is much shorter – Joel Cornett – 2012-05-15T08:31:17.023

@JoelCornett r=input;a=r();r(sum(a for b in range(r()))) is even shorter (43 vs 51 bytes) – FatalError – 2018-09-27T21:49:08.130

3

Ruby, 30

->(a){Array.new(*a).inject:+}

Based on GigaWat answer.

Hauleth

Posted 2011-02-07T13:37:57.427

Reputation: 1 472

2

J, 18 17 characters

+/({.${:)".1!:1]3

Input needs to be space separated.

Gareth

Posted 2011-02-07T13:37:57.427

Reputation: 11 678

2

Golfscript - 43

~\:@;0 1{.3$&{\@+\}{}if@@+:@;.+.3$>!}do;\;

Implementation of the peasant multiplication. I think I may be able to golf it some more later on.

Juan

Posted 2011-02-07T13:37:57.427

Reputation: 2 738

2

Python, also 64 chars

m=lambda x,n:0 if n==0 else x+m(x,n-1);print m(input(),input())

Doug T.

Posted 2011-02-07T13:37:57.427

Reputation: 139

1You could shorten it by assigning i=input and using i() – st0le – 2011-02-08T06:55:54.763

3actually that works out to be exactly the same number of characters – Doug T. – 2011-02-08T13:41:46.560

2could replace 0 if n==0 else with n and – recursive – 2011-02-11T18:53:35.550

1

A variation in Scala, optimized for size: 48 chars

def m(a:Int,b:Int):Int=if(b==1)a else a+m(a,b-1)

optimized for speed a bit:

def mul (a:Int, b:Int) : Int = {
  print (".")
  if (a == 1) b
  else if (a > b) mul (b, a)
  else if (a % 2 == 0) mul (a >> 1, b << 1) 
  else b + mul (a - 1, b) 
}

I swap (a, b) if (a > b), to reach the end more fast. The difference is 11 to 20 steps, when calling mul (1023,31), compared with omitting that line of code.

golfed: 95 chars:

def m(a:Int,b:Int):Int=if(a==1)b
else if(a>b)m(b,a)
else if(a%2==0)m(a>>1,b<<1)
else b+m(a-1,b)

user unknown

Posted 2011-02-07T13:37:57.427

Reputation: 4 210

1

Ruby, 35 bytes

def x(a)Array.new(*a).inject :+end

Usage: x([123, 456]) #=> 56088

Could probably be shortened if the numbers are read from ARGV, but it complains about them being the wrong format (strings, not ints). Any suggestions would be great.

Mr. Llama

Posted 2011-02-07T13:37:57.427

Reputation: 2 387

1

VBA, 70 chars

This is actually quite slow for large numbers, but it's small. I managed to improve the code size while improving speed. Calculation time varies, depending on argument position - not just size. (i.e. 1000, 5000 computes in about 4 seconds while 5000, 1000 calculates in about 19) Since the OP lists both fast and small, I figured I'd go with this one. Input is two numeric args, comma separated.

Sub i(j,k)
For m=1 To j:n=n & String(k," "):Next
MsgBox Len(n)
End Sub

This longer version (103 chars) will ensure it runs with the faster of the two possible arrangements:

Sub i(j,k)
If j<k Then a=j:b=k Else b=j:a=k
For m=1 To a:n=n & String(b," "):Next
MsgBox Len(n)
End Sub

Gaffi

Posted 2011-02-07T13:37:57.427

Reputation: 3 411

You can loose quite a few bytes by removing whitespace before To and in concatenation, as well as by outputiing to the VBE immediate window via Debug.? – Taylor Scott – 2017-05-31T15:16:37.720

1

Perl: 52 chars

This is an old question, but Perl needs to be represented:

perl -pl '($m,$n,$_)=split;$_+=$m&1&&$n,$m>>=1,$n<<=1while$m'

(This is the binary algorithm; iterated addition is smaller but way too boring.)

This program includes an unintentional feature: if your input line contains a third number, the program will actually calculate A*B+C.

breadbox

Posted 2011-02-07T13:37:57.427

Reputation: 6 893

How fast is it? – user unknown – 2012-05-16T03:24:23.110

It runs in O(log n), naturally. Are you asking about its actual speed? On my machine I measure roughly 2-3 times slower than Perl's builtin multiply, but I don't know how significant that is. – breadbox – 2012-05-16T06:05:25.950

1

K, 18 16

{#,/(!y),\:/:!x}

.

k){#,/(!y),\:/:!x}[4;20]
80
k){#,/(!y),\:/:!x}[13;21]
273
k){#,/(!y),\:/:!x}[3;6]
18

tmartin

Posted 2011-02-07T13:37:57.427

Reputation: 3 917

1

Ruby, 35 chars

p $*.map!(&:to_i).pop*$*.inject(:+)

It's a program, which takes input and outputs, not just a function.

.-(~/virt)-----------------------------------------------------------------------------------------------------------------------------------------------------(ice@distantstar)-
`--> wc -c golf.rb         
35 golf.rb
.-(~/virt)-----------------------------------------------------------------------------------------------------------------------------------------------------(ice@distantstar)-
`--> ruby ./golf.rb 734 929
681886

defhlt

Posted 2011-02-07T13:37:57.427

Reputation: 1 717

0

VB11, 101 Chars

   Dim m As Func(Of Integer, Integer, Integer, Integer) = Function(a, b, t) If(a = 0, t, m(a >> 1, b << 1, t + If(a Mod 2 = 1, b, 0)))

Adam Speight

Posted 2011-02-07T13:37:57.427

Reputation: 1 234

1You used a few disallowed operations... – Gaffi – 2012-05-26T08:15:24.030

I don't think this uses disallowed operations (unless control flow is disallowed; the question is unclear on that, which is part of the reason it's on hold). "mod 2" is a bit test operation. I guess comparisons (==) aren't allowed by the question, but plenty of answers are using them. – None – 2017-06-03T05:15:50.920

0

Mathematica 12

The following sums #2 instances of #1.

Code

#1~Sum~{#2}&

Usage

#1~Sum~{#2} &[734, 929]

(* out *)

681886


9 chars?

If program parameters, a, b, may be used for input, the same result can be achieved with 9 chars.

a~Sum~{b}

DavidC

Posted 2011-02-07T13:37:57.427

Reputation: 24 524