Thread: Long (really long) number

  1. #1
    Registered User
    Join Date
    Aug 2007
    Posts
    13

    Long (really long) number

    Indeed.
    So, as probably someone understood from my previous post, I'm trying to work my way out of the easiest problems listed in projecteuler.net, in an attempt to improve my coding skills and my knowledge of the C language. Anyway, I'm stuck again, after I completed a couple of other problems since your last help, and here's why.

    The point of the code that follows is to calculate a really big sum: one hundred 50-digits numbers have to be summed. I thought a bit about it and I came to this conclusion: I could copy-paste the values in a file, and from there I could loop as follows: read one string, convert it to a integer, sum and then proceed to the next value. Perhaps you already spotted the problem - I can't find a way to store the value, 'cause nothing I've found is big enough for a 50-digits number. The sad thing is that it dawned me all together when I've found this. If I understood it correctly, it says that the maximum value that could be stored is 18,446,744,073,709,551,615, an unsigned long long. Which is exactly what I'm using, and that's why when I convert from string to integer I receive unpleasant results.

    Code:
    /*Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.
    
     *SEE FILE ATTACHED** */
    
    #include<stdio.h>
    #include<stdint.h>
    #include<stdlib.h>
    
    int main(int argc, char *argv[]) {
        int i;
        uintmax_t pivot=0, sum=0;
        char ascii_num[50], ascii_sum[sizeof(uintmax_t)*8]; //this last one is gonna be 64 
        FILE *fp;
    
        //File opening
        fp=fopen("problem13.txt", "r");
        if (fp==NULL) {
            printf("Error: could not open file problem13.txt.\nPress any key to exit.\n");
            getch();
            return (1);
        }
        
        while (fgets(ascii_num, 50, fp) != NULL) {
            pivot = atoll(ascii_num);
            sum +=pivot;
        }
        
        itoa(sum, ascii_sum, 10);
        
        for(i=0; i<10; i++) {
            printf("%d", ascii_sum[i]);
        }
        
        fclose(fp);
        
        printf("\nPress any key to continue.\n");
        getch();
        return (0);
    }
    I tried in several different ways to work around the conversion from string to integer - atoll is just the last one in chronological order.
    My main point is: is this algorithm flawed, or can this work out the way I want? I can see at least one other problem down the road (that atoi down there, for the second conversion), so I'm not really sure this is the best way to do it. Actually, I'm sure this is not it - should I rethink my solution? Any ideas?
    Last edited by Doriän; 09-05-2007 at 05:12 PM.

  2. #2
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Generally, these days an unsigned long long is 64-bits and an int is 32-bits, so don't do any conversions to or from int if you're going to be using a 64-bit number.

    One solution, perhaps easier, is to simply add it all one digit's place at a time, while storing the carry. You should be able to handle that without a chance of overflow. Even 100 9's added together is just 900.

    The next time around, you have to add the carry as well. Keep the data always as a string except when adding numbers together. When you want to print it out, use a string, not an int.

  3. #3
    Registered User
    Join Date
    Aug 2007
    Posts
    13
    Thanks!
    I see your point here - and to be honest, I already thought of doing something like that, but left the idea when I realized I had no idea how to switch lines...now I'll think a bit about it and I'll write here the conclusions!

  4. #4
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    If you did it by digit, you would simply need two loops. One to read in each 50-digit number, and an inner loop to handle the addition.

    The outter loop would be used to read in the line, using fgets(). If fgets() returns NULL, you can then use feof() and ferror() to figure out what happened. You can also do some checking here to make sure that you do indeed have 50 digits (using strlen()), so you can catch invalid input (or use it to extend the size of the number to 50 digits with 0 padding), although this may not be as important if the question requires each line of input to be 50 and only 50 digits long.

    The inner loop would be where you do the actual work. Get the index of the last element of your result so far (initially set to 0's at the beginning of the program), and add to the last element of the new number you've read it. Lower index numbers. Rinse and repeat.

    It's not a complete description, but it should give you an idea of what I'm talking about.

  5. #5
    Registered User
    Join Date
    Jul 2005
    Posts
    14
    Doriän, I've spent some time on project euler aswell some time ago. For this problem you don't need to handle 50-digit numbers, in fact, the native types will suffice (if you read the description carefully and think about it).

  6. #6
    Registered User
    Join Date
    Aug 2007
    Posts
    13
    Hi guys! Thanks for the tips, I did it quite alright with your suggestions!
    I ended up reading the numbers and coping them in a bi-dimensional array. There I looped summing, storing only (sum/10) in the sum vector and carrying (sum&#37;10) over the next sum. Felt kinda dumb afterwards, my previous attempt was really lame :|. Meh, ain't gonna make the same mistake next time anyway!

    Here's some code:

    Code:
    /*Work out the first ten digits of the sum of the following one-hundred 50-digit numbers.
    
     *SEE FILE ATTACHED** */
    
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    int main(int argc, char *argv[]) {
    	int i, x=0, y=0, sum=0, carry=0, result[500];
    	char num[100][50], row[60];
    	FILE *fp;
    	
    	//File opening
    	fp=fopen("problem13.txt", "r");
    	if (fp==NULL) {
    		printf("Error: could not open file problem13.txt.\nPress any key to exit.\n");
    		getch();
    		return (1);
    	}
    	
    	while(fgets(row, 60, fp) != NULL) {
    		for(i=0; i<=50; i++) {
    			num[y][i] = row[i];
    		}
    		y++;
    	}
    	
    	memset(result, 0, sizeof(result));
        
    	sum = carry = 0;
    	for(i=49; i>=0; i--) { //i points to column
    		sum += carry;
    		for(y=0; y<100; y++) { //y points to row
    			sum += num[y][i]-48;
    		}
    		carry = sum/10;
    		result[x] = sum%10;
    		x++;
    		sum = 0;
    	}
    	
    	fclose(fp);
    	
    	printf("\nPress any key to continue.\n");
    	getch();
    	return (0);
    }

    I found the debugger quite useful with this program - I'm starting to understand the potential of that tool. I actually used it to get the solution, I was too lazy to write the for loop required to read the first ten digits, so I just read the values of my variables from the debugger and it worked out quite alright!

    edit: lol I just realized that code is a real mess.
    Last edited by Doriän; 09-10-2007 at 03:29 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Compiling sample DarkGDK Program
    By Phyxashun in forum Game Programming
    Replies: 6
    Last Post: 01-27-2009, 03:07 AM
  2. sorting using pointer to pointer not working
    By eager2no in forum C Programming
    Replies: 17
    Last Post: 09-21-2008, 12:52 AM
  3. Nim Trainer
    By guesst in forum Game Programming
    Replies: 3
    Last Post: 05-04-2008, 04:11 PM
  4. Quick, Partiotion, and Insertion Sort
    By silicon in forum C++ Programming
    Replies: 0
    Last Post: 05-18-2005, 08:47 PM
  5. can someone check this out and let me know ?
    By javaz in forum C Programming
    Replies: 5
    Last Post: 01-21-2002, 02:13 PM