Inaccuracy when using pow() function - c

I made a program that splits a number into numbers that, when added, give the first number. For example, 1234 should be split into 1000, 200, 30, and 4.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main ()
{
int i, num1, num2;
char tmp[6]; // the number will be stored here as string
int num3 = 12345; //the number
sprintf(tmp, "%d", num3); //convert to string
for(i = 0; i < strlen(tmp); i++) //check every digit
{
num1 = pow(10, strlen(tmp) - 1 - i); //every number will be multiplied by 10
//to the power of number of digits - 1 - counter
num2 = tmp[i] - '0'; //convert character to int
printf("%d\n", num1*num2); //print the number
}
return 0;
}
This is the output:
9999
2000
297
40
5
As you can see this is not correct, why?

The problem is that floating point calculations may have small errors. Which is to say that the results of the pow function may be slightly larger or slightly smaller than expected. When you convert to an int, the result is truncated. For example, if pow(10,4) returns 9999.999999, then converting to an int yields 9999, which is not what you expected. On the other hand, if pow(10,3) returns 1000.000001 then converting to an int will give the expected result.
Here's some code that should demonstrate the problem (on computers where the results of the pow function are not exact):
int main( void )
{
for ( int i = 0; i < 5; i++ )
{
double num1 = pow(10,i);
int num2 = num1;
printf( "%12f --> %5d\n", num1, num2 );
}
}
To avoid the problem, you either need to round the results of pow, or avoid floating point math altogether. Here's some code that shows how to solve the problem using only integer math.
int main( void )
{
char temp[] = "12345";
int length = strlen( temp );
int multiplier = 1;
for ( int i = 1; i < length; i++ )
multiplier *= 10;
for ( int i = 0; i < length; i++ ) {
printf( "%d\n", (temp[i] - '0') * multiplier );
multiplier /= 10;
}
}

Related

storing digits of a number in array

How do I store different digits of an integer in any array
like 1234 to {1,2,3,4}
It can be done using char str[]="1234"; printf("%c",str[0];
but how to do it without using string and in integer itself
Here's a snippet that creates an array of digits and prints them out:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
// Print digits 1 by 1
void numToDigits (int number, int base) {
int i;
int n_digits = (int)ceil(log(number+1) / log(base));
printf("%d digits\n", n_digits);
int * digits = calloc(n_digits, sizeof(int));
for (i=0; i<n_digits; ++i) {
digits[i] = number % base;
number /= base;
}
// digits[0] is the 1's place, so print them starting from the largest index
for (i=n_digits-1; i>=0; --i) {
printf("%d", digits[i]);
}
printf("\n");
free(digits);
}
You'll likely want to modify this, but I think it exposes all the important ideas. Don't forget to add -lm when you compile to include math libraries needed for log and ceil. Also note that the printing code isn't made to work with bases larger than 10.
Here's one method, more or less:
get the log10() of the integer to determine its 'size'
take the floor() of that to get exponent (number of digits - 1)
then calculate the highest divider with (int)pow(10, exponent)
finally have a for-loop:
int value = 1234; // Your value to split up in digits.
for (int d = divider; divider > 0; divider /= 10)
{
int digit = value / d;
value = value / 10;
// Store digit in array
}
I leave the details for you to fill in.
Carson had a similar idea which nicely avoids the use of pow()
If your compiler supports variable length arrays then you can use the approach shown in the demonstration program below
#include <stdio.h>
enum { Base = 10 };
size_t size( unsigned int x )
{
size_t n = 0;
do { ++n; } while ( x /= Base );
return n;
}
int main( void )
{
unsigned int x = 0;
printf( "Enter a non-negative number: " );
scanf( "%u", &x );
size_t n = size( x );
unsigned int digits[n];
for ( size_t i = n; i != 0; x /= Base )
{
digits[--i] = x % Base;
}
for ( size_t i = 0; i < n; i++ )
{
printf( "%u", digits[i] );
}
putchar( '\n' );
}
The program output might look like
Enter a non-negative number: 123456789
123456789
If the compiler does not support variable length arrays then you will need to allocate the array dynamically as for example
unsigned int *digits = malloc( n * sizeof( unsigned int ) );
You don't need to calculate how many digits are in a given integer n at runtime. You can check your compiler's <limits.h> for the maximum number of digits an int can hold.
int n = 124343;
int digits[10]; // INT_MAX is 10-digit long on x86 and x64 (GCC and Clang)
int ndigits;
Another solution is to pre-compute (#chux) the maximum number of digits using macros:
#define INT_DIGIT10_WIDTH ((sizeof(int)*CHAR_BIT - 1)/3 + 1)
int digits[INT_DIGIT10_WIDTH];
The rest is simple:
// Digits are stored in reverse order
for (ndigits = 0; n; n /= 10)
digits[ndigits++] = n % 10;
for (int i = ndigits - 1; i > 0; --i)
printf("%d\t", digits[i]);
If you want to store them in-order:
// Digits are stored in reverse order
for (ndigits = 0; n; n /= 10)
digits[ndigits++] = n % 10;
// Reverse digits by swapping every two parallel elements
for (int i = 0, j = ndigits-1; i < j; ++i, --j) {
int tmp = digits[i];
digits[i] = digits[j];
digits[j] = tmp;
}
for (int i = 0; i < ndigits; ++i)
printf("%d\t", digits[i]);
I was writing my response when the first answer showed up. This will work just fine. The loop in the middle basically isolates each digit by removing all the ones in front of it and then dividing it down to the ones place before adding it to the array.

Implement a reverse function to reverse an integer but the output here is always 0

I do not understand why the return .... does not work. Somehow, Output is always 0. Here the return call to atoi always outputs 0.
#include <stdio.h> //INCLUDES
#include <stdlib.h>
int reverse (int x); //Func Decls
int
main ()
{
printf ("%d", reverse (123)); //123=321, -123=-321, 120=21, 0=0
return 0;
}
int
reverse (int x)
{
int i, rem = 0;
char arr[15];
while (x % 10 != 0)
{
rem = x % 10;
arr[i] = ((char)rem);
x /= 10;
i++;
}
return atoi(arr); //OUTPUT = 0, does not return actual output
}
You don't need an array nor atoi function for this task, and the logic of while loop is not correct. A correct and simple one could be something like that (provided that no integer overflow occurs):
#include <stdio.h>
int reverse (int x)
{
int r = 0;
while (x != 0) {
r = 10 * r + x % 10;
x /= 10;
}
return r;
}
int main (void)
{
printf("%d\n", reverse(1234));
return 0;
}
The problem is the usage of atoi() function. The atoi() function basically converts a string with numeric characters codified in ASCII to an integer.
If you look the ASCII table, the numbers 1, 2 and 3 codify the characters '^A', '^B' and '^C', respectively. This means that, after the while loop in reverse() function, the string passed as argument to atoi() is not a numeric string, so zero is returned as an error. Also, the characters '1', '2' and '3' are codified as numbers 49, 50 and 51, respectively.
Now, I suggest you to change your entire implementation, because it does not make sense to receive an integer as input to operate with and, during the operation, convert it to string to return an integer again using atoi(). So, forget strings, ASCII, and atoi().
Lets start creating a loop to operate with each digit of the number, using the module operator, as you did.
int reverse (int x) {
int result = 0;
while ( x != 0 ) {
result = x%10;
}
return result;
}
Then, to insert another digit to the result, do the opposite: multiply it by 10.
int reverse (int x) {
int result = 0;
while ( x != 0 ) {
result = result*10 + x%10;
}
return result;
}
Now, cut the target digit out of the x, dividing it by ten.
int reverse (int x) {
int result = 0;
while ( x != 0 ) {
result = result*10 + x%10;
x /= 10;
}
return result;
}
Finally, the entire code.
#include <stdio.h>
#include <stdlib.h>
int reverse (int x);
int main () {
printf ("%d\n", reverse(123));
printf ("%d\n", reverse(-123));
printf ("%d\n", reverse(120));
printf ("%d\n", reverse(0));
return 0;
}
int reverse (int x) {
int result = 0;
while ( x != 0 ) {
result = result*10 + x%10;
x /= 10;
}
return result;
}
And the result, as expected:
$ gcc -Wall -std=c99 -o program program.c
$ ./program
321
-321
21
0
$
Based on your code, you can fix your code a little bit to make it works. Below is my opinion:
#include <stdio.h> //INCLUDES
#include <stdlib.h>
int reverse (int x); //Func Decls
int main () {
printf ("%d", reverse (123)); //123=321, -123=-321, 120=21, 0=0
return 0;
}
int reverse (int x) {
int i, rem = 0;
int arr[15];
while (x != 0)
{
rem = x % 10;
arr[i] = rem;
x /= 10;
i++;
}
int result = 0;
for (int j = 0; j < i; j++) {
result = 10 * result + arr[j];
}
return result;
}
regarding:
int i, rem = 0;
and
arr[i] = ((char)rem);
the local variable i in not initialized!. on my system the result is a seg fault event.

Program doesn't output anything using a dynamic array

I just started with C and I am trying to create a program which takes a number and converts it to binary using this method (from indepth.dev):
To convert integer to binary, start with the integer in question and divide it by 2 keeping notice of the quotient and the remainder. Continue dividing the quotient by 2 until you get a quotient of zero. Then just write out the remainders in the reverse order.
(...)
Now, we simply need to write out the remainder in the reverse order —1100. So, 12 in decimal system is represented as 1100 in binary.
I am trying to make the array dynamic in size. Coming from Python this is a bit confusing, because in Python you can just append to a list.
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int *ptr, n, i;
ptr = (int*)malloc(1 * sizeof(int));
printf("Enter a number to convert: ");
scanf("%d", &n);
for (i = 0; n>0; i++)
{
ptr = realloc(ptr, i * sizeof(int));
ptr[i] = n % 2;
n = n/2;
}
for(i=i-1; i>= 0; i--)
{
printf("%d", ptr[i]);
}
free(ptr);
return 0;
}
When I run the program and enter a number it doesn't output anything. If I do the same with a fixed array size it works. Why is this happening?
The problem lies in these few lines:
for (i = 0; n>0; i++)
{
ptr = realloc(ptr, i * sizeof(int));
ptr[i] = n % 2;
n = n/2;
}
You are reallocating an array capable of holding i integers each time, however you end up writing at index i. An array holding i integers has indexes from 0 to i - 1, and you are therefore writing past the end of the array. This results in undefined behavior.
The easiest fix for this is to just start with i = 1 and write to ptr[i - 1]:
for (i = 1; n > 0; i++)
{
ptr = realloc(ptr, i * sizeof(int));
ptr[i - 1] = n % 2;
n = n/2;
}
A simpler approach would be to use a fixed size array. You already know that an int is 8*sizeof(int) bits long, so that's the maximum you'll need. Also, you probably don't need to work with signed integers since those can cause problems with negative values (therefore you can use unsigned).
EDIT: I am saying 8 * sizeof(int) because the sizeof operator returns the size of the type (in this case int) in bytes. A byte is 8 bits, so I multiply that by 8 to get the size in bits. I said 8 here, but using CHAR_BIT (from limits.h) would be better, because a "byte" in C could be expressed using more than 8 bits and in that case CHAR_BIT holds the right number of bits per byte. I'm not aware of any C implementation that has a value different than 8 for CHAR_BIT, but it's nonetheless the correct way to go. I updated the code below to use CHAR_BIT instead of 8.
#include <stdio.h>
#include <limits.h>
#define N_BITS CHAR_BIT * sizeof(unsigned)
int main(void) {
unsigned digits[N_BITS] = {0}; // Start with an array filled with zeroes.
unsigned n;
int i;
printf("Enter a number to convert: ");
scanf("%u", &n);
// Calculate binary digits.
for (i = 0; n > 0; i++) {
digits[i] = n % 2;
n /= 2;
}
// Skip leading zeroes.
while (digits[i] == 0)
i--;
// Print binary digits in reverse order.
for(; i >= 0; i--)
printf("%u", digits[i]);
// Final newline.
putchar('\n');
return 0;
}
Bonus:
#include <stdio.h>
int main(void) {
int i = 8 * sizeof(unsigned);
unsigned n;
printf("Enter a number to convert: ");
scanf("%u", &n);
while (i--)
putchar('0' + ((n >> i) & 1));
putchar('\n');
return 0;
}
You allocated not enough memory. If sizeof( int ) is equal to 4 then the number of binary digits can be equal to 32 ( sizeof( int ) * CHAR_BIT).
And there is no need to use realloc.
Moreover this statement
ptr = realloc(ptr, i * sizeof(int));
allocates memory of zero size when i in the loop is equal to 0. You may not write to such a memory.
Also you should use an object of the type unsigned int.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(void)
{
unsigned int Base = 2;
int *ptr = malloc( CHAR_BIT * sizeof( unsigned int ) );
printf( "Enter a number to convert: " );
unsigned int x = 0;
scanf( "%u", &x );
size_t n = 0;
do
{
ptr[n++] = x % Base;
} while ( x /= Base );
while ( n-- )
{
printf( "%u", ptr[n] );
}
putchar( '\n' );
free( ptr );
return 0;
}
Its output might look like
Enter a number to convert: 12
1100
If you want to use realloc then the code can look like
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main(void)
{
unsigned int Base = 2;
int *ptr = NULL;
printf( "Enter a number to convert: " );
unsigned int x = 0;
scanf( "%u", &x );
size_t n = 0;
do
{
ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
ptr[n++] = x % Base;
} while ( x /= Base );
while ( n-- )
{
printf( "%u", ptr[n] );
}
putchar( '\n' );
free( ptr );
return 0;
}
In general such a call
ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
is unsafe because the function can return NULL. So in general you should use an intermediate variable like
unsigned int *tmp = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
if ( tmp ) ptr = tmp;

A program that calculate the factorial of big number

It's a test in a website, here is the code
#include <stdio.h>
void Print_Factorial ( const int N );
int main()
{
int N;
scanf("%d",&N);
Print_Factorial(N--);
return 0;
}
/* your code will be put in here*/
#include <math.h>
int getFactLength(int N){
double length = 0;
while(N){
length += log10(N--);
}
return (int)length+1;
}
void printFact(int fact[], int length){
while(length--){
printf("%d",*fact++);
}
}
void initialNums(int nums[], int length, int num){
while(length--){
*nums++ = num;
}
}
void Print_Factorial( const int N ){
if(N < 0){
printf("Invalid input");
return ;
}
int NT = N;
if(NT>=0 && NT<15){
int fact = 1;
while(NT){
fact *= NT--;
}
printf("%d",fact);
return ;
}
int length = getFactLength(N);
int fact[length];
initialNums(fact, length, 0);
fact[length-1] = 1;
int lastNoneZeroIndex = length-1;
while(NT > 1){
int lengthT = length;
int carry = 0;
while(lengthT-- > lastNoneZeroIndex){
int result = NT*fact[lengthT] + carry;
fact[lengthT] = result % 10;
carry = result / 10;
}
while(carry){
fact[--lastNoneZeroIndex] = carry % 10;
carry /= 10;
}
NT--;
}
printFact(fact, length);
}
I use values from 0 to 20 to test it, all of them are right. But when I submit it in that website, a test case always do not pass. I don't know what that case is. But, there are 5 cases, all test cases are between 0 and 1000, and two of them are no more than 15, one of them is negative, one of them use most time to pass, so I think the case that didnt pass is a number that smaller than 1000. That's all I know, I can't imagine that 1000 was passed, but the number smaller than 1000 didn't pass. I don't know what is wrong with my lovely code. I hope you can watch my code, and find some bugs.
There create a overflow in the fact variable, here you use int type for fact variable.
For input 13,14, it gives wrong answer.
Solution:
long long int fact = 1;
or,
change the condition- if(NT>=0 && NT<13)

convert an integer number into an array

I am trying to convert an integer number in C into an array containing each of that number's digits
i.e. if I have
int number = 5400
how can I get to
int numberArray[4]
where
numberArray[0] = 0;
numberArray[1] = 0;
numberArray[2] = 4;
numberArray[3] = 5;
Any suggestions gratefully received.
This would work for numbers >= 0
#include <math.h>
char * convertNumberIntoArray(unsigned int number) {
int length = (int)floor(log10((float)number)) + 1;
char * arr = new char[length];
int i = 0;
do {
arr[i] = number % 10;
number /= 10;
i++;
} while (number != 0);
return arr;
}
EDIT: Just a little bit more C style but more cryptic.
#include <math.h>
char * convertNumberIntoArray(unsigned int number) {
unsigned int length = (int)(log10((float)number)) + 1;
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}
Hint: Take a look at this earlier question "Sum of digits in C#". It explains how to extract the digits in the number using several methods, some relevant in C.
From Greg Hewgill's answer:
/* count number of digits */
int c = 0; /* digit position */
int n = number;
while (n != 0)
{
n /= 10;
c++;
}
int numberArray[c];
c = 0;
n = number;
/* extract each digit */
while (n != 0)
{
numberArray[c] = n % 10;
n /= 10;
c++;
}
You could calculate the number of digits in an integer with logarithm rather than a loop. Thus,
int * toArray(int number)
{
int n = log10(number) + 1;
int i;
int *numberArray = calloc(n, sizeof(int));
for ( i = 0; i < n; ++i, number /= 10 )
{
numberArray[i] = number % 10;
}
return numberArray;
}
Try this,
void initialise_array(int *a, int size, int num) {
for (int i = 0; i < size; ++i, num /= 10)
a[(size - 1) - i] = num % 10;
}
If you need to take negative numbers into account, you might need some extra logic. In fact, when playing around with arrays you don't know the size of upfront, you may want to do some more safety checking, and adding an API for handling the structure of the data is quite handy too.
// returns the number of digits converted
// stores the digits in reverse order (smalles digit first)
// precondition: outputdigits is big enough to store all digits.
//
int convert( int number, int* outputdigits, int* signdigit ) {
int* workingdigits = outputdigits;
int sign = 1;
if( number < 0 ) { *signdigit = -1; number *= -1; }
++workingdigits;
for ( ; number > 0; ++ workingdigits ) {
*workingdigits = number % 10;
number = number / 10;
}
return workingdigits - outputdigits;
}
void printdigits( int* digits, int size, int signdigit ) {
if( signdigit < 0 ) printf( "-" );
for( int* digit = digits+size-1; digit >= digits; --digit ){
printf( "%d", *digit );
}
}
int main() {
int digits[10];
int signdigit;
printdigits( digits, convert( 10, digits, &signdigit ), signdigit );
printdigits( digits, convert( -10, digits, &signdigit ), signdigit );
printdigits( digits, convert( 1005, digits, &signdigit ), signdigit );
}
#include <stdio.h>
#include <string.h>
int main(void)
{
int i, inputNumber;
char* charArray;
printf("\nEnter number: ");
scanf("%d", &inputNumber);
/* converts int to print buffer which is char array */
sprintf(charArray, "%d", inputNumber);
int size = strlen(charArray);
int intArray[size];
for (i = 0; i < size; i++)
{
intArray[i] = charArray[i] - '0';
}
return 0;
}
C code:
/* one decimal digit takes a few more than 3 bits. (2^3=8, 2^4=16) */
int digits[(sizeof (int) * CHAR_BIT) / 3 + 1],
*digitsp = digits;
do {
*digitsp++ = number % 10;
number /= 10;
} while(number > 0);
You will see how many digits you converted by taking the difference
digitsp - digits
If you want to put it into a function:
#define MIN_DIGITS_IN_INT ((sizeof (int) * CHAR_BIT) / 3 + 1)
int to_array(int number, int *digits) {
int *digitsp = digits;
do {
*digitsp++ = number % 10;
number /= 10;
} while(number > 0);
return digitsp - digits;
}
int main() {
int number = rand();
int digits[MIN_DIGITS_IN_INT];
int n = to_array(number, digits);
/* test whether we're right */
while(n-- > 0)
printf("%d", digits[n]);
}
printf(" = %d\n", number);
}
I prefer automatic arrays to dynamic memory allocation in this case, since it's easier to do it right and not leak accidentally.
using vadim's code, I came up with this test program:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
char * convertNumberIntoArray(unsigned int number) {
unsigned int length = (int)(log10((float)number)) + 1;
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}
int main(void)
{
int InputNumber;
int arr[5];
printf("enter number: \n");
scanf("%d", &InputNumber);
convertNumberIntoArray(InputNumber);
printf("The number components are: %d %d %d\n", arr[0],arr[1],arr[2]);
system("PAUSE");
return 0;
}
but the output is garbage. Can anyone advise if I have done something stupid here?
/***** output *****/
enter number:
501
The number components are: 2009291924 2009145456 -1
Press any key to continue . . .
--dave

Resources