Question:
How does this code work ?
Nace
2012-01-02 09:25:21 UTC
I have been working on my own code for a C program. I asked help on a forum and someone posted only this code. It was terribly difficult to understand at first, but I have been working through to try and understand what is going on by renaming variables and trying to comment. It computes the factorial of an input value then sums the digits together.

1) How are these two the same?
int_array[j] = sum -(100000*(sum/100000));
int_array[j] = sum % 100000;

2) Also, how does doing integer division by 100,000 work? I will try an simulate what I believe the above code is doing. I tried similar methods for my program but used integer division by 10.
10! = 3,268,800.
10! / 100,000 = 36
36 * 100,000 = 3,600,000
3,628,800 - 3,600,000 = 28,800 (adds to sum)
Sum is suppose to be small digits. 10! sum = 27. ( 3+6+2+8+8 ... )

3) What does the %05d placeholder do? (%d is for integers, but why the 05?)

Also, if anyone can decipher what is happening here, would you mind elaborating? I understand that the code takes an integer and computes the factorial and adds that to an int array. The sum of its digits are calculated by adding each number together inside of the array. What I do not understand is how it gets accomplished through the use of each loop using such confusing variables.

http://codepad.org/TUk0sVL1
Five answers:
husoski
2012-01-02 11:39:50 UTC
It computes a factorial as a very large integer in the (int_array[]) variable, then computes the sum of digits in the (sum) variable. (That's at the end. The (sum) variable is also used for temporary results in the



1. Integer division of unsigned numbers (and positive signed numbers) is defined to truncate the quotient, if needed, toward 0. That means that 24/5 = 4. It works just like grade-school quotient-and-remainder division, where a/b is the quotient of a divided by b, and a%b is the remainder. So, if:



q = a/b .... and

r = a%b



then a == q*b + r



Now, it's simple algebra. If a == q*a + r, then r = a - q*b. But r is a%b, and q is a/b, so:



r == a - q*b

a%b == a - (a/b)*b



That's basic enough that it's the formal definition of what the % operator does, even with signed integer types where the rounding direction is implementation-dependent. So, substitute sum for a and 100000 for b and you get your result:



sum%100000 == sum - (sum/100000)*100000



2. The arithmetic into the int_array[] array is much like grade-school arithmetic, too, only the "digits" are in base 100000. When you multiply two digits, the result may be larger than a single digit. You handle that by writing down the ones digit, and "carrying" the tens digit. If you add:



product = a * b .... where a and b are digit values from 0 to 9



the ones digit of product is (product%10) and the carry is (product/10). The same idea is used to multiply in "base 100000", by storing sum%100000 and carrying (sum/100000) to the next iteration of the loop. The sum variable at entry to the for(j) loop is the carry-in from the preceding digit position, and the first statement makes it equal to (carry-in) + (digit j of big number)*(i). That is, it's i times the next digit, plus whatever was "carried from the right".



3. In a printf format, %d is for (signed) *decimal*. (You'd use %u for unsigned decimal formatting, or %x for hexadecimal. Read the docs for more information.) The 5 is the minimum width to format. If the formatted result is smaller, it is right-adjusted in a 5-position field. The 0 in front of the width says to pad with zeros on the left instead of spaces. A number like 123 in the array would normally format as only three characters, but with %05d formatting it will display as 00123 instead. That's exactly what you want for all but the very leftmost digit (which is formatted with just %d, outside the loop, to suppress leading zeros for that group of base-ten digits only.)



Summary:



The base-100000 "digits" are stored in the int_array[] variable with the ones digit in int_array[0], the 100,000s digit in int_array[1], the 10,000,000s digit in int_array[2] and so on. The variable k is the index of the highest-order digit currently in the array.



In the for(i) loop, i is the muliplier 2, 3, 4, ..., (input) Each iteration multiplies int_array[] by i.



The for(j) loop multiplies one digit of int_array by i, adds the previous carry, stores the low "digit" of the result back into the current digit position, and computes the carry into the next position.



The while(sum>0) loop increases the size of the number in int_array[] when there is a carry out of the highest previous position.



The standalone printf() prints the label and leftmost digits.



The for(z) loop prints out the remaining digits, preserving interior zeros (as noted above).



The final for(i) loop computes the sum of the decimal digits of int_array[]. In each iteration, z is one "base 100000" digit of int_array, with up to 5 nonzero digits.



The while(z) loop (which means "while (z != 0)" in standard C/C++) is a classic loop, using the ideas above, to add the decimal digits of a non-negative integer value. Standard C/C++ doesn't define exactly what it does for negative values, but that doesn't happen here.



- - - -



A final (patriotic?) note: As written, the int_array[] will hold any whole number up to 5000 digits (1000 positions, 5 decimal digits in each position.) The first factorial to overflow this is 1776!.
peteams
2012-01-02 10:08:14 UTC
1) The % operator returns the remainder after division, as in the 6 in "20 divided 7 is 2 remainder 6". The / operator on integers returns the whole part of the division, as in the 2 in my example.



sum-(100000*(sum/100000)) is the same as sum%100000 because the division loses the remainder, the multiplication returns the value to the correct magnitude and the subtraction obtains the actual remainder.



2) The code works by doing long division, just like you were taught in the first years of school. The difference here is that you were taught in base 10, this code is working in base 100000. So the code "carries" when a "digit" reaches 100000, rather than 10 as you did.



3) %d is the decimal integer placeholder. %5d modifies the placeholder to take 5 characters, so 0 will print as four spaces followed by the zero, rather than just zero. The additional 0 in %05d says to zero pad rather than space pad, so 0 prints as 00000. That allows the program to print it's based 100000 numbers so they look like base 10.



Why does the code need to work in base 100000? Integers in C have a finite range, and factorials start exceeding that range very quickly. So in the absence of a type that can hold massive integers, or sacrificing accuracy and using doubles, a solution like this is needed. More normally you would use a library that offered alternative number types and use C++ rather than C.
anonymous
2012-01-02 09:38:10 UTC
There was a site i used to be a part of. Called " Hackforums.net". They have a subforum for programming and a spot for C. Most of the programs put on hack forums come with the code as most people are learning from each other there.You could copy and paste this excact question there. There are some smart people on there. Not sure if it has changed since i been there. Hope it didint get overun by little wanna-be kids and horrible trolls. And no its not a pure hacking forums its a community were computer savvy people hang out.Be weary though you will ecounter some bad trolls and/or kids who say they will "hax" you with your ip address. Just ignore them there are some really intelligent people on that forum.
anonymous
2012-01-02 10:17:10 UTC
in C the remainder as a result of integer division is discarded and the result is always rounded down. Also if the absolute value of numerator is less than the absolute value of the denominator, the result is zero. All calculations done by your computer(with instructions from you program) are done in binary, which is turning bits off or on. I don't know what you are doing with the factorial stuff.
?
2012-01-02 10:16:31 UTC
The sample code you cited was way too complex for your problem

this should be easier to follow:



#include



int main(void)

{

long f=1,input;

int i,sum=0;

printf("Enter a number: ");

scanf("%d", &input);

for (i = 2; i <= input; i++)

f=f*i;

printf("%ld! = %ld", input, f);

while (f>0) {

sum=sum+f%10;

f=f/10;

}

printf( " sum: %d", sum );

return 0;



}



1) How are these two the same?

int_array[j] = sum -(100000*(sum/100000));

int_array[j] = sum % 100000;



consider that sum is 100001

100001 -(100000*100001/100000)

100001 -(100000* 1)

100001 -100000

1





10! = 3,268,800.

10! / 100,000 = 32

32 * 100,000 = 3,200,000

3,268,800 - 3,200,000 = 68,800 (adds to sum)

not what you want to do

this is easier:

sum=0;

while (n>0) {

sum=sum+n%10;

n=n/10;

}

let us say that we want to sum the digits in 123

n=123;

sum=0;

sum = sum+ n%10. // sum =sum +3 // sum ==3

n=n/10; //now n=12

sum =sum + n%10 // sum =sum +2 // sum ==5

n=n/10 // n now equals 1

sum=sum +n%10 // sum =sum +1 // sum==6

n=n/10// n now equals 0 so we stop.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...