[Patches] Long Multiplication is not commutative.

Christian Tismer tismer@tismer.com
Fri, 07 Apr 2000 21:19:26 +0200


> The following factorial loops differ by a remarkable
> factor of 1.8, and we can gain this speed by changing
> long_mult to always put the lower multiplicand into the left.
> 
> This was reported to me by Lenny Kneler, who thought he had
> found a Stackless bug, but he was actually testing long math. :-)
> 
> This buddy...
> 
> >>> def ifact3(n) :
> ...  p = 1L
> ...  for i in range(1,n+1) :
> ...    p = i*p
> ...  return p
> 
> performs better by a factor of 1.8 than this one:
> 
> >>> def ifact1(n) :
> ...  p = 1L
> ...  for i in range(1,n+1) :
> ...    p = p*i
> ...  return p

Checkin-message:
long multiplication is more efficient if the smaller
argument is at the left side. This patch swaps the
arguments accordingly. Thanks to Lenny Kneler who
let me find this out by chance.

Changed files:
longobject.c  test_long.py

Diff:
*** //d/cvsroot/python-pu/python/dist/src/lib/test/test_long.py	Thu Dec 23
15:36:42 1999
--- //d/python/python-1.5.2/lib/test/test_long.py	Fri Apr 07 20:55:38 2000
***************
*** 77,82 ****
--- 77,84 ----
  def test_division_2(x, y):
      q, r = divmod(x, y)
      q2, r2 = x/y, x%y
+     pab, pba = x*y, y*x
+     check(pab == pba, "multiplication does not commute for", x, y)
      check(q == q2, "divmod returns different quotient than / for", x, y)
      check(r == r2, "divmod returns different mod than % for", x, y)
      check(x == q*y + r, "x != q*y + r after divmod on", x, y)
*** //d/cvsroot/python-pu/python/dist/src/objects/longobject.c	Thu Dec 23
15:41:28 1999
--- //d/python/python-1.5.2/objects/longobject.c	Fri Apr 07 20:59:16 2000
***************
*** 1196,1201 ****
--- 1196,1210 ----
  	
  	size_a = ABS(a->ob_size);
  	size_b = ABS(b->ob_size);
+ 	if (size_a > size_b) {
+ 		/* we are faster with the small object on the left */
+ 		int hold_sa = size_a;
+ 		PyLongObject *hold_a = a;
+ 		size_a = size_b;
+ 		size_b = hold_sa;
+ 		a = b;
+ 		b = hold_a;
+ 	}
  	z = _PyLong_New(size_a + size_b);
  	if (z == NULL)
  		return NULL;
%%%%%%%%%%%%%%%%%%%%%%% end patch %%%%%%%%%%%%%%%%%%%%%%%%%%
Disclaimer:
I confirm that, to the best of my knowledge and belief, this
contribution is free of any claims of third parties under
copyright, patent or other rights or interests ("claims").  To
the extent that I have any such claims, I hereby grant to CNRI a
nonexclusive, irrevocable, royalty-free, worldwide license to
reproduce, distribute, perform and/or display publicly, prepare
derivative versions, and otherwise use this contribution as part
of the Python software and its related documentation, or any
derivative versions thereof, at no cost to CNRI or its licensed
users, and to authorize others to do so.

I acknowledge that CNRI may, at its sole discretion, decide
whether or not to incorporate this contribution in the Python
software and its related documentation.  I further grant CNRI
permission to use my name and other identifying information
provided to CNRI by me for use in connection with the Python
software and its related documentation.

-- 
Christian Tismer             :^)   <mailto:tismer@appliedbiometrics.com>
Applied Biometrics GmbH      :     Have a break! Take a ride on Python's
Kaunstr. 26                  :    *Starship* http://starship.python.net
14163 Berlin                 :     PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint       E182 71C7 1A9D 66E9 9D15  D3CC D4D7 93E2 1FAE F6DF
     where do you want to jump today?   http://www.stackless.com