S
silly
/* hello, I have some fairly naive queries here related to optimising code!
I know the first answer is 'don't' but leave that to one side for the
moment.
1) I'm looking for constructive comments on the mul_a() and pow_a() below
comments on style/clarity/portability/obvious efficiency issues are welcome
- any better ways to write them without changing the algorithm.
2) Comments on mul_b() and pow_b() below which attempt to optimise them.
3) any better algorithms - code examples preferred,
- I don't have access to knuth at the moment!
4) I have assumed x and y are non negative integers. If x were allowed to be
negative, should be no portability issues as there are no right shifts on x,
right?
Obviously for the multiply routines only, assume there isn't an in-built
multiply
but you can double, halve and use mod (%) with a 2. A bit artificial perhaps
but
I'm trying to understand when and where you might use shifts and ANDs, etc!
Also assume pow(0,0)=1.
Thanks very much in advance
---
BTW its not a homework problem, if it were I'd go for a variation of
double ipow(double x, int n)
{
return (!n)?1
n<0)?ipow(1/x,-n)
n&1)?x*ipow(x,n-1):ipow(x*x,n/2);
}
from Mark Stephen on comp.lang.c.moderated a few years back!
which would give:
int kpow(int x, int n)
{
return (!n)?1
n&1)?x*kpow(x,n-1):kpow(x*x,n/2);
}
Presumably with tail recursion this version is quite efficient?
*/
/*--------------------start of code---------------*/
/*Tested using Borland C++ 5.6.*/
#include <stdio.h>
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* basic versions */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant multiply */
int mul_a(int x, int y)
{
int t=0;
for(;
{
if (y%2) t+=x; /* if y is odd... */
if (!(y/=2))break; /* halve y and if result is zero... */
x*=2; /* double x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant power */
int pow_a(int x, int y)
{
int t=1;
for(;
{
if (y%2) t*=x; /* if y is odd... */
if (!(y/=2))break; /* halve y and if result is zero... */
x*=x; /* square x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* better(?) versions */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant multiply - attempt to optimise */
int mul_b(int x, int y)
{
int t=0;
for(;
{
if (y&1) t+=x; /* if y is odd... */
if (!(y>>=1))break; /* halve y and if result is zero... */
x<<=1; /* double x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant power - attempt to optimise */
int pow_b(int x, int y)
{
int t=1;
for(;
{
if (y&1) t*=x; /* if y is odd... */
if (!(y>>=1))break; /* halve y and if result is zero... */
x*=x; /* square x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void main() {
int n;
putchar('\n');
for( n =0; n<=10; n++)
printf("%5d, %5d, %5d, %5d\n", n, n<<1, n>>1, n&1);
putchar('\n');
for( n =0; n<=5; n++)
printf("%5d, %5d, %5d\n", n, mul_a(n,n), pow_a(n,n));
putchar('\n');
for( n =0; n<=5; n++)
printf("%5d, %5d, %5d\n", n, mul_b(n,n), pow_b(n,n));
putchar('\n');
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*--------------------end of code-----------------*/
I know the first answer is 'don't' but leave that to one side for the
moment.
1) I'm looking for constructive comments on the mul_a() and pow_a() below
comments on style/clarity/portability/obvious efficiency issues are welcome
- any better ways to write them without changing the algorithm.
2) Comments on mul_b() and pow_b() below which attempt to optimise them.
3) any better algorithms - code examples preferred,
- I don't have access to knuth at the moment!
4) I have assumed x and y are non negative integers. If x were allowed to be
negative, should be no portability issues as there are no right shifts on x,
right?
Obviously for the multiply routines only, assume there isn't an in-built
multiply
but you can double, halve and use mod (%) with a 2. A bit artificial perhaps
but
I'm trying to understand when and where you might use shifts and ANDs, etc!
Also assume pow(0,0)=1.
Thanks very much in advance
---
BTW its not a homework problem, if it were I'd go for a variation of
double ipow(double x, int n)
{
return (!n)?1
}
from Mark Stephen on comp.lang.c.moderated a few years back!
which would give:
int kpow(int x, int n)
{
return (!n)?1
}
Presumably with tail recursion this version is quite efficient?
*/
/*--------------------start of code---------------*/
/*Tested using Borland C++ 5.6.*/
#include <stdio.h>
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* basic versions */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant multiply */
int mul_a(int x, int y)
{
int t=0;
for(;
{
if (y%2) t+=x; /* if y is odd... */
if (!(y/=2))break; /* halve y and if result is zero... */
x*=2; /* double x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant power */
int pow_a(int x, int y)
{
int t=1;
for(;
{
if (y%2) t*=x; /* if y is odd... */
if (!(y/=2))break; /* halve y and if result is zero... */
x*=x; /* square x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* better(?) versions */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant multiply - attempt to optimise */
int mul_b(int x, int y)
{
int t=0;
for(;
{
if (y&1) t+=x; /* if y is odd... */
if (!(y>>=1))break; /* halve y and if result is zero... */
x<<=1; /* double x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* peasant power - attempt to optimise */
int pow_b(int x, int y)
{
int t=1;
for(;
{
if (y&1) t*=x; /* if y is odd... */
if (!(y>>=1))break; /* halve y and if result is zero... */
x*=x; /* square x */
}
return t;
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void main() {
int n;
putchar('\n');
for( n =0; n<=10; n++)
printf("%5d, %5d, %5d, %5d\n", n, n<<1, n>>1, n&1);
putchar('\n');
for( n =0; n<=5; n++)
printf("%5d, %5d, %5d\n", n, mul_a(n,n), pow_a(n,n));
putchar('\n');
for( n =0; n<=5; n++)
printf("%5d, %5d, %5d\n", n, mul_b(n,n), pow_b(n,n));
putchar('\n');
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*--------------------end of code-----------------*/