Home > Software engineering >  Integer factorization, code isn't responding
Integer factorization, code isn't responding

Time:03-17

I'm facing an issue where my code seems to misbehave - the cursor is blinking in the terminal, but the code isn't responding, it's stuck. I tried to do some debugging, but couldn't figure out what's causing it to happen.

Here's my code:

#include <stdio.h>
int main()
{
    int prim[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71},szam,i=0;
    printf("Kerek egy szamot!\n");
    scanf("%d",&szam);
    while(szam!=1)
    {
        if(szam%prim[i]==0)
        {
            szam=szam/prim[i];
            printf("%d*",prim[i]);
        }
        else
        {
            if(szam%prim[i]!=0)
            {
                prim[i]=prim[i 1];
            }
        }
    }
    printf("1");
    return 0;
}

Basically, what it should do for an integer input is (as the title suggests integer factorization). I went through various inputs on a sheet and checked what would happen according to my code.

For input = 40 it should execute the first while loop, then step into the if clause, then get divided by 2, and output 2*. Skip the else part and enter the while loop again since 20 not equals with 1. Again, should get divided by 2, and output another 2*, repeat the same process one more time, by now outputting 2*2*2*, and for the 4th iteration, it should enter the else clause, as the input has reduced to 5. Then execute the if clause, increase value of "i" by 1, and since the value of the input should remain 5, iterate the else clause again. Then increase the value of "i" by 1 again, which points to the third element of the array by now, which is 5. Now that both values are the same (input and "i"), it should do the first if clause one more time and output 2*2*2*5*1. The code is never showing the requested 1 before the return 0;, which makes me think it gets stuck inside the while loop.

Any help is highly appreciated. Thank you in advance.

CodePudding user response:

There are multiple problems with Revision 1 of the self-answer. These include:

  • You should not be editing the prim array, but your else clause changes it. Make that const int prim[] = { … };. For a single-cycle program, that doesn't matter, but if you tried to create a loop so as to analyze multiple numbers in a single run, modifying the prim array means that it can't be reused on the next cycle unless it is initialized, but the first 20 primes don't change so you really shouldn't be modifying it at all.
  • Also, prim[i] = prim[i ]; is UB — you use i twice and modify it, and the sequencing is not defined.
  • You need to use i rather than the assignment, but you also need to ensure that i does not go out of bounds of the array.

Here's a mildly modified version of your code — it prints the prim array to show the damage done.

#include <stdio.h>

static void dump_array(const char *tag, size_t size, const int array[size])
{
    printf("%s (%zu):\n", tag, size);
    const char *pad = "";
    for (size_t i = 0; i < size; i  )
    {
        printf("%s%d", pad, array[i]);
        pad = " ";
    }
    putchar('\n');
}

int main(void)
{
    int prim[20] =
    {
         2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
        31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
    };
    int szam, i = 0;
    dump_array("Primes before", sizeof(prim)/sizeof(prim[0]), prim);
    printf("Kerek egy szamot!\n");
    scanf("%d", &szam);
    while (szam != 1)
    {
        if (szam % prim[i] == 0)
        {
            szam = szam / prim[i];
            printf("%d*", prim[i]);
        }
        else
        {
            prim[i] = prim[i   1];
            i  ;
        }
    }
    printf("1\n");
    dump_array("Primes after", sizeof(prim)/sizeof(prim[0]), prim);

    return 0;
}

This produces correct outputs on some inputs. The source was in pr53.c and the program was pr53:

$ pr53
Primes before (20):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
Kerek egy szamot!
48
2*2*2*2*3*1
Primes after (20):
3 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
$ pr53
Primes before (20):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
Kerek egy szamot!
47
47*1
Primes after (20):
3 5 7 11 13 17 19 23 29 31 37 41 43 47 47 53 59 61 67 71
$ pr53
Primes before (20):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
Kerek egy szamot!
46
2*23*1
Primes after (20):
3 5 7 11 13 17 19 23 23 29 31 37 41 43 47 53 59 61 67 71
$ pr53
Primes before (20):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
Kerek egy szamot!
165
3*5*11*1
Primes after (20):
3 5 7 11 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
$

So far, so good. Note that the code handles numbers bigger than 71 as long as the biggest prime factor is no larger than 71.

If the code reused the prim array, the factor 2 has been lost. Over time, other factors would be lost too — the analysis would no longer be correct.

However, the behaviour is less than satisfactory when the number entered has a prime factor larger than 71:

$ pr53
Primes before (20):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
Kerek egy szamot!
73
Floating point exception: 8
$

It is not very hard to write code that handles such range errors better. For example, consider this program (source pr71.c, program pr71). Since the array of primes is constant, there's no need to print it; it doesn't change. I also print 1 first so that the factors are consistently increasing. At the end, the code prints szam if it is not 1, and adds a newline.

#include <stdio.h>

int main(void)
{
    const int prim[20] =
    {
         2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
        31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
    };
    enum { NUM_PRIM = sizeof(prim) / sizeof(prim[0]) };
    int szam;
    printf("Kerek egy szamot!\n");
    if (scanf("%d", &szam) != 1)
        return 1;
    int i;
    printf("1");
    for (i = 0; i < NUM_PRIM && szam > 1; i  )
    {
        while (szam % prim[i] == 0)
        {
            szam = szam / prim[i];
            printf("*%d", prim[i]);
        }
    }
    if (szam > 1)
        printf("*%d", szam);
    putchar('\n');
    return 0;
}

Example runs:

pr71
Kerek egy szamot!
48
1*2*2*2*2*3
LP2-US-51694112 JL: pr71
Kerek egy szamot!
47
1*47
LP2-US-51694112 JL: pr71
Kerek egy szamot!
46
1*2*23
$ pr71
Kerek egy szamot!
73
1*73
$ pr71
pr71
Kerek egy szamot!
166
1*2*83
$ pr71
Kerek egy szamot!
5329
1*5329
$

Only the last result is incorrect; 5329 is 73², so it is composite. One of the many tests I ran processed the numbers in the range 5300..5330, and pr71 produced the filtered output:

1*2*2*5*5*53
1*3*3*19*31
1*2*11*241
1*5303
1*2*2*2*3*13*17
1*5*1061
1*2*7*379
1*3*29*61
1*2*2*1327
1*5309
1*2*3*3*5*59
1*47*113
1*2*2*2*2*2*2*83
1*3*7*11*23
1*2*2657
1*5*1063
1*2*2*3*443
1*13*409
1*2*2659
1*3*3*3*197
1*2*2*2*5*7*19
1*17*313
1*2*3*887
1*5323
1*2*2*11*11*11
1*3*5*5*71
1*2*2663
1*7*761
1*2*2*2*2*3*3*37
1*5329
1*2*5*13*41

This agrees with the output from another program factoring the same range — except for the second last line where 5329 is properly factored:

5300:    (2^2).(5^2).53
5301:    (3^2).19.31
5302:    2.11.241
5303:    5303
5304:    (2^3).3.13.17
5305:    5.1061
5306:    2.7.379
5307:    3.29.61
5308:    (2^2).1327
5309:    5309
5310:    2.(3^2).5.59
5311:    47.113
5312:    (2^6).83
5313:    3.7.11.23
5314:    2.2657
5315:    5.1063
5316:    (2^2).3.443
5317:    13.409
5318:    2.2659
5319:    (3^3).197
5320:    (2^3).5.7.19
5321:    17.313
5322:    2.3.887
5323:    5323
5324:    (2^2).(11^3)
5325:    3.(5^2).71
5326:    2.2663
5327:    7.761
5328:    (2^4).(3^2).37
5329:    (73^2)
5330:    2.5.13.41

CodePudding user response:

Thank you very much for the replies! I didn't know the increment could never be done by " 1". I applied your suggestions, and it works as wanted.

#include <stdio.h>
int main()
{
    int prim[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71},szam,i=0;
    printf("Kerek egy szamot!\n");
    scanf("%d",&szam);
    while(szam!=1)
    {
        if(szam%prim[i]==0)
        {
            szam=szam/prim[i];
            printf("%d*",prim[i]);
        }
        else
        {
            prim[i]=prim[i  ];
        }
    }
    printf("1");
    return 0;
}
  • Related