Finding trailing 0's in factorial of a number - c

#include <stdio.h>
main() {
int n;
scanf("%d", &n);
int zz, count;
int i = 5;
while(zz >= 1) {
zz = n / i;
count += zz;
i = i * 5;
}
printf("%d", count);
}
This is code to find trailing 0's in factorial of a number.
It's giving different output in Ubuntu than on Windows.

You can find out at least a few of the issues by enabling warnings during compilation. In this case (output from clang -Wall -Wextra the_file.c):
tst.c:3:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main() {
^
tst.c:10:9: warning: variable 'count' is uninitialized when used here [-Wuninitialized]
count += zz;
^~~~~
tst.c:6:18: note: initialize the variable 'count' to silence this warning
int zz, count;
^
= 0
tst.c:6:9: warning: variable 'zz' is used uninitialized whenever function 'main' is called [-Wsometimes-uninitialized]
int zz, count;
~~~~^~
tst.c:8:11: note: uninitialized use occurs here
while(zz >= 1) {
^~
tst.c:6:11: note: initialize the variable 'zz' to silence this warning
int zz, count;
^
= 0
3 warnings generated.
You should fix all of those first.

I'm not sure exactly what you're asking, but there are a couple problems with your code I can point out:
Indent your code. Indenting code is mandatory.
Try to put whitespace around operators. It goes a long way towards making your code more readable.
Don't use scanf. You will be much happier if you avoid the entire scanf family of functions.
You're using zz and count without initializing them. C does not initialize variables to any particular value; you always must initialize them yourself.
You should really change main to int main. They do the same thing, but the latter is easier to read.
If you add some test cases explaining what your code is supposed to do, it will be easier to answer your question.

Uninitialized variable
int zz, count;
int i = 5;
while(zz >= 1) { // what is zz?
i = i * 5; overflows. Undefined behavior. Different result on different systems is not unexpected.
--
There is no need to compute the factorial. Just count the number of 5s in n.
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
printf("%d", n/5);
}
15! --> 1307674368000
9! --> 362880
To have a trailing 0, the factual needs a product of some multiple of 5 and a multiple of 2. Every other number in the factorial combination is even and every 5th is a multiple of 5.

public static void main(String[] args) {
int n=23;
String fact= factorial(BigInteger.valueOf(23)).toString();
System.out.format("Factorial value of %d is %s\n", n,fact);
int len=fact.length();
//Check end with zeros
if(fact.matches(".*0*$")){
String[] su=fact.split("0*$");
//Split the pattern from whole string
System.out.println(Arrays.toString(fact.split("0*$")));
//Subtract from the total length
System.out.println("Count of trailing zeros "+(len-su[0].length()));
}
}
public static BigInteger factorial(BigInteger n) {
if (n.equals(BigInteger.ONE) || n.equals(BigInteger.ZERO)) {
return BigInteger.ONE;
}
return n.multiply(factorial(n.subtract(BigInteger.ONE)));
}

Related

Totally unexpected output when trying to compute the average using arrays

I am trying to compute the average after reading in the data from a text file of int type.The program compiles fine. clang -std=gnu11 -Weverything -g3 -pedantic -g3 -O3 -lm average_weight_of_elephant_seals.c -o average_weight_of_elephant_seals
Suppose I want to compute the average weight of 2000 seals,the expected output is 6838.848152 but I get 1710.566467.I have no idea how to make sense of GDB yet.
Could someone please point out where have I have gone wrong?
/* The following program demonstrates the usage of fscan to read in a set of integer data into a file and then computes the sum followed by the average.
* The computation shall be encapsulated in a function and then be called in the main routine
*/
#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */
double average_weight(int count, int weights_array[]);
int main(void)
{
int number_of_seals;
int weights_array[MAXSIZE];
printf("Enter the number of seals: \n");
scanf("%i", &number_of_seals);
printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));
return 0;
}
double average_weight(int count, int weights_array[])
{
/* Variable declaration and initialization
* Note the use of the FILE data type */
int weight;
int sum = 0;
FILE *elephant_seal_data = fopen("elephant_seal_data.txt", "r");
if (elephant_seal_data == NULL)
{
return -1;
}
/* FEOF function to determine if EOF has been reached or not */
while (!feof(elephant_seal_data))
{
fscanf(elephant_seal_data, "%i", &weight);
weights_array[count++] = weight;
sum += weight;
count++;
}
double average_weight = (double)sum / (double)count;
fclose(elephant_seal_data);
return average_weight;
}
printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));
The code passes a pointer to a position into the array for no apparent reason, and does not check if number_of_seals * 2 is less than MAXSIZE so may overflow the array. But the array isn't needed for this calculation anyway.
weights_array[count++] = weight;
sum += weight;
count++;
The code is writing to the array not reading it. The array is not needed for this calculation.
The code increments count twice, so the average will be out by a factor of two, and alternate locations in the array will have undefined values in them.
There are 2 stupid mistakes in your code, a nastier one, and a risk.
First the stupid ones:
You pass count to the function and increment that value twice per each value in the file. If the initialy given value was correct, you end with a count 3 times too big. You should not pass count to the function but compute it there.
You use a wrong syntax to pass an array: you are expected to pass a pointer to its first element.
Now the nasty one: while Why is “while ( !feof (file) )” always wrong? is indeed a FAQ, is is still a common thing in beginners code...
feof only returns true after a read operation returned an error. Let us examine what happens for the last value. It is read and correctly processed once. feof still returns false (no error so far) so your code re-enters the loop. scanf reaches the end of file and returns 0 (what your code ignores) but does not change the values => the last value will be processed twice. Never ever use while (!feof(...
And finally the risk.
You are summing value into an integer. Even if the average will easily fit there, if you had larger value and a very high number of them, you could get an integer overflow. The recommended way it to sum into a larger type (double?) and if possible use a guess to limit the cumulative error: average(qty-guess) + guess is indeed average(quantity), but the computed sum can be much lower, limiting the cumulative error when using floating point values or preventing overflow when using integer ones. From the number of seals and the expected average there should be no problem here so a guess is useless, but remember that for a different use case...
Last but not least, main is expected to be declared as int main() if you do not care for additional parameters but never int main(void)
Code could become:
/* The following program demonstrates the usage of fscan to read in a set of integer data into a file and then computes the sum followed by the average.
* The computation shall be encapsulated in a function and then be called in the main routine
*/
#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */
double average_weight(int* count, int weights_array[]);
int main()
{
int number_of_seals;
int weights_array[MAXSIZE];
double weight = average_weight(&number_of_seals, weights_array);
printf("Their number is %d and their average weight is %lf\n", number_of_seals, weight);
return 0;
}
double average_weight(int* count, int weights_array[])
{
/* Variable declaration and initialization
* Note the use of the FILE data type */
int weight;
int sum = 0;
FILE* elephant_seal_data = fopen("elephant_seal_data.txt", "r");
if (elephant_seal_data == NULL)
{
return -1;
}
*count = 0;
/* FEOF function to determine if EOF has been reached or not */
for(int i=0; i<MAXSIZE; i++) // never process more than the array size
{
if (1 != fscanf(elephant_seal_data, "%i", &weight)) {
break; // immediately stop at end of file
}
weights_array[(* count)++] = weight;
sum += weight;
}
double average_weight = (double)sum / (double)*count;
fclose(elephant_seal_data);
return average_weight;
}
I have kept your general program structure unchanged, but IMHO, you are expected to first read the data into an array, and then pass that populated array along with its count to an average function. Just split your current function into 2 steps.
You have sent the number of counts to use in the array which is great, since the function does not know the length of the weights_array. But you are not using it properly.
I'd suggest you to:
Use count to limit the number of loops based on how many data you want.
Do not change/reassign the value of count. Since this number is crucial to calculate the average. Create some other variable to do the task.
So here is how I slightly modified your code to bring those changes. I assumed the format of elephant_seal_data.txt as space separated integer values.
#include <stdio.h>
#define MAXSIZE 5000 /* Macro definition to pre-define the size of the array */
double average_weight(int count, int weights_array[]);
int main(void)
{
int number_of_seals;
int weights_array[MAXSIZE];
printf("Enter the number of seals: \n");
scanf("%i", &number_of_seals);
printf("Their average weight is %lf\n", average_weight(number_of_seals, &weights_array[number_of_seals]));
return 0;
}
double average_weight(int count, int weights_array[])
{
/* Variable declaration and initialization
* Note the use of the FILE data type */
int weight;
int sum = 0;
int i = 0;
FILE *elephant_seal_data = fopen("elephant_seal_data.txt", "r");
if (elephant_seal_data == NULL)
{
return -1;
}
/* FEOF function to determine if EOF has been reached or not */
while (i<count)
{
fscanf(elephant_seal_data, "%d", &weight);
weights_array[i++] = weight;
if (feof(elephant_seal_data)) break;
sum += weight;
}
double average_weight = (double)sum / (double)count;
fclose(elephant_seal_data);
return average_weight;
}
Edit:
I have used the elephant_seals_data.txt to simulate these in Google Colab for you. Try running the first cell there.
Google Colab Link

Having issues with printing an array in c

I'm having issues on printing an array, that's what I'm doing:
#include <stdio.h>
#define DIM 5
int main () {
double data[DIM] = {128.5, 131.4, 133.2, 127.1, 130.9};
printf("%lf", data[DIM]);
return 0;
}
The answer is always 0.000000.
I've also tried to put the values separately, like this:
#include <stdio.h>
#define DIM 5
int main () {
double data[DIM];
data[0]=128.5;
data[1]=131.4;
data[2]=133.2;
data[3]=127.1;
data[4]=130.9;
printf("%lf", data[DIM]);
return 0;
}
And still the answer is always 0.000000.
Could someone please help. Thank you in advance!
As 4386427 and 500 - Internal Server Error pointed out, there are two issues at work here.
You are trying to print an out-of-bounds index. When you make an array of length 5, indexes go from 0 to 4.
More importantly, there is no specific "print array" function that I am aware of. Your best bet is to create a loop that prints each element of the array.
void printDoubleArray(double arr[], int length)
{
printf("[");
if (length > 0)
{
printf("%f", arr[0]);
}
for (int i = 1; i < length; i++)
{
printf(", %f", arr[i]);
}
printf("]\n");
}
In this call
printf("%lf", data[DIM]);
you are trying to output a non-existent element of the array with the index DIM while the valid range of indices for the array is [0, DIM). This record means that 0 is included in the range as a valid index and DIM is excluded from the range.
As a result the call of printf invokes undefined behavior.
Also you should use the conversion specifier f instead of lf. The length modifier l does not have an effect used with the conversion specifier f. So it is just redundant.
You can not output a whole array except character arrays (by means of the conversion specifier s).
To output the whole array you need to use a loop as for example
for ( size_t i = 0; i < DIM; i++ )
{
printf( "%.1f ", data[i] );
}
putchar( '\n' );
Here is a demonstrative program.
#include <stdio.h>
#define DIM 5
int main(void)
{
double data[DIM] = { 128.5, 131.4, 133.2, 127.1, 130.9 };
for ( size_t i = 0; i < DIM; i++ )
{
printf( "%.1f ", data[i] );
}
putchar( '\n' );
return 0;
}
The program output is
128.5 131.4 133.2 127.1 130.9
C, the language itself, does not have array bounds checking. You want the element one past the end? sure thing. You want the element a million past the end? sure you can ask for that too (who knows what will happen but you can ask for it)
If your compiler supports it, you can get more robust error reporting. Not C standard but helpful nonetheless.
GCC:
Compile with -fsanitize=address and at run-time the sanitizer will catch this overrun:
=======================
==220715==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffed8db4988 at pc 0x559ba54babcc bp 0x7ffed8db4920 sp 0x7ffed8db4910
READ of size 8 at 0x7ffed8db4988 thread T0
#0 0x559ba54babcb in main /tmp/overrun.c:9
clang:
In addition to the run-time sanitizer (-fsanitize=address), Clang can also point out your problem at compile time:
printf("%lf", data[DIM]);
^ ~~~
overrun.c:7:5: note: array 'data' declared here
double data[DIM] = {128.5, 131.4, 133.2, 127.1, 130.9};
^
1 warning generated.

Decimal integer to binary in C

Please give me some feedback on how to make my code better or more efficient. It should convert a decimal integer to binary.
#include <stdio.h>
binarydigits(int div, int dis)
{
int numit;
numit=0;
do
{
++numit;
div /= dis;
}
while (div!=1);
++numit;
return numit;
}
main()
{
int x, nb, i;
printf("\n Input an decimal integer number to be converted: ");
scanf("%d", &x);
fflush(stdin);
if (x==0 || x==1)
{
printf("\n\n %d in binary : %d", x, x);
}
else
{
printf("\n\n %d in binary : ", x);
nb = binarydigits(x, 2);
// the function 'binarydigits' returns how many binary digits are needed to represent 'x'
int remind[nb];
// an array of 'nb' elements is declared. Each element of this array will hold a binary digit
for(i=(nb-1) ; i>=0 ; --i, x/=2)
{
remind[i] = x%2;
}
//this 'for' structure saves the remainder of 'x/2' (x%2) in an element of the 'remind[nb]' array
for (i=nb ; i>0 ; --i)
{
printf("%d", remind[nb-i]);
}
//this 'for' structure prints the elements of the 'remind[nb]' array in increasing order
}
getch();
return 0;
}
Any tips on how to make this better would be nice.
Firstly, binarydigits should have a return type int. This is because you return an integer variable numit at the end of this function. Change your function header to:
int binarydigits(int div, int dis)
Secondly, the main() function needs to have a return type int by definition in C, and C++ for that matter. Without it, your compiler will produce a warning, something similar to:
main.c:18:1: warning: return type defaults to 'int' [-Wimplicit-int]
main()
^~~~
Here is a snippet from the the C11 standard (ISO/IEC 9899:2011) on the definition of the main() function:
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters: - Return Type of main()
int main(void) { /* ... */ }
Thirdly, you should remove fflush(stdin) because using the fflush() for stdint is undefined behavior as it is not a part of standard C. From C11 7.21.5.2, fflush works only with output/update stream, not input stream:
If stream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined. - fflush(stdin)
How to make my code better or more efficient?
My advice to you is to stop trying to learn C by trial-and-error method. You should obtain a good book and study it first. It is impossible to create a fast and efficient C program without mastering pointers, bitwise operators and memory manipulations.
Simply, to make your code fast, you should completelly delete your code (I am not going to list all of your bad-practice things here) and start understanding my example:
int main(void){
char *s = (char*)malloc(33);
char *t = s;
int a;
s += 33;
*s = 0;
printf("Enter a number: ");
scanf("%d", &a);
printf("That number in binary: ");
while(a){
*(--s) = a & 1 ? '1' : '0';
a >>= 1;
}
printf("%s\n", s);
free(t);
return 0;
}
Explanation: we have pointer (if you don't know pointers, well you should probably first learn them) s which points to the end of a string. While number from input (number a) is nonzero, we put its last binary digit in the string, decrease pointer and divide a integrally by 2 (this is a >>= 1 instruction). When a is 0, just print the string.

For Loop condition

#include <stdio.h>
#define all_mem (sizeof(x) /sizeof(x[0]))
int x[] ={1,2,3,4,5,6,7,8,9,10};
int main(void) {
// printf("The condition is %d",(all_mem-2));
int i;
for(i=-1;i<=(all_mem-2);i++)
{
printf("The number is %d",i);
}
return 0;
}
In the above code for loop is not even executing for a single time, i tried printing condition and its satisfies for loop condition. Any insights how macro expression in for loop condition is evaluated to the value less than -1?
The all_mem macro is returning a size_t value; integer promotion rules mean the comparison of i <= (all_mem - 2) is promoting i to a size_t, which means the value is huge, rather than -1. Try casting to ensure signed comparison:
for(i = -1; i <=(ssize_t)(all_mem- 2); ++i)
after making a few corrections to the code, forinstance, sizeof() returns a size_t, not an int the code worked perfectly.
Here is the modified code:
#include <stdio.h>
#define all_mem (sizeof(x) /sizeof(x[0]))
int x[] ={1,2,3,4,5,6,7,8,9,10};
int main(void)
{
printf( "all_mem = %ld\n", all_mem ); // << added for debugging
// printf("The condition is %d",(all_mem-2));
int i;
for(i=-1;i<=(int)(all_mem-2);i++) // <<
// << properly cast to int
// otherwise compiler raises warning and unsigned comparison made
{
printf("The number is %d\n",i);
}
return 0;
}
Here is the output from the above code:
all_mem = 10
The number is -1
The number is 0
The number is 1
The number is 2
The number is 3
The number is 4
The number is 5
The number is 6
The number is 7
The number is 8
When compiling, always enable all the warnings, then fix those warnings.
If the above statement had been followed, then you would have seen the problem, without our help.
(for gcc, at a minimum use: -Wall -Wextra -pedantic and I also add: -Wconversion -std=c99)

error: expected expression before ‘float’

I would like to find all the primes within 100. Here is my codes.
// Find all the prime number within 100.
#include<stdio.h>
#include<math.h>
#include<stdbool.h>
int main() {
int i,n;
int j = 0;
for ( n = 2; n <= 100; ++n) {
bool isPrime = true;
for (i = 2; i <= sqrt(float(n)); ++i) {
if(n % i == 0) {
isPrime = false;
break;
}
}
if(isPrime) {
++j;
printf("%d is a prime number\n",n);
}
}
printf("The total number of prime number within 100 is %d\n",j);
return 0;
}
When compile it, there is one error.
prime.c:14:8: error: expected expression before ‘float’
m = float(n);
^
Could anyone help solve this problem? Thanks.
You're using the wrong syntax when casting (you're using one of C++'s many styles of casting, but for C there is only one way). Change:
sqrt(float(n))
to
sqrt((float)n)
Note however that sqrt takes a double, so strictly speaking this should be:
sqrt((double)n)
Note also that the cast is not necessary, and you can just write:
sqrt(n)
Change this
sqrt(float(n))
to this
sqrt((float)n)
You want to cast n to float.
You should use this function:
float sqrtf (float x);
which in C99 receives a float as an argument. Otherwise, it would be better to cast into double (if you use sqrt()).
sqrt-ref
What you have written:
float(n)
is like saying that float is a name of a function and you pass to it the parameter n.
Notice, that in your case, you don't need casting, since it's going to be performed automatically (to float if you use sqrtf() or to double if you use sqrt()).
Other notes, irrelevant with your syntax error.
Why not start the loop from 3 and increase the counter by two? If you think about it, this will faster and will produce the same results. If you want to test yourself, check my example here.
Also, what I had found pretty exciting when I was searching for primes, is the sieve of Eratosthene's (Κόσκινο του Ερατοσθένη) . Here is an example of it.
If you want to cast n to a float, use (float)n.
Just do:
sqrt(n);
You'll be having the exam same result as the casting for your case.

Resources