Optimizing a nested loop in C - c

I have a nested loop to find all possible combinations of numbers between 1 and x in groups of 4, where a < b < c < d.
A method is called as each group is discovered to do a simple equivalency test on the sum of those numbers.
The loop does work and produces expected output (1 set of numbers for this particular x), however it takes 12+ seconds to find this answer and another ~5 to test the remaining possibilities, which is definitely bad, considering the x values are < 1000.
I tried having the outer loop iterate a < x - 3 times, the b loop b < x - 2 times, down to d < x times which didn't make a noticeable difference.
What would be a better approach in changing this loop?
for (a = 1; a < x; a++) {
for (b = a + 1; b < x; b++) {
for (c = b + 1; c < x; c++) {
for (d = c + 1; d < x; d++) {
check(a, b, c, d);
}
}
}
}

With such a deep level of nesting, any early exit you can introduce - particularly at the outer loops - could net big gains.
For example, you write that check is testing a + b + c + d == x && a * b * c * d == x - so you can compute the intermediate sum and product, and break when you encounter numbers that would make any selection of later numbers impossible.
An example:
for (a = 1; a < x; a++) {
for (b = a + 1; b < x; b++) {
int sumAB = a + b;
if (sumAB + sumAB > x) break;
int prodAB = a * b;
if (prodAB * prodAB > x) break;
for (c = b + 1; c < x; c++) {
int sumABC = sumAB + c;
if (sumABC + c > x) break;
int prodABC = prodAB * c;
if (prodABC * c > x) break;
for (d = c + 1; d < x; d++) {
int sumABCD = sumABC + d;
if (sumABCD > x) break;
if (sumABCD != x) continue;
int prodABCD = prodABC * d;
if (prodABCD > x) break;
if (prodABCD != x) continue;
printf("%d, %d, %d, %d\n", a, b, c, d);
}
}
}
}
This is just an example - you can constrain all the checks here further (e.g. make the first check be sumAB + sumAB + 3 > x). The point is to focus on early exits.
I added a counter for each loop, counting how many times it was entered, and tried your version and my version, with x = 100. My version has orders of magnitude less loop entries:
No early exits: 99, 4851, 156849, 3764376
With early exits: 99, 4851, 1122, 848

Related

c 8 coins combination code [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
My code is supposed to calculate the total combinations. For paying cash between 1-500 dollars using these coins: 1, 2, 5, 10, 20, 50, 100, 200. But it doesn't calculate it right. what have I done wrong?
You can assume that the input is correct and you can only use loops and if statements. You may not use recursion.
int pr, a, b, c, d, e, f, g,h, poss = 0;
printf_s("What is the amount that you like to check? (or press '0' to exit)\n");
scanf_s("%d", &pr);
for (a = 0; a <= pr; a++)
{
for (b = 0; b <= (pr/2); b++)
{
for (c = 0; c <= (pr /5); c++)
{
for (d = 0; d <= (pr /10); d++)
{
for (e = 0; e <= (pr /20); e++)
{
for (f = 0; f <= (pr / 50); f++)
{
for (g = 0; g <= (pr / 100); g++)
{
for (h = 0; h <= (pr/200); h++)
{
if (1 * a + 2 * b + 4 * c + 10 * d + 20 * e + 40 * f + 100 * g + h * 200 == pr)
poss += 1;
}
}
}
}
}
}
}printf_s("The number of possibilities is: %d.\n", poss);
}
When 5 is entered the correct number of perms is reported but expanding the code prints the wrong values. Because this line
if (1 * a + 2 * b + 4 * c + 10 * d + 20 * e + 40 * f + 100 * g + h * 200 == pr)
has the wrong denominations. It should be
if (1 * a + 2 * b + 5 * c + 10 * d + 20 * e + 50 * f + 100 * g + h * 200 == pr)
You should also move the line
printf_s("The number of possibilities is: %d.\n", poss);
outside of the loops.
Your final printf needs to be out of the loops
for (a = 0; a <= pr; a++)
{
for (b = 0; b <= (pr/2); b++)
{
for (c = 0; c <= (pr /5); c++)
{
for (d = 0; d <= (pr /10); d++)
{
for (e = 0; e <= (pr /20); e++)
{
for (f = 0; f <= (pr / 50); f++)
{
for (g = 0; g <= (pr / 100); g++)
{
for (h = 0; h <= (pr/200); h++)
{
if (1 * a + 2 * b + 4 * c + 10 * d + 20 * e + 50 * f + 100 * g + h * 200 == pr)
poss += 1;
}
}
}
}
}
}
}
}
printf("The number of possibilities is: %d.\n", poss);
As mentioned in Weather Vane answer, OP is using some wrong multipliers in the inner condition (4 and 40 instead of 5 and 50).
It's worth noting that, even with this brute force approach, we can save some CPU time by avoiding unnecessary calculations inside the (way too nested) loops and limiting the ranges of those loops to a smaller extent.
Consider the following refactorization:
#include <stdio.h>
int number_of_possibilities(int price)
{
int poss = 0;
// It takes less time to consume the bigger pieces earlier
for (
// 'a' represent the sum of the values of 200$ pieces, not the number of 200$
// pieces, which is 'a / 200'
int a = 0; a <= price;
// add the value of a single 200$ piece to move forward
a += 200 )
{
for ( int b = 0,
// 'dif_b' is what is left from the price, once the 200$ pieces are counted
dif_b = price - a;
// we don't need to iterate from 0 to 'price', but only to what is left
b <= dif_b; b += 100 )
{
// 'dif_c' is what is left once the 100$ and 200$ pieces counted so far are
// subctracted from the original price. The same holds for the inner loops
for ( int c = 0, dif_c = dif_b - b; c <= dif_c; c += 50 )
{
for ( int d = 0, dif_d = dif_c - c; d <= dif_d; d += 20 )
{
for ( int e = 0, dif_e = dif_d - d; e <= dif_e; e += 10 )
{
for ( int f = 0, dif_f = dif_e - e; f <= dif_f; f += 5 )
{
for ( int g = 0, dif_g = dif_f - f; g <= dif_g; g += 2 )
{
// now that only the 1$ coins are left to consider, we can avoid another inner
// loop and just realize that we need exactly 'dif_g - g' 1$ coins to pay the
// full price, so there is one and only one possible combination.
++poss;
}
}
}
}
}
}
}
return poss;
}
int main(void)
{
printf(" i number of possibilities\n\n");
for ( int i = 0; i < 501; ++i )
{
printf("%4d %16d\n", i, number_of_possibilities(i));
}
return 0;
}
Which gives the following:
i number of possibilities
0 1
1 1
2 2
3 2
4 3
5 4
6 5
7 6
8 7
9 8
10 11
...
99 4366
100 4563
101 4710
...
498 6159618
499 6224452
500 6295434
Executed in less then 2 seconds on an old Atom N270 at 1.6 GHz...

Converting for() loop to do{}while in C with nested loops

I am trying to write a program that will find all acute triangle solutions after the user enters a min and max value (dmin and dmax). Right now I think I have the program working using only for() loops, but I need to change the first for() loop to a do{}while loop, which is confusing me. I'm not able to figure out how to write the do{}while loop so that is also includes these nested for() loops and the if statements. Everything I've tried either tells me b and c aren't being used or it just runs and provides no output. Here is my code with the for() loops.
double a = 0, b = 0, c = 0;
printf("Here are the acute triangle solutions the program found:\n");
for (c = dmin; c <= dmax, c++)
{
for (b = dmin; b <= dmax; b++)
{
for (a = dmin; a <= dmax; a++)
{
if (a * a + b * b - c == c * c ){ //
if (((a + b) > c) && ((b + c) > a) && ((b + a) > b))
{printf("(%lf %lf %lf)\n", a, b, c);}
//sum of two sides must be greater than the third
//and angle across from c must be <90 degrees
}
}
}
}
a for (e1;e2;e3) something loop can be transformed in:
e1;
while (e2) {
something;
e3;
}
or:
e1;
if (e2) {
do {
something;
e3;
} while (e2);
}
In a do while, you simply do an initialization before and the check after. It is really somewhat similar to what the system does for a for loop.
The following code:
for (c = dmin; c <= dmax, c++)
{
for (b = dmin; b <= dmax; b++)
{
for (a = dmin; a <= dmax; a++)
{
if (a * a + b * b - c == c * c ){ //
if (((a + b) > c) && ((b + c) > a) && ((c + a) > c))
{printf("(%lf %lf %lf)\n", a, b, c);}
//sum of two sides must be greater than the third
//and angle across from c must be <90 degrees
}
}
}
}
Becomes:
c = dmin;
if(c < dmax) { //Make sure not to run once if c is greater
do
{
for (b = dmin; b <= dmax; b++)
{
for (a = dmin; a <= dmax; a++)
{
if (a * a + b * b - c == c * c ){ //
if (((a + b) > c) && ((b + c) > a) && ((c + a) > b))
{printf("(%lf %lf %lf)\n", a, b, c);}
//sum of two sides must be greater than the third
//and angle across from c must be <90 degrees
}
}
}
} while( ++c <= dmax );
}

Including first iteration in loop in C

I wrote this program to give the user all acute triangle solutions when they give a min and max value. It works correctly except it seems like the solutions don't include the first iterations of the loops (for example, with min = 1 and max = 45, (1, 1, 1) isn't included in the solutions). How can this be fixed? I thought the problem was with my while-loop for the a-value, but when I changed it into a for-loop, the problem persisted. How can I have it include these first values?
if (c >= dmin) {
c = dmin;
do {
++c;
for (b = dmin; b < dmax; b++) {
a = dmin;
while (a < dmax) {
a = a + 1;
if (a * a + b * b - c == c * c) {
if (((a + b) > c) && ((b + c) > a) && ((c + a) > b)) {
printf("(%d, %d, %d)", a, b, c);
}
}
}
}
} while (c <= dmax);
}
move ++c; after the for loop instead of before.
This increments c to 2 before it even starts, but you want to include 1.
*Note, you may want to add conditions that prevent minimums of 0 or less.
If the value range for a, b and c is [dmin..dmax] (both inclusive), the sample looks like below:
for (c = dmin; c <= dmax; c++)
{
for (b = dmin; b <= dmax; b++)
{
for (a = dmin; a <= dmax; ++a)
{
if (a * a + b * b - c == c * c )
{
if (((a + b) > c) && ((b + c) > a) && ((c + a) > b))
{
printf("(%d, %d, %d)", a, b, c);
}
}
}
}
}

Error in C program to find integer triplets (x,y,z) such that n^x + n^y = n^z for given range of n

I want to make a C program compatible for DEV-C++ 4.9.9.2 to find integer triplets (x,y,z) such that for any integer n the equation n^x + n^y = n^z holds where n is any integer in the range [a,b]. The c program would have an input of only a and b and find such possible triplets.
The code that I wrote isn't working. What's the error in it?
for (n = a ; n <= b ; n++) {
for (x = a ; x < b ; x++) {
for (y = a ; y < b ; y++) {
for (z = a ; z = b ; z++) {
c = pow(n, x);
d = pow(n, y);
e = pow(n, z);
f = c + d;
if (e = f) {
printf("(%d , %d , %d) : %d", x,y,z,n);
}
}
}
}
}
I'm a novice in C.
C correction
Try changing
if (e=f)
into
if (e==f)
The first does assignment, the second tests equality.
(Note that you may also get overflow if the numbers tested get larger than your datatype.)
Maths approach
If y==x, then:
n^x + n^x = n^z
2n^x = n^z
=> n == 0 or n == 2
Now, assume y>x and n!=0.
n^x + n^y = n^z
n^x ( 1 + n^(y-x)) = n^z
=> 1+n^(y-x) = n^(z-x)
=> 1 = 0 ( modulo n)
=> impossible unless n==0 (in which case any x,y works) or n==1 (which does not work)
So this equation has solutions for any x,y if n==0.
Otherwise, the only solutions are with n==2, x==y and z=x+1.
Change
if (e = f)
to
if (e == f)
The first one assigns f to e, enable compiler warnings for such mistakes. The second one equates the LHS to the RHS.
Secondly, assuming your program is a brute force, i.e., loops for all values of x, y and z, you might want to change this statement:
for (z = a ; z = b ; z++)
to
for (z = a ; z < b ; z++)
Your implementation is O(n^4) , actually it can be done in O(n^3) .Here is the code
for (n = a ; n <= b ; n++) {
for (x = a ; x < b ; x++) {
for (y = a ; y < b ; y++) {
{
c = pow(n, x);
d = pow(n, y);
f = c + d;
e = pow(f,1.0/n);
if (e >= a && e < b) {
z = e;
printf("(%d , %d , %d) : %d", x,y,z,n);
}
}
}
}
}

Pollard Rho factorization method implementation in C

Can anyone help me out with the pollard rho implementation? I have implemented this in C. It's working fine for numbers upto 10 digits but it's not able to handle greater numbers.
Please help me out to improve it to carry out factorization of numbers upto 18 digits . My code is this:
#include<stdio.h>
#include<math.h>
int gcd(int a, int b)
{
if(b==0) return a ;
else
return(gcd(b,a%b)) ;
}
long long int mod(long long int a , long long int b , long long int n )
{
long long int x=1 , y=a ;
while(b>0)
{
if(b%2==1) x = ((x%n)*(y%n))%n ;
y = ((y%n)*(y%n))%n ;
b/=2 ;
}
return x%n ;
}
int isprimes(long long int u)
{
if(u==3)
return 1 ;
int a = 2 , i ;
long long int k , t = 0 , r , p ;
k = u-1 ;
while(k%2==0)
{ k/=2 ; t++ ; }
while(a<=3) /*der are no strong pseudoprimes common in base 2 and base 3*/
{
r = mod(a,k,u) ;
for(i = 1 ; i<=t ; i++)
{
p = ((r%u)*(r%u))%u ;
if((p==1)&&(r!=1)&&(r!=(u-1)))
{ return 0 ; }
r = p ;
}
if(p!=1)
return 0 ;
else
a++ ;
}
if(a==4)
return 1 ;
}
long long int pol(long long int u)
{
long long int x = 2 , k , i , a , y , c , s;
int d = 1 ;
k = 2 ;
i = 1 ;
y = x ;
a = u ;
if(isprimes(u)==1)
{
return 1;
}
c=-1 ;
s = 2 ;
while(1)
{
i++;
x=((x%u)*(x%u)-1)% u ;
d = gcd(abs(y-x),u) ;
if(d!=1&&d!=u)
{ printf("%d ",d);
while(a%d==0) { a=a/d; }
x = 2 ;
k = 2 ;
i = 1 ;
y = x ;
if(a==1)
{ return 0 ; }
if(isprimes(a)!=0)
{ return a ; }
u=a ;
}
if(i==k)
{y = x ; k*=2 ; c = x ;} /*floyd cycle detection*/
if(c==x)
{ x = ++s ; }
}
return ;
}
int main()
{
long long int t ;
long long int i , n , j , k , a , b , u ;
while(scanf("%lld",&n)&&n!=0)
{ u = n ; k = 0 ;
while(u%2==0)
{ u/=2 ; k = 1 ; }
if(k==1) printf("2 ") ;
if(u!=1)
t = pol(u) ;
if(u!=1)
{
if(t==1)
{ printf("%lld",u) ; }
else
if(t!=0)
{ printf("%lld",t) ; }
}
printf("\n");
}
return 0;
}
sorry for the long code ..... I am a new coder.
When you're multiplying two numbers modulo m, the intermediate product can become nearly m^2. So if you use a 64-bit unsigned integer type, the maximal modulus it can handle is 2^32, if the modulus is larger, overflow may happen. It will be rare when the modulus is only slightly larger, but that makes it only less obvious, you cannot rely on being lucky if the modulus allows the possibility of overflow.
You can gain a larger range by a factor of two if you choose a representative of the residue class modulo m of absolute value at most m/2 or something equivalent:
uint64_t mod_mul(uint64_t x, uint64_t y, uint64_t m)
{
int neg = 0;
// if x is too large, choose m-x and note that we need one negation for that at the end
if (x > m/2) {
x = m - x;
neg = !neg;
}
// if y is too large, choose m-y and note that we need one negation for that at the end
if (y > m/2) {
y = m - y;
neg = !neg;
}
uint64_t prod = (x * y) % m;
// if we had negated _one_ factor, and the product isn't 0 (mod m), negate
if (neg && prod) {
prod = m - prod;
}
return prod;
}
So that would allow moduli of up to 2^33 with a 64-bit unsigned type. Not a big step.
The recommended solution to the problem is the use of a big-integer library, for example GMP is available as a distribution package on most if not all Linux distros, and also (relatively) easily installable on Windows.
If that is not an option (really, are you sure?), you can get it to work for larger moduli (up to 2^63 for an unsigned 64-bit integer type) using Russian peasant multiplication:
x * y = 2 * (x * (y/2)) + (x * (y % 2))
so for the calculation, you only need that 2*(m-1) doesn't overflow.
uint64_t mod_mult(uint64_t x, uint64_t y, uint64_t m)
{
if (y == 0) return 0;
if (y == 1) return x % m;
uint64_t temp = mod_mult(x,y/2,m);
temp = (2*temp) % m;
if (y % 2 == 1) {
temp = (temp + x) % m;
}
return temp;
}
Note however that this algorithm needs O(log y) steps, so it's rather slow in practice. For smaller m you can speed it up, if 2^k*(m-1) doesn't overflow, you can proceed in steps of k bits instead of single bits (x*y = ((x * (y >> k)) << k) + (x * (y & ((1 << k)-1)))), which is a good improvement if your moduli are never larger than 48 or 56 bits, say.
Using that variant of modular multiplication, your algorithm will work for larger numbers (but it will be significantly slower). You can also try test for the size of the modulus and/or the factors to determine which method to use, if m < 2^32 or x < (2^64-1)/y, the simple (x * y) % m will do.
You can try this C implementation of Pollard Rho :
unsigned long long pollard_rho(const unsigned long long N) {
// Require : a composite number N, not a square.
// Ensure : res is a non-trivial factor of N.
// Option : define a timeout, define a rand function.
static const int timeout = 18;
static unsigned long long rand_val = 2994439072U;
rand_val = (rand_val * 1025416097U + 286824428U) % 4294967291LLU;
unsigned long long res = 1, a, b, c, i = 0, j = 1, x = 1, y = 1 + rand_val % (N - 1);
for (; res == 1; ++i) {
if (i == j) {
if (j >> timeout)
break;
j <<= 1;
x = y;
}
a = y, b = y;
for (y = 0; a; a & 1 ? b >= N - y ? y -= N : 0, y += b : 0, a >>= 1, (c = b) >= N - b ? c -= N : 0, b += c);
y = (1 + y) % N;
for (a = N, b = y > x ? y - x : x - y; (a %= b) && (b %= a););
res = a | b;
}
return res;
}
Otherwise there is a pure C quadratic sieve which factors numbers from 0 to 300-bit.

Resources