int getCycleLen(int n){//counts the number of iterations before n=1
int cycle_len=0;
while(n!=1){
if(n%2==0) n/=2; else n=3*n+1;
cycle_len++;
}
return cycle_len;
}
int main(){
int i,j,n;
int max_len=0,len;
i = 1; j = 1000000;//j = a million
for(n=i;n<=j;n++){
printf("%d ",n);
len = getCycleLen(n);
if(len > max_len)
max_len=len;
}
printf("%d %d %d\n",i,j,max_len);
}
I am using Ubuntu 16.04 and compiling using gcc 5.4. For some reason the program hangs when n of the for loop is 113299. Any suggestions as to why this happens?
This is an integer overflow. Use a long for the parameter to getCycleLen instead.
You can see this for yourself if you print every value of n as you iterate in getCycleLen. When the number gets too big to fit in an int, it will overflow and become a negative number. The negative numbers will then not converge on 1.
In C, integers have a specific limit. This limit depends on the architecture of your system. But basically your value has overflowed the the max possible value stored at an integer.
Related
This question already has answers here:
Project Euler Question 14 (Collatz Problem)
(8 answers)
Closed 3 years ago.
I was writing a program which involved input up to the range of 1 million, when I was using datatype 'int' to deal with my values the run time was very very high, the program never executed itself completely so I was not able to note down the run time.
code before;
#include<stdio.h>
int main()
{
int n,m,i,maxt=0,maxn;
for(n=2;n<=1000000;n++){
m=n;
i=0;
for(i=0;m!=1;i++){
if(m%2==0)
m=m/2;
else
m=(3*m+1);
}
if(i>maxt){
maxt=i;
maxn=n;
}
}
printf("%d%d",maxn,maxt);
return 0;
}
But then while juggling with the code I changed the datatype from 'int' to 'long long int' surprisingly the run time decreased drastically(milli seconds), can anyone explain what may be the reason behind this ?
code after;
#include<stdio.h>
int main()
{
long long int n,m,i,maxt=0,maxn;
for(n=2;n<=1000000;n++){
m=n;
i=0;
for(i=0;m!=1;i++){
if(m%2==0)
m=m/2;
else
m=(3*m+1);
}
if(i>maxt){
maxt=i;
maxn=n;
}
}
printf("%lld%lld",maxn,maxt);
return 0;
}
You are calculating the Collatz conjecture. For some numbers n as input, the m's can get very large. If m gets larger than 231, with a normal int, you get a negative number. To be more explicit: when m >= 231 and m < 232 a signed 32-bit value will be interpreted as a negative number: the computer can not see such difference when only working with 32-bit.
Negative numbers for m get caught in an endless loop never reaching the m == 1 end condition. Therefore, an int type of 64 bits is needed. On the wikipedia page, 3 different loops between negative numbers are shown, for example m=-1 becomes m=-2 which again becomes m=-1 in a never ending loop.
The first time m gets larger than 231 is for n=113383 where m reaches 2482111348.
To further clarify: the problem is not with n but with m in following loop.
m=n;
for(i=0;m!=1;i++){
if(m%2==0)
m=m/2;
else
m=(3*m+1);
}
For each n, this loop gets executed many times. m starts with getting the value of n, for example 113383. In this case, after 120 steps, m reaches 2482111348, which is so big it doesn't fit anymore in a 32-bit signed integer. On most modern processors, 2482111348 gets the same representation as -1812855948. The loop now continues further with negative values. After a while, it gets in an endless loop always repeating the same 18 numbers -17, -50, -25, ..., -34, -17. And never reaching the condition m==1 needed to stop the for-loop.
Here is a small modification to your code that works with gcc
#include<stdio.h>
#include<stdlib.h>
void overflow()
{
fprintf(stderr, "Overflow\n");
exit(1);
}
int main()
{
int n,m,i,maxt=0,maxn;
for(n=2;n<=1000000;n++){
m=n;
i=0;
for(i=0;m!=1;i++){
if(m%2==0)
m=m/2;
else {
int m_prev = m;
// Replacing m = (3*m+1) with operations that checks for
// overflow
if(__builtin_mul_overflow(m,3,&m)) {
printf("%d\n", m_prev);
printf("%d\n", INT_MAX);
overflow();
}
if(__builtin_add_overflow(m,1,&m))
overflow();
}
}
if(i>maxt){
maxt=i;
maxn=n;
}
}
printf("%lld%lld",maxn,maxt);
return 0;
}
If an overflow happens, it will print "overflow" and exit. And that's what's happening. What's happening is that the result of 3*m+1 gets too large for an int to hold, which overflows it.
You can read about those gcc functions here: https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
I wrote code for getting binary form of an integer. It works well for inputs like 1 or 10. However, it is failing for inputs like 256. (It gives 0000000 s output and misses the one).
#include <stdio.h>
#include <math.h>
int number_of_binary_digits_required(int n){
return ceil(log(n))+1;
}
void print_array(int * a, int n){
int i = 0;
for (;i<n;i++){
printf("%d\t", a[i]);
}
}
int main(){
int num = 256;
int binary[100];
int n = number_of_binary_digits_required(num);
int bin_digits = n-1;
while (num){
int temp = num%2;
num = num / 2;
binary[bin_digits] = temp;
//printf("%d\n", bin_digits);
bin_digits--;
}
print_array(binary, n);
//printf("%d", number_of_binary_digits_required(num));
//for(bin_digits = 0;bin_digits < number_of_binary_digits_required(num);bin_digits++)
//printf("%d",binary[bin_digits]);
}
Why is the issue coming and how to resolve it?
Thanks you!
C's log function gives result with a base of e, not 2. This is why some numbers give unexpected result in your program since you calculate using that. There is a function log2 which is what you need i think.
Your use of a logarithmic function to compute the number of digits in conjunction with ceil will suffer due to floating point undershoot.
A more reliable way of calculating the number of binary digits is to divide by two repeatedly until zero is attained.
The first mistake is to use log(n), which calculates log of n base e.
Instead use log2(n)
Hope it helps. :-)
Problem : Consider the following algorithm to generate a sequence of
numbers. Start with an integer n. If n is even, divide by 2. If n is
odd, multiply by 3 and add 1. Repeat this process with the new value
of n, terminating when n = 1. The input will consist of a series of
pairs of integers i and j, one pair of integers perline. All integers
will be less than 1,000,000 and greater than 0.
For each pair of
input integers i and j, output i, j in the same order in which they
appeared in the input and then the maximum cycle length for integers
between and including i and j. These three numbers should be separated
by one space, with all three numbers on one line and with one line of
output for each line of input.
sample input :
1 10
sample output:
1 10 20
so i wrote this :
#include <stdio.h>
#include <string.h>
struct line{int in1;int in2;int result;};
int cycle(int in);
int main(int argc, char *argv[]) {
int cycle(int in);
char c;
int firstIn=0;
struct line l[500] ;
int pointer=0;
while(2<3){
l[pointer].in1=0;
l[pointer].in2=0;
scanf("%u %u",&l[pointer].in1,&l[pointer].in2);
if(l[pointer].in1<1||l[pointer].in2<1){
break;
}
int maxCyc=0;
int j,m;
int min,max;
if(l[pointer].in1>l[pointer].in2){
max=l[pointer].in1;
min=l[pointer].in2;
}
else{
max=l[pointer].in2;
min=l[pointer].in1;
}
for(j=min;j<=max;j++){
m = cycle(j);
if(m>maxCyc)
maxCyc=m;
}
l[pointer].result=maxCyc;
printf("%d %d %d\n",l[pointer].in1,l[pointer].in2,l[pointer].result);
pointer++;
}
}
int cycle(int in){
int cyc = 1;
while(in>1){
if(in%2==0){
cyc++;
in=in/2;
}
else{
cyc++;
in=in*3+1;
}
}
return cyc;
}
Its completly ok but when you change while(in>1) in cycle method to while(in!=1) it gets much more slower. my question is why?!
Time when its while(in>1) : 0.683 sec
and when its while(in!=1) : I waited more than 5 min nothing
happened yet :)
for input : 1 1000000
there is no infinite loop or something because in cant get below 1 at all(for that it must be already 1) .
Best regards
When you call cycle with the input value 113383, the process eventually sets n to
827370449, and 3*827370449+1 is 2482111348, which is greater than the maximum signed int and is interpreted as -1812855948. So there's your first negative number where there should be no negative number.
If this process then eventually sets n to -2, it will loop infinitely between -2 and -1 from then on. There may be other loops I haven't considered.
If you were to use an unsigned int, there is a possibility (I haven't checked) that this too will overflow eventually, which will not result in a negative value but will result in an incorrect value, invalidating your results.
No matter what integer representation you use, it would probably be a good idea to compare n with (maximum-1)/3 at the top of each loop, where maximum is the largest possible positive value of your integer type, just to be sure you do not overflow.
As you told me it was a simple overflow problem thx everyone.
max int value is 2,147,483,647; So when i changed int cycle(int in) to int cycle(long long int in) my problem was solved.
i also figured it out that my first answer with while(in>1) was wrong.
When an integer overflow occurs,the value will go below 0 .That was the reason while(in!=1) was an infinte loop.
I was really tired that i didn't figure it out by myself. sorry for that :)
This program gives us the position of the odd numbers in a given integer, this program works well, but when I give him an integer in its numbers are greater than 10 -like 123456789123-, it doesn't work.
I do not know if is a problem of ram or algorithm ?
#include<stdio.h>
#include<stdlib.h>
main(){
int a,b;
int i = 0;
scanf("%d",&a);
while(a/10!=0){
b=a%10;
if(b%2!=0)
printf("\nodd number position: %d",i);
a=a/10;
i++;
}
if(a%2!=0)
printf("\nodd number position: %d",i);
system("pause");
}
The problem is one of processor (architecture) rather than RAM. On your platform the size of an int seems to be 32 bits which cannot hold a number as large as 123456789123. As Groo commented to Raon, you could use a string instead (if you don't plan to do any calculations on the number):
char a[1024] = {0}; /* should be plenty, but extend the array even more if needed */
fgets(a, sizeof a, stdin); /* fgets is recommended as it doesn't overflow */
int i, length = strlen(a);
for(i = 0; i < length; i++){
/* count your odd digits here
left as an exercise to the reader */
/* note that you must access the individual digits using a[i] */
}
Every data type is limited to specific range.for example char is limited to range -128 to 128. if you use the beyond this range. You might get unexpected results.
In your program if you give any number which is beyond the range of integer, then you will get unexpected results
if your int size is 4 byte/32-bit you can give input with in this range –2,147,483,648 to 2,147,483,647
if Your int size is 2 byte/16-bit you can give input with in this range –32,768 to 32,767
Check this Data Type Ranges.
And if you want to give large Numbers You can declare variable as long int/long long int
and don't forgot to change format specifier when using long int(%ld) and long long int(%lld)
You can also use string and check whether all characters are digits are not by using isdigit() function in ctype.h header and convert character digit into integer digit by substracting '0'(character zero). and check whether is that odd or not.
The problem is that 123456789123 exceed the storage limit for an integer data type,
try using a string to store the value and parse it, something like
#include<stdio.h>
int main(){
char a[] = "12345678912345678913246798";
int i = 0;
for (i=0; a[i] != '\0'; i++){
if ( a[i] % 2 != 0 ) printf("%c is odd\n", a[i]);
}
return 0;
}
#include<stdio.h>
void main() {
int i;
char s[256];
scanf("%s",s);
for( i=0; s[i]!=0; ++i ) {
/*int digit = s[i]-48;
if( digit%2==1 ) break;
- or even shorter: */
if( s[i]%2==1 ) break;
}
if( s[i]!=0 )
printf( "First odd digit position: %d", i );
else
printf( "All digits are even" );
}
Here is working sample: http://cfiddle.net/sempyi
I think this program will not give proper answer if you give more than 10 digits! please correct me if I am wrong.
The max Unsigned integer value is 4294967295 (in any 32 bit processor). if the given value is more than that then it will either limit to that max value or overflow will happen. So if you give a integer which is more than 4294967295 it will not work as it supposed to.
try printing the input. In that case you will know whether complete number is sent or Max number is sent to find the odd number's position.
One way to make it work is read the input number as array of characters and then try to figure out the odd number position.
Note: for signed integer maximum is 2147483647
123456789123 is 0x1CBE991A83
so if int is 32 bit, your number is truncated (to 3197704835 or 0xBE991A83).
Number you are giving input is greater than range of int. You need to change the data type Below link should help you.
http://www.tutorialspoint.com/ansi_c/c_basic_datatypes.htm
You need to choose a data type that matches the expected data range.
If you want your program to work for any number it is probably best to read the number one character at a time.
Code (not that in this code, position is counted with the most significant digit = 1, which is the other direction compared to your code):
int c;
unsigned long long pos = 0;
while (++pos) {
c = getc();
if (c < '0' || c > '9') break; // Not a digit
if ((c - '0')%2 != 0) {
printf("\nodd number position: %ulld", pos);
}
}
The code can handle numbers that have a ridiculus amount of digits. Eventually the pos variable will overflow, though.
I'm working on Project Euler #14 in C and have figured out the basic algorithm; however, it runs insufferably slow for large numbers, e.g. 2,000,000 as wanted; I presume because it has to generate the sequence over and over again, even though there should be a way to store known sequences (e.g., once we get to a 16, we know from previous experience that the next numbers are 8, 4, 2, then 1).
I'm not exactly sure how to do this with C's fixed-length array, but there must be a good way (that's amazingly efficient, I'm sure). Thanks in advance.
Here's what I currently have, if it helps.
#include <stdio.h>
#define UPTO 2000000
int collatzlen(int n);
int main(){
int i, l=-1, li=-1, c=0;
for(i=1; i<=UPTO; i++){
if( (c=collatzlen(i)) > l) l=c, li=i;
}
printf("Greatest length:\t\t%7d\nGreatest starting point:\t%7d\n", l, li);
return 1;
}
/* n != 0 */
int collatzlen(int n){
int len = 0;
while(n>1) n = (n%2==0 ? n/2 : 3*n+1), len+=1;
return len;
}
Your original program needs 3.5 seconds on my machine. Is it insufferably slow for you?
My dirty and ugly version needs 0.3 seconds. It uses a global array to store the values already calculated. And use them in future calculations.
int collatzlen2(unsigned long n);
static unsigned long array[2000000 + 1];//to store those already calculated
int main()
{
int i, l=-1, li=-1, c=0;
int x;
for(x = 0; x < 2000000 + 1; x++) {
array[x] = -1;//use -1 to denote not-calculated yet
}
for(i=1; i<=UPTO; i++){
if( (c=collatzlen2(i)) > l) l=c, li=i;
}
printf("Greatest length:\t\t%7d\nGreatest starting point:\t%7d\n", l, li);
return 1;
}
int collatzlen2(unsigned long n){
unsigned long len = 0;
unsigned long m = n;
while(n > 1){
if(n > 2000000 || array[n] == -1){ // outside range or not-calculated yet
n = (n%2 == 0 ? n/2 : 3*n+1);
len+=1;
}
else{ // if already calculated, use the value
len += array[n];
n = 1; // to get out of the while-loop
}
}
array[m] = len;
return len;
}
Given that this is essentially a throw-away program (i.e. once you've run it and got the answer, you're not going to be supporting it for years :), I would suggest having a global variable to hold the lengths of sequences already calculated:
int lengthfrom[UPTO] = {};
If your maximum size is a few million, then we're talking megabytes of memory, which should easily fit in RAM at once.
The above will initialise the array to zeros at startup. In your program - for each iteration, check whether the array contains zero. If it does - you'll have to keep going with the computation. If not - then you know that carrying on would go on for that many more iterations, so just add that to the number you've done so far and you're done. And then store the new result in the array, of course.
Don't be tempted to use a local variable for an array of this size: that will try to allocate it on the stack, which won't be big enough and will likely crash.
Also - remember that with this sequence the values go up as well as down, so you'll need to cope with that in your program (probably by having the array longer than UPTO values, and using an assert() to guard against indices greater than the size of the array).
If I recall correctly, your problem isn't a slow algorithm: the algorithm you have now is fast enough for what PE asks you to do. The problem is overflow: you sometimes end up multiplying your number by 3 so many times that it will eventually exceed the maximum value that can be stored in a signed int. Use unsigned ints, and if that still doesn't work (but I'm pretty sure it does), use 64 bit ints (long long).
This should run very fast, but if you want to do it even faster, the other answers already addressed that.