- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
This is, of course, a one- or two-liner (depending how long you like your lines) in Haskell and probably most other functional languages:
Or adding some labels for clarity:
Admin
oops the last 2 lines are busted (great idea to refactor just before posting :-)
Admin
Not the shortest or simplest bit of code, but a pretty elegant way of mirroring the Russian Peasant method, as opposed to looking more like binary multiplication.
Python:
Admin
I'm sure this is lost in the haze:
Didn't bother with bitshifting. Looking at the generated assembly is an interesting excersize.
Admin
I feel daring today and throw this in untested. thx for spoiler alert i did it in a text editor before scrolling down to comment. =)
// russian multiply // the usual limitations on result size apply int ru_mul(int fac0,int fac1) { int prod=0; do { prod+=(fac0&1)*fac1; fac1<<=1; } while (fac0>>=1); return prod; }
Admin
the wtf is of course that my spaces got eaten... =)
Admin
echo "In soviet russia, multiplication does YOU!"
Admin
nah, the real wtf is: ye shouldnae do sucha thing that i did there: late night surfing on coding sites while not sober. speaking of test-driven development, hihi! i inadvertedly coded for unsingeds... take brians solution!
Admin
Admin
Admin
Got to add AutoIt:
Admin
Short recursive C# technique:
Admin
This actually misses adding the first row if the initial lval is odd.
Admin
(sorry, I meant the first sample given)
Admin
Tail-recursive Mathematica implementation:
RussianPeasantTimes[x_Integer, y_Integer] := Sign[x] RussianPeasantTimesImpl[Abs[x], y, 0];
RussianPeasantTimesImpl[x, y, res] := RussianPeasantTimesImpl[Quotient[x, 2], 2 y, res + Mod[x, 2] y]; RussianPeasantTimesImpl[1, y, res_] := res + y; RussianPeasantTimesImpl[0, , res] := res;
Admin
Scheme:
(define peasant (lambda (x y) (letrec ((loop (lambda (ls1 ls2) (if (eq? (car ls1) 1) (apply + (select odd? ls1 ls2)) (loop (cons (quotient (car ls1) 2) ls1) (cons (* 2 (car ls2)) ls2)))))) (loop (list x) (list y)))))
Admin
I salute you sir!
Admin
I found a neat little trick to it. See if you can figure out what I did ;-) :
I stress tested this (with 100 million random trials against the * operator) on an x86 and a PPC machine, so it works, trust me.
Admin
You spent more than 5 minutes on a 3 minute problem. Congratulations.
Admin
Here's a version in C that multiplies two 8-bit numbers and produces a 16-bit result. It requires a 64-bit unsigned type. I know it doesn't look much like the original algorithm but that's because it treats the 64-bit variables as an array of 8-bit values that can be operated on in parallel.
Admin
C code. FACTOR can be changed to another integer > 1 without breaking the code.
Admin
Here my implementation i JavaScript (yeah, I know, not a programming language :D )
Ok, the WTF is also that it doesn't work in IE, and looks funny in Opera. And that it's a bit long, not because of the calculation, but because of the whizbang :)
Admin
Bash: abusing the arithmetic evaluation to fit the bulk of the algorithm on one line. (Everything except the line starting with echo is to handle the first argument being negative.)
Remove the outermost arithmetic brackets on the second last line to see the working.
(Note that this doesn't work unless it's in an actual script file and called as such)
Admin
Couldn't see if this had been done - but anyway how about some F#.
Admin
If you've got a copy of Excel you can always do it this way, and lets face if, if you've got Excel why wouldn't you?
Sub WhyOhWhy() Dim iRowNo As Integer Dim sValue As String
End Sub
Admin
In Newlisp. I came up with & on my own but after reading Tim's version, I used >> and <<. Mine's tested.
; odd? (= (& col1 1) 1) instead of (= (% col1 2) 0) ; half! (>> col1 1) instead of (/ col1 2) ; double! (<< col2 1) instead of (* col2 2) ; because %, / and * are expensive
(define (rus col1 col2) (let ((t 0)) (do-until (< col1 1) (if (= (& col1 1) 1) (setq t (+ col2 t))) (println col1 " x " col2) (set 'col1 (>> col1 1) 'col2 (<< col2 1))) (println t)))
Admin
;; Scheme using the design recipe and optimized for lowest number of iterations
(define (russian-multiply m n) (define (russian-multiply* x y p) (if (zero? x) p (russian-multiply* (quotient x 2) (+ y y) (if (odd? x) (+ p y) p)))) (if (< m n) (russian-multiply* m n 0) (russian-multiply* n m 0)))
Admin
these are all in python
the first is the most verbose:
The next one is less verbose, but still easy to follow:
Personally, I like this one for it's complete incomprehensibility (and that it says "lambda f,a,b:a", which makes me laugh):
agrif - 71aaeb8b415a620bf185b6093ebaf5c5
Admin
No branches in the innerloop. Should run pretty fast.
C-version:
x86 Assembly version, as compiled by MSVC
Admin
Oops, I probably should have logged in. :)
Something to add - my version doesn't need the actual CPU's multiply or divide instructions, making it feasible to implement on some processor that doesn't have that. Also, in its current incarnation, it depends on 2's Complement numbers being used.
Admin
int mult(int a, int b) { return a*b; } /because that's how computers do it in hardware, anyway./
Admin
The question is, why would I want to?
Admin
Ok, so how do I run that? I tried the "Brainfuck Interpreter" (http://koti.mbnet.fi/villes/php/bf.php), but I couldn't get any meaningful result. How do I set the input?
Otherwise: Coolest solution so far -- imho.
Admin
Can we please end the off-topic rants about Russian peasant multiplication and get back to our juicy jewelry discussion?
Admin
Common Lisp:
This time it does the expected thing when the first number is negative instead of looping forever :)
Admin
Common Lisp:
Admin
This feels a little "me too" at this point but I've tried to follow all the "rules".
Here's PHP that accounts for negative numbers, doesn't use * or /, accounts for 0 in either position and generates nifty colored output.
<?php function Russian($a,$b) { echo "\n<tr bgcolor='".($a&1?"green":"red")."'>".$a."".$b.""; if(!$a || !$b) { return 0; } if($a < 0) { $a = ($a^-1)+1; $b = ($b^-1)+1; } return (($a <= 1)?($a?$b:0):((intval($a&1)?$b:0)+Russian(intval($a>>1),$b<<1))); } ?><html> <head><title>Russian Peasant</title></head> <body> <form method="get">Admin
Another using Oracle PL/SQL
Admin
#include <iostream>
template<int I> struct is_odd { enum { value = I % 2 }; };
template<int A, int B, int Odd> struct russian_impl;
template<int A, int B> struct russian_impl<A, B, 1> { enum { value = B + russian_impl<A/2, B*2, is_odd<A/2>::value>::value }; };
template<int A, int B> struct russian_impl<A, B, 0> { enum { value = russian_impl<A/2, B*2, is_odd<A/2>::value>::value }; };
template<int B> struct russian_impl<1, B, 1> { enum { value = B }; };
template<int A, int B> struct russian { enum { value = russian_impl<A, B, is_odd::value>::value }; };
int main(int argc, char* argv[]) { std::cout << russian<18, 23>::value << std::endl; return EXIT_SUCCESS; }
Admin
In VBA
Function RussianPeasantMultiplication() Dim a As Integer, b As Integer, c As Integer a = 18 b = 23 Debug.Print a & " x " & b Do Until a = 1 a = Int(a / 2) b = b * 2 If a / 2 <> Int(a / 2) Then c = c + b Debug.Print a & vbTab & b & vbTab & b Else Debug.Print a & vbTab & b End If Loop Debug.Print vbTab & vbTab & c End Function
Admin
CREATE FUNCTION Peasant_Mul (@A INT, @B INT) RETURNS INT AS BEGIN DECLARE @Result INT; WITH f AS ( SELECT @A A, @B B UNION ALL SELECT A / 2, B * 2 FROM f WHERE A > 1 ) SELECT @Result = SUM(B) FROM f WHERE A % 2 = 1;
RETURN @Result; END GO
Admin
Here is my solution in Java. It supports really big numbers and does pretty much what you do in Russian peasant multiplication.
Admin
In Perl:
print "Enter sum in form "a x b":\n";$=<>; s!(\n|^)(\d+) x (\d+)\n$!"$1$2 x $3\n".int(($2)/2)." x ".($3 * 2)."\n"!e while!/^1 x \d+$/m; s!(\n|^)(\d*[24680]) x (\d+)!$1-($2 x $3)-!g; $v+=$2 while/(\n|^)\d+ x (\d+)/g;$.="\nTotal: $v\n"; print "Paper working is:\n$_";
Admin
Repost now I've worked out how to create an account...
In Perl:
print "Enter sum in form "a x b":\n";$=<>; s!(\n|^)(\d+) x (\d+)\n$!"$1$2 x $3\n".int(($2)/2)." x ".($3 * 2)."\n"!e while!/^1 x \d+$/m; s!(\n|^)(\d*[24680]) x (\d+)!$1-($2 x $3)-!g; $v+=$2 while/(\n|^)\d+ x (\d+)/g;$.="\nTotal: $v\n"; print "Paper working is:\n$_";
Admin
private int RussianMultiply(int input1, int input2) { int retVal = 0; do { retVal += (input1 & 1) * input2;
Admin
10 PRINT "HELLO, WELCOME TO THE RUSSIAN (FORMERLY ROMAN) PEASANT MULTIPLICATION" 20 INPUT "PLEASE, ENTER THE TWO OPERANDS: "; A, B 30 SIGN = 1 40 PRINT "IS "; A; " NEGATIVE? (Y/N)" 50 INPUT ANSWER 60 IF ANSWER = "Y" THEN SIGN = -1 70 PRINT "IS "; B; " NEGATIVE? (Y/N)" 80 INPUT ANSWER 90 IF ANSWER = "Y" THEN SIGN = SIGN * -1 100 PRINT A; " EQUALS 0? (Y/N)" 110 INPUT ANSWER 120 IF ANSWER = "Y" THEN PRINT "THE PRODUCT IS 0": END 130 PRINT B; " EQUALS 0? (Y/N)" 140 INPUT ANSWER 150 IF ANSWER = "Y" THEN PRINT "THE PRODUCT IS 0": END 160 PRINT A; " EQUALS 1? (Y/N)" 170 INPUT ANSWER 180 IF ANSWER = "Y" THEN PRINT "THE PRODUCT IS "; B: END 190 PRINT B; " EQUALS 1? (Y/N)" 200 INPUT ANSWER 210 IF ANSWER = "Y" THEN PRINT "THE PRODUCT IS "; A: END 220 INDEX = 1 230 PRINT "IS "; A; " EVEN? (Y/N)" 240 INPUT ANSWER 240 IF ANSWER = "Y" THEN PRINT "USEFUL VALUE "; INDEX; " -> "; B: INDEX = INDEX+1 250 PRINT "PLEASE, DIVIDE "; A; " BY 2 (GIVE ME THE SMALLEST PART):" 260 INPUT A 270 PRINT "PLEASE, DOUBLE "; B 280 INPUT B 290 PRINT A; " EQUALS 1? (Y/N)" 300 INPUT ANSWER 310 IF ANSWER = "Y" THEN PRINT "USEFUL VALUE "; INDEX; " -> "; B: GOTO 330 320 GOTO 250 330 PRINT "PLEASE, GIVE ME THE USEFUL VALUE 1, FROM ABOVE:" 340 INPUT A 350 AINDEX = 1 360 FOR I=2 TO INDEX 370 PRINT "PARTIAL RESULT "; AINDEX; " -> "; A 380 PRINT "PLEASE, SUM USEFUL ANSWER "; I; " WITH PARTIAL RESULT ": AINDEX 390 INPUT A 400 AINDEX = AINDEX + 1 410 NEXT 420 PRINT "THE PRODUCT IS "; A 430 END
Admin
whoops...
420 PRINT "THE PRODUCT IS "; A * SIGN
There, fixed.
CYA
Admin
Oracle SQL version, showing the working out:
Admin
multiply: XOR EAX, EAX XOR EDX, EDX CMP ECX, EAX JNL .ps NEG ECX NEG EBX .ps: XOR EDI, EDI CMP EBX, EAX SBB EBP, EBP SHR ECX, 1 JZ .nd .lp: SBB ESI, ESI MOV EDI, ESI AND ESI, EBX AND EDI, EBP ADD EBX, EBX ADC EBP, EBP ADD EAX, ESI ADC EDX, EDI SHR ECX, 1 JNZ .lp .nd: SBB ESI, ESI MOV EDI, ESI AND ESI, EBX AND EDI, EBP ADD EAX, ESI ADC EDX, EDI ; done ; ... or just use IMUL
Admin
And of course in Haskell:
multiply n m = sum $ map snd $ filter (odd . fst) $ russian n m where russian 1 m = [(1,m)] russian n m = (n,m) : russian (n
div
2) (m * 2)