#### 184 lines 4.6 KiB Plaintext Raw Normal View History

 2016-08-19 01:25:18 +00:00 `# Russian Peasant Multiplication` ``` ``` 2020-02-05 17:37:39 +00:00 `From Assembly to Basic to C to Javascript!` 2016-08-19 01:33:28 +00:00 ``` ``` 2020-02-05 16:46:06 +00:00 `Here are my implementations of Russian Peasant Multiplication implemented in various languages:` 2016-08-19 01:25:18 +00:00 ``` ``` 2020-02-05 16:46:06 +00:00 `* 6502 Assembly Language (Both [ca65](rpm_ca65.s) and [merlin32](rpm_m32.s) sources)` 2016-08-19 01:25:18 +00:00 `* Applesoft BASIC` `* JavaScript (Procedural version)` `* JavaScript (OOP version)` ``` ``` 2016-08-19 01:33:28 +00:00 `A .dsk image has been provided as an convenience.` 2016-08-19 01:25:18 +00:00 ``` ``` `To see how much faster the Assembly version is then the BASIC version:` ``` ``` ````` `RUN RPM.BAS` `BRUN RPM.BIN` ````` ``` ``` `And enter in `123456789` * `987654321` respectively for A and B ...` ``` ``` `| Version | Time |` `|:----------|:-----|` `| Applesoft | 33 s |` `| Assembly | ~1 s |` ``` ``` 2016-08-19 14:17:35 +00:00 `# So what the heck is it?` ``` ``` 2016-08-19 14:52:19 +00:00 `An alternative algorithm to implement multiplication using only:` 2016-08-19 14:17:35 +00:00 ``` ``` 2020-02-05 16:46:25 +00:00 `* bit-shifts (left and right), and` 2016-08-19 14:17:35 +00:00 `* addition.` ``` ``` `# Algorithm` ``` ``` 2020-02-05 17:37:39 +00:00 `1. Initialize Sum <- zero. In C nomenclature: `Sum = 0;`` `2. If B is odd then add A to Sum. In C nomenclature: `Sum += A;`` `3. Multiply A by 2 -- that is, Shift A **left** by one. In C nomenclature: `A <<= 1;`` `4. Divide B by 2 -- that is, Shift B **right** by one. In C nomenclature: ` B >>= 1;`` 2020-02-05 17:37:39 +00:00 `5. If B is zero then STOP. `while( b ) { ... }`` `6. Goto step 2` ``` ``` 2020-02-05 17:37:39 +00:00 `Paste the following program into an [online C compiler](https://www.onlinegdb.com/online_c_compiler)` ``` ``` ````c` `#include ` ``` ``` `int RPM( int a, int b )` `{` ` int sum = 0;` ``` ``` ` while( b )` ` {` ` if( b & 1 )` ` sum += a;` ``` ``` ` a <<= 1;` ` b >>= 1;` ` }` ``` ``` ` return sum;` `}` ``` ``` `int main()` `{` ` return printf( "%d\n", RPM( 86, 57 ) );` `}` ````` ``` ``` `# Examples` ``` ``` 2016-08-19 15:13:09 +00:00 `Example of "traditional" multiplication:` 2016-08-19 14:17:35 +00:00 ``` ``` `In base 10:` ``` ``` ````` ` 86` ` x 57` ` ----` ` 602` ` 430` ` ====` ` 4902` ````` ``` ``` `In base 2:` ``` ``` 2016-08-19 14:20:26 +00:00 ````` 2016-08-19 14:17:35 +00:00 ` 01010110 (86)` ` 00111001 (57)` ` --------` ` 01010110 (86 * 2^0 = 86)` 2020-02-05 16:46:48 +00:00 ` 00000000 (86 * 2^1 = 172) <- wasted work, partial sum = 0` ` 00000000 (86 * 2^2 = 344) <- wasted work, partial sum = 0` 2016-08-19 14:17:35 +00:00 ` 01010110 (86 * 2^3 = 688)` ` 01010110 (86 * 2^4 = 1376)` ` 01010110 (86 * 2^5 = 2752)` ` ==============` ` 01001100100110 (4902 = 86*2^0 + 86*2^3 + 86*2^4 + 86*2^5)` 2016-08-19 14:20:26 +00:00 ````` 2016-08-19 14:17:35 +00:00 ``` ``` `Example of Russian Peasant multiplication:` ``` ``` `In Base 10:` ``` ``` ````` 2020-02-05 16:48:04 +00:00 ` A B B Odd? Sum = 0` ` 86 57 Yes + A = 86` ` x 2 = 172 / 2 = 28 No = 86` ` x 2 = 344 / 2 = 14 No = 86` ` x 2 = 688 / 2 = 7 Yes + A = 774` ` x 2 = 1376 / 2 = 3 Yes + A = 2150` ` x 2 = 2752 / 2 = 1 Yes + A = 4902` 2016-08-19 14:17:35 +00:00 ````` ``` ``` `In Base 2:` ``` ``` ````` 2020-02-05 16:50:19 +00:00 ` A B B Odd? Sum = 0` ` 01010110 00111001 Yes + A = 00000001010110` ` 010101100 00011100 No = 00000001010110` ` 0101011000 00001110 No = 00000001010110` ` 01010110000 00000111 Yes + A = 00001100000110` ` 010101100000 00000011 Yes + A = 00100001100110` ` 0101011000000 00000001 Yes + A = 01001100100110` 2016-08-19 14:17:35 +00:00 ````` 2020-02-05 16:48:04 +00:00 ``` ``` `In Base 8:` ``` ``` ````` ` A B B Odd? Sum = 0` ` 126 71 Yes + A = 126` ` x 2 = 254 / 2 = 34 No = 126` ` x 2 = 530 / 2 = 16 No = 126` ` x 2 = 1260 / 2 = 7 Yes + A = 1406` ` x 2 = 2540 / 2 = 3 Yes + A = 4146` ` x 2 = 5300 / 2 = 1 Yes + A = 11446` ````` ``` ``` `In Base 16:` ``` ``` ````` ` A B B Odd? Sum = 0` ` 56 39 Yes + A = 56` ` x 2 = AC / 2 = 1C No = 56` ` x 2 = 158 / 2 = E No = 56` ` x 2 = 2B0 / 2 = 7 Yes + A = 306` ` x 2 = 560 / 2 = 3 Yes + A = 866` ` x 2 = AC0 / 2 = 1 Yes + A = 1326` ````` ``` ``` `# Efficiency` 2020-02-05 16:48:54 +00:00 ``` ``` `For a "BigInt" or "BigNumber" library this _is NOT_ the most efficient (\*) way to` ` multiply numbers as it doesn't scale (\*\*). However, it is rather trivial to implement. You only need a few` 2020-02-05 16:48:54 +00:00 ` functions:` ``` ``` `* `isEven()`` `* `isZero()`` `* `Shl()`` `* `Shr()`` `* `AddTo()`` 2020-02-05 16:48:04 +00:00 ``` ``` `Notes:` ``` ``` `(\*) Almost everyone uses FFT (Fast Fourier Transforms), Toom, and/or Karatsuba for multiplication. For example [GMP](https://gmplib.org/manual/), GNU Multiple Precision arithmetic library, uses **[seven](https://gmplib.org/manual/Multiplication-Algorithms.html#Multiplication-Algorithms)** different multiplication algorithms!:` ``` ``` `* Basecase` `* Karatsuba` `* Toom-3` `* Toom-4` `* Toom-6.5` `* Toom-8.5` `* FFT` ``` ``` `(\*\*) What do we mean by "Doesn't scale"? As the input numbers uses more bits we end up doing more work other other algorithms.` ``` ``` `# References` ``` ``` `* https://tspiteri.gitlab.io/gmp-mpfr-sys/gmp/Algorithms.html#Multiplication-Algorithms` `* https://en.wikipedia.org/wiki/Multiplication_algorithm` ``` ```