I basically want to convert a given int number and store individual digits in an array for further processing.
I know I can use % and get each digit and store it. But the thing is if I do not know the number of digits of the int till runtime and hence I cannot allocate the size of the array. So, I cannot work backwards (from the units place).
I also do not want to first store the number backwords in an array and then again reverse the array.
Is there any other way of getting about doing this?
Eg: int num = 12345;
OUTPUT: ar[0] = 1, ar[1] = 2 and so on, where ar[] is an int array.
Convert is probably not the right word. You can take the int, dynamically allocate a new int[], and then store the digits of the int into the int[]. I'm using log base 10 to calculate how many digits num has. Include math.h to use it. The following code is untested, but will give you an idea of what to do.
int num = 12345;
int size = (int)(log10(num)+1);
// allocate array
int *digits = (int*)malloc(sizeof(int) * size);
// get digits
for(int i=size-1; i>=0; --i) {
digits[i] = num%10;
num=num/10; // integer division
}
The easiest way is to calculate number of digits to know the size of an array you need
int input = <input number>; // >= 0
int d, numdigits = 1;
int *arr;
d = input;
while (d /= 10)
numdigits++;
arr = malloc(sizeof(int) * numdigits);
There's even easier way: probably you pass a number to your program as an argument from command line. In this case you receive it as a string in argp[N], so you can just call strlen(argp[N]) to determine number of digits in your number.
If you have a 32-bit integer type, the maximum value will be comprised of 10 digits at the most (excluding the sign for negative numbers). That could be your upper limit.
If you need to dynamically determine the minimum sufficient size, you can determine that with normal comparisons (since calling a logarithmic function is probably more expensive, but a possibility):
size = 10;
if (myint < 1000000000) size--;
if (myint < 100000000) size--;
/* ... */
Declaring the array to be of a dynamic size depends on the C language standard you are using. In C89 dynamic array sizes (based on values calculated during run-time) is not possible. You may need to use dynamically allocated memory.
HTH,
Johan
The following complete program shows one way to do this. It uses unsigned integers so as to not have to worry about converting - you didn't state what should happen for negative numbers so, like any good consultant, I made the problem disappear for my own convenience :-)
It basically works out the required size of an array and allocates it. The array itself has one element at the start specifying how many elements are in the array (a length int).
Each subsequent element is a digit in sequence. The main code below shows how to process it.
If it can't create the array, it'll just give you back NULL - you should also remember to free the memory passed back once you're done with it.
#include <stdio.h>
#include <stdlib.h>
int *convert (unsigned int num) {
unsigned int *ptr;
unsigned int digits = 0;
unsigned int temp = num;
// Figure out how many digits in the number.
if (temp == 0) {
digits = 1;
} else {
while (temp > 0) {
temp /= 10;
digits++;
}
}
// Allocate enough memory for length and digits.
ptr = malloc ((digits + 1) * sizeof (unsigned int));
// Populate array if we got one.
if (ptr != NULL) {
ptr[0] = digits;
for (temp = 0; temp < digits; temp++) {
ptr[digits - temp] = num % 10;
num /= 10;
}
}
return ptr;
}
That convert function above is the "meat" - it allocates an integer array to place the length (index 0) and digits (indexes 1 through N where N is the number of digits). The following was the test program I used.
int main (void) {
int i;
unsigned int num = 12345;
unsigned int *arr = convert (num);
if (arr == NULL) {
printf ("No memory\n");
} else {
// Length is index 0, rest are digits.
for (i = 1; i <= arr[0]; i++)
printf ("arr[%d] = %u\n", i, arr[i]);
free (arr);
}
return 0;
}
The output of this is:
arr[1] = 1
arr[2] = 2
arr[3] = 3
arr[4] = 4
arr[5] = 5
You can find out the number of digits by taking the base-10 logarithm and adding one. For that, you could use the log10 or log10f functions from the standard math library. This may be a bit slower, but it's probably the most exact as long as double has enough bits to exactly represent your number:
int numdigits = 1 + log10(num);
Alternatively, you could repeatedly divide by ten until the result is zero and count the digits that way.
Still another option is just to allocate enough room for the maximum number of digits the type can have. For a 32-bit integer, that'd be 10; for 64-bit, 20 should be enough. You can just zero the extra digits. Since that's not a lot of wasted space even in the worst case, it might be the simplest and fastest option. You'd have to know how many bits are in an int in your setup, though.
You can also estimate fairly well by allocating 3 digits for each 10 bits used, plus one. That should be enough digits unless the number of bits is ridiculously large (way above the number of digits any of the usual int types could have).
int numdigits = 1
unsigned int n = num;
for (n = num; n & 0x03ff; n >>= 10)
numdigits += 3;
/* numdigits is at least the needed number of digits, maybe up to 3 more */
This last one won't work (directly) if the number is negative.
What you basically want to do is to transform your integer to an array of its decimal positions. The printf family of functions perfectly knows how to do this, no need to reinvent the wheel. I am changing the assignment a bit since you didn't say anything about signs, and it simply makes more sense for unsigned values.
unsigned* res = 0;
size_t len = 0;
{
/* temporary array, large enough to hold the representation of any unsigned */
char positions[20] = { 0 };
sprintf(position, "%u", number);
len = strlen(position);
res = malloc(sizeof(unsigned[len]));
for (size_t i = 0; i < len; ++i)
res[i] = position[i] - '0';
}
Related
I have a function named num_to_binary, which is used to convert a decimal number stored in the form of array. The prototype for this function num_to_binary is as below:
void num_to_binary(int *number_b, int size_of_number);
Here:
number_b is pointer to array which stores my number. For example, if I would like to convert the number 12345 to binary, then I will be storing 12345 in number_b as follows:
number_b[0] = 1
number_b[1] = 2
number_b[2] = 3
number_b[3] = 4
number_b[4] = 5
Also, size_of_number is the number of digits in the number (or it is the number of elements in the array number_b). So for the number 12345, size_of_number has the value 5.
Below is the full declaration of the function num_to_binary:
void num_to_binary(int *number_b, int size_of_number)
{
int *tmp_pointer = malloc(1 * sizeof(int));
int curr_size = 1;
int i = 0;
while(!is_zero(number_b,size_of_number))
{
if(i != 0)
{
curr_size += 1;
tmp_pointer = realloc(tmp_pointer, curr_size * sizeof(int));
}
if(number_b[size_of_number - 1] % 2 == 1)
{
tmp_pointer[i] = 1;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
else
{
tmp_pointer[i] = 0;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
}
int *fin_ans;
fin_ans = malloc(curr_size * sizeof(int));
for(int j = 0 ; j < curr_size; j++)
{
fin_ans[curr_size-1-j] = tmp_pointer[j];
}
}
In the above function:
tmp_pointer: It is initially allocated some memory using malloc(), and is used to store the reverse of the binary representation of the number stored in number_b
curr_size: It stores the current size of tmp_pointer. It is initially set to 1.
i: It is used to keep track of the while loop. It is also used to reallocation purpose, which I have explained a bit later.
is_zero(number_b, size_of_number): It is a function, which returns 1 if the number stored in number_b is 0, else it returns 1.
divide_by_2(number_b, size_of_number): It divides the number stored in number_b by 2. It does NOT change the size of the array number_b.
fin_ans: It is an integer pointer. Since the binary representation stored in the array tmp_pointer will be the reverse of the actual binary representation of the number, so fin_ans will store the correct binary representation of number by reversing the content of tmp_pointer.
Below is the how this function works :
First of all, tmp_pointer is allocated a memory equal to the
size of 1 int. So, now tmp_pointer can store an integer.
We now go into the while loop. The loop will terminate only
when the number stored in number_b equals 0.
Now, we check if i is equal to 0 or not. If it is not equal to
zero, then this means than the loops has been run atleast once, and
in order to store the next binary digit, we resize the memory
allocated to tmp_pointer so that it can store the next bit.
If the last digit of the number is odd, then that implies that the
corresponding binary digit will be 1, else it will be 0. The
if and else condition do this task. They also increment
i each time one of them is executed, and also divide the number by 2.
Now, we are out of the loop. It's time to reverse the binary number
stored in tmp_pointer to get the final answer.
For this, we create a new pointer called fin_ans, and allocate
it the memory which will be used for storing the correct binary
representation of the number.
The last for loop is used to reverse the binary representation
and store the correct binary representation in fin_ans.
The problem:
The code runs for small numbers such as 123, but for large numbers such as 1234567891, it gives a segmentation fault error. This can be checked by trying to print the digits stored in fin_ans.
I tried using GDB Debugger, and got to know that the reason for Segmentation Fault lies in the while loop. I am sure that the functions divide_by_2 and is_zero are not the reason for Segmentation Fault, since I have tested them thoroughly.
I also used DrMemory, which indicated that I am trying to access (read or write) a memory location which has not been allocated. Unfortunately, I am not able to figure out where the error lies.
I suspect realloc() to be the cause of Segmentation Fault, but I am not sure.
Apologies for such a long question, however, I would highly appreciate any help provided to me for this code.
Thanks in advance for helping me out !
There are multiple problems in the code:
you do not check for memory allocation failure
you forget to free tmp_pointer before leaving the function.
you allocate a new array fin_ans to reserve the array tmp_pointer and perform the reverse operation but you do not return this array to the caller, nor do you have a way to return its size. You should change the prototype to return this information.
if the number of zero, the converted number should probably have 1 digit initialized as 0, but you use malloc which does not initialize the array it allocates so tmp_pointer[0] is uninitialized.
you did not provide the code for is_zero() nor divide_by_two(). It is possible that bugs in these functions cause the segmentation fault, especially if the loop does not reach zero and memory is eventually exhausted during this infinite loop.
Here is a modified version:
int *num_to_binary(int *number_b, int size_of_number, int *binary_size) {
int i, j, curr_size;
int *p, *newp;
curr_size = 1;
p = malloc(1 * sizeof(int));
if (p == NULL)
return NULL;
p[0] = 0;
for (i = 0; !is_zero(number_b, size_of_number); i++) {
if (i != 0) {
curr_size += 1;
newp = realloc(p, curr_size * sizeof(int));
if (newp == NULL) {
free(p);
return NULL;
}
p = newp;
}
p[i] = number_b[size_of_number - 1] % 2;
divide_by_2(number_b, size_of_number);
}
for (i = 0, j = curr_size; i < j; i++)
int digit = p[--j];
p[j] = p[i];
p[i] = digit;
}
*binary_size = curr_size;
return p;
}
There is no need for multiple memory reallocations. Result memory buffer size could be easily evaluated as binary logarithm of the decimal input value. Calculation of the number binary representation could also be simplified:
//Transform binary array to actual number
int arr2int(int* pIntArray, unsigned int nSizeIn) {
if (!pIntArray || !nSizeIn)
return 0;
int nResult = 0;
for (unsigned int i = 0; i < nSizeIn; ++i)
nResult += pIntArray[i] * (int)pow(10, nSizeIn - i - 1);
return nResult;
}
int* int2bin(int* pIntArray, unsigned int nSizeIn, unsigned int* nSizeOut){
//0) Converting int array to the actual value
int nVal = arr2int(pIntArray, nSizeIn);
//1)Evaluating size of result array and allocating memory
if(!nVal)
*nSizeOut = 1;
else
*nSizeOut = (int)floor(log2(nVal)) + 1;
//2)Allocate and init memory
int* pResult = malloc(*nSizeOut);
memset(pResult, 0, *nSizeOut * sizeof(int));
//3) Evaluate binary representation
for (unsigned int i = 0; i < *nSizeOut; ++i){
int nBinDigit = (int)pow(2, i);
if (nBinDigit == (nVal & nBinDigit))
pResult[*nSizeOut - i - 1] = 1;
}
return pResult;
}
Testing:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define _DC 9
int main()
{
int test[_DC];
for (int i = 0; i < _DC; ++i)
test[i] = i;
unsigned int nRes = 0;
int* pRes = int2bin(test, _DC, &nRes);
for (unsigned int i = 0; i < nRes; ++i)
printf("%d", pRes[i]);
free(pRes);
return 0;
}
Question:
I want to know the difference of number n and a, both stored in char
arrays in ALI structures. Basically, what I'm doing is initialising
two integers (temp_n and temp_a) with the current digits of n and a,
subtracting them and placing the result in a new ALI instance named
k. If the j-th digits of a is greater than the i-th digit of n, then
I add 10 to the digit if n, finish the subtraction, and in the next
turn, I increase temp_a by one. The value of number a certainly falls
between 1 and n - 1 (that's given). If a is shorter than n, as soon
as I reach the last digits of a, I put the remaining digits of n to
the result array k. And I do this all backwards, so the initialising
value of i would be the size of n -1.
Example:
I store a number in a structure like this:
typedef struct Arbitrary_Large_Integer
{
char digits[];
} ALI;
Requirements:
I know that it could be easier to use char arrays instead of a
structure with a single member which barely makes sense, but I'm
forced to put structures in my code this time (that's a requirement
for my assignment).
Code:
ALI *subtraction(ALI n, ALI a, int nLength, int aLength)
{
ALI *result;
result = (ALI*)malloc(nLength * sizeof(ALI));
if (result == NULL)
printf("ERROR");
int temp_n, temp_a, difference;
int i = nLength - 1; //iterator for number 'n'
int j = aLength - 1; //iterator for number 'a'
int k = 0; //iterator for number 'k', n - a = k
bool carry = false; //to decide whether a carry is needed or not the turn
for (i; i >= 0; i--)
{
//subtracting 48 from n.digits[i], so temp_n gets the actual number
//and not its ASCII code when the value is passed
temp_n = n.digits[i] - ASCIICONVERT;
temp_a = a.digits[j] - ASCIICONVERT;
//Performing subtraction the same way as it's used on paper
if (carry) //if there is carry, a needs to be increased by one
{
temp_a++;
carry = false;
}
if (temp_n >= temp_a)
{
difference = temp_n - temp_a;
}
//I wrote else if instead of else so I can clearly see the condition
else if (temp_a > temp_n)
{
temp_n += 10;
difference = temp_n - temp_a;
carry = true;
}
//placing the difference in array k, but first converting it back to ASCII
result->digits[k] = difference + ASCIICONVERT;
k++;
//n is certainly longer than a, so after every subtraction is performed on a's digits,
//I place the remaining digits of n in k
if (j == 0)
{
for (int l = i - 1; l >= 0; l--)
{
result->digits[k] = n.digits[l];
k++;
}
//don't forget to close the array
result->digits[k] = '\0';
break;
}
j--;
}
//reverse the result array
_strrev(result->digits);
return result;
}
Output/Error:
Output results
It seems like when the array is passed to the function, its value
changes for some reason. I can't figure out what's wrong with it.
Problems:
Non-standard C
The typedef is not a valid standard C structure. The Flexible Array Member(FAM) .digits must be accompanied by at least one more prior named member in addition to the flexible array member. Recommend to put .nLength as the first member.
// Not standard
typedef struct Arbitrary_Large_Integer {
char digits[];
} ALI;
malloc(0)??
Since code is using a non-standard C, watch out that nLength * sizeof(ALI) may be the same as nLength * 0.
No room for the null character
Code is attempting to use .digits as a string with _strrev(), themallloc() is too small by 1, at least.
Other problems may exist
A Minimal, Complete, and Verifiable example is useful for additional fixes/solutions
Hello guys i am trying to implement a program which is finding the happy numbers were between two numbers A and B.
Summing the squares of all the digits of the number, we replace the number with the outcome, and repeat the process. If after some steps the result is equal to 1 (and stay there), then we say that the number N is **<happy>**. Conversely, if the process is repeated indefinitely without ever showing the number 1, then we say that the number N is **<sad>**.
For example, the number 7 is happy because the procedure described above leads to the following steps: 7, 49, 97, 130, 10, 1, 1, 1 ... Conversely, the number 42 is sad because the process leads to a infinite sequence 42, 20, 4, 16, 37, 58, 89, 145, 42, 20, 4, 16, 37 ...
I try this right down but i am getting either segm faults or no results.
Thanks in advance.
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
void happy( char * A, int n);
int numPlaces (long n);
int main(void)
{
long A,B;
int npA;
char *Ap;
printf("Give 2 Numbers\n");
scanf("%li %li",&A,&B);
npA = numPlaces(A);
Ap = malloc(npA);
printf("%ld %d\n",A,npA);
//Search for happy numbers from A to B
do{
sprintf(Ap, "%ld", A);
happy(Ap,npA);
A++;
if ( npA < numPlaces(A) )
{
npA++;
Ap = realloc(Ap, npA);
}
}while( A <= B);
}
//Finds happy numbers
void happy( char * A, int n)
{
//Basic Condition
if ( n == 1)
{
if (A[0] == 1 || A[0] == 7)
printf("%c\n",A[0]);
printf("%s\n",A);
return;
}
long sum = 0 ;
char * sumA;
int nsum;
int Ai;
//Sum the squares of the current number
for(int i = 0 ; i < n;i++)
{
Ai = atoi(&A[i]);
sum = sum + (Ai*Ai);
}
nsum = numPlaces (sum);
sumA = malloc(nsum);
sprintf(sumA, "%li", sum);
happy(sumA,nsum);
free(sumA);
}
//Count digits of a number
int numPlaces (long n)
{
if (n < 0) return 0;
if (n < 10) return 1;
return 1 + numPlaces (n / 10);
}
Thanks for your time.
by the definition of your program sad numbers will cause your program to run forever
Conversely, if the process is repeated indefinitely
You need to add a stopping condition, like if I have looped for 1000 times, or if you hit a well known non terminating number (like 4) (is there a definite list of these? I dont know)
I find this solution tested and working..
Thanks for your time and I am sorry for my vagueness.
Every advice about this solution would be welcome
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
void happy( char * A, int n);
int numPlaces (long n);
int happynum = 0;
int main(void)
{
long A,B;
int npA;
char *Ap;
printf("Give 2 Numbers\n");
scanf("%li %li",&A,&B);
npA = numPlaces(A);
Ap = malloc(npA);
//Search for happy numbers from A to B
do{
sprintf(Ap, "%ld", A);
happy(Ap,npA);
if (happynum ==1)
printf("%s\n",Ap);
A++;
if ( npA < numPlaces(A) )
{
npA++;
Ap = realloc(Ap, npA);
}
}while( A <= B);
}
//Finds happy numbers
void happy( char * A, int n)
{
//Basic Condition
if ( n == 1)
{
if (A[0] == '3' || A[0] == '6' || A[0] == '9')
{
happynum = 0;
}
else
{
happynum = 1;
}
return;
}
long sum = 0;
char * sumA;
int nsum;
int Ai;
//Sum the squares of the current number
for(int i = 0 ; i < n;i++)
{
Ai = (int)(A[i]-48);
sum = sum + (Ai*Ai);
}
nsum = numPlaces (sum);
sumA = malloc(nsum);
sprintf(sumA, "%li", sum);
happy(sumA,nsum);
free(sumA);
}
//Count digits of a number
int numPlaces (long n)
{
if (n < 0) return 0;
if (n < 10) return 1;
return 1 + numPlaces (n / 10);
}
Your code uses some questionable practices. Yoe may be misguided because you are concerned about performance and memory usage.
When you allocate memory for the string, you forget to allocate one character for the null terminator. But you shouldn't be allocating, re-allocating and freeing constantly anyway. Dynamic memory allocation is expensive compared to your other operations.
Your limits are long, which may be a 32-bit or 64-bit signed integer, depending on your platform. The maximum number that can be represented with e 64-bit signed integer is 9,223,372,036,854,775,807. This is a number with 19 digits. Add one for the null terminator and one for a possible minus sign, so that overflow won't hurt, you and use a buffer of 21 chars on the stack.
You probably shouldn't be using strings inthe first place. Use the basic code to extract the digits: Split off the digit by taking the remainder of a division by 10. Then divide by 10 until you get zero. (And if you use strings with a fixed buffer size, as described above, you don't have to calculate the difits separately: sprintf returns the number of characters written to the string.
Your functions shouldn't be recursive. A loop is enough. As pm100 has noted, you need a termination criterion: You must keep track of the numbers that you have already visited. Each recursive call creates a new state; it is easier to keep an array, that can be repeatedly looked at in a loop. When you see a number that you have already seen (other than 1, of course), your number is sad.
Happy and sad numbers have this property that when your sum of squares is a number with a known happiness, the original number has this happiness, too. If you visit a known das number, the original number is sad. If you visit a known happy number, the original number is happy.
The limits of your ranges may ba large, but the sum of square digits is not large; it can be at most the number of digits times 81. In particular:
type max. number number of max. square sum dss
int 2,147,483,647 1,999,999,999 730
uint 4,294,967,295 3,999,999,999 738
long 9,223,372,036,854,775,807 8,999,999,999,999,999,999 1522
ulong 18,446,744,073,709,55,1616 9,999,999,999,999,999,999 1539
That means that when you take the sum of digit squares of an unsigned long, you will get a number that is smaller than 1540. Create an array of 1540 entries and mark all known happy numbers with 1. Then you can reduce your problem to taking the sum of digit squares once and then looking up the happiness of the number in this array.
(You can do the precalculation of the array once when you start the program.)
I am trying to build a simple function to handle block striping onto a "fake" disk (implemented in memory as a nested array of n blocks of x bytes represented by 4 byte ints, stored to a regular file on close). Data is passed into my write_block function as an array of chars from the buffer in my open-file table (OFT).
In order to do this my thought process is to convert my array of chars to an integer value in blocks of 4 chars (the logic being 4x1 byte chars is equivalent to 1x4 byte integer) by using the following function:
//write_block(index, block_pointer)
// write block, start with array of characters and write integers to ldisk (convBlock == converted Block)
// return: 1 if successful, -1 if not
int write_block(int blockIndex, char *convBlock) {
if (strlen(convBlock) > blockSize) {
printf("Block passed to write exceeds max block size\n");
return -1;
}
int i, j;
int scalar, currIndex;
for (i = 0; i < strlen(convBlock) / sizeof(int) + ((strlen(convBlock) % sizeof(int) == 0) ? 0 : 1); i++) {
scalar = 1;
for (j = 0; j < sizeof(int); j++) {
currIndex = (i * sizeof(int) + j);
if (currIndex > strlen(convBlock))
break;
ldisk[blockIndex][i] += convBlock[i] * scalar;
scalar *= 1000;
}
}
return 1;
}
However, this doesn't work because the maximum size of an unsigned 4 bit integer is 4294967295 (10 digits), while converting a char array this way results in 12 digits (3 per char). I know I should technically be able to do this since a char takes up a single byte, while an integer takes 4.
My next thought was to convert to binary then convert back to an integer. However, I would need to somehow store the binary representation of 4 chars back to back which would require an integer with 4*8 = 32 digits, while the max size of the largest numeric type (long long) is 18446744073709551615 (20 digits).
My understanding of your goal is you want to store a null terminated block of characters to a virtual disk made of integers into block blockIndex.
Here is a simplified version of your function that can handle different storage types: 4 byte ints or 8 byte ints:
#include <stdint.h>
//write_block(index, block_pointer)
// write block, start with array of characters src and write integers to ldisk
// return: 1 if successful, -1 if not
int write_block(int blockIndex, const char *src) {
size_t i, j, k, size;
size = strlen(src) + 1; // include the null terminator in the written conversion.
if (size > blockSize) {
printf("Block passed to write exceeds current block size\n");
return -1;
}
for (i = j = k = 0; i < size; i++) {
ldisk[blockIndex][j] &= ~(0xFFULL << k);
ldisk[blockIndex][j] |= (unsigned long long)(unsigned char)src[i] << k;
k += 8;
if (k == sizeof(ldisk[blockIndex][j]) * 8) {
j++;
k = 0;
}
}
return 1;
}
Notes:
I included the null terminator in the conversion so the reading code knows where to stop.
The char values must be cast as unsigned char to avoid sign propagation in case char type is signed, which is the default on many systems.
You should return the number if blocks written (j) to the caller. This is useful information, and can easily be distinguished from -1 for errors.
This code does assume that char has 8 bits. Using CHAR_BITS instead of 8 would allow for other values with some other constant adjustments, if you really seek full compatibility with exotic platforms.
I use unsigned long long arithmetic to allow for the storage unit to be as large as possible.
I'm building a program in C that can get powers of 2. The user inputs the value of n, and the program calculates 2^n.
Here's the code.
The problem comes when I input 100
What I am getting:
1,267,650,600,228,229,400,000,000,000,000
What I should get
1,267,650,600,228,229,401,496,703,205,376
It has to be coded entirely in ANSI C. Any ideas on how to increase the precision? The maximum value of N has to be 256 (256 bits, I imagine, which means the maximum output should be 2^256).
What I'm lacking here is precision, and I don't know how to fix that. Any ideas?
I think it's easiest if you work in base 10 from the start. This is because while calculating powers of 2 in binary is trivial, the conversion back to base 10 is a lot harder.
If you have an array of base 10 digits1, you only need to implement base 10 addition with carry to be able to multiply by 2 (by adding the number to itself). Do that n times in a loop and you have your answer.
If you wish to support higher exponents, you can also look into implementing exponentiation by squaring, but that's harder, since you'll need general multiplication, not just by 2 for that.
1 Tip: It's more convenient if you store the digits in reverse order.
Here is my quick and dirty implementation of hammar's approach., storing the decimal number as a C string with the digits in reverse order.
Run the code on ideone
void doubleDecimal(char * decimal)
{
char buffer[256] = "";
char c;
unsigned char d, carry = 0;
int i = 0;
while (c = decimal[i])
{
d = 2 * (c - '0') + carry;
buffer[i] = (d % 10) + '0';
carry = d / 10;
i++;
}
if (carry > 0)
buffer[i++] = (carry % 10) + '0';
buffer[i] = '\0';
strncpy(decimal, buffer, 256);
}
void reverse(char * str)
{
int i = 0;
int j = strlen(str) - 1;
while (j > i)
{
char tmp = str[i];
str[i] = str[j];
str[j] = tmp;
i++;
j--;
}
}
int main(void)
{
char decimal[256] = "1";
int i;
for (i = 0; i < 100; i++)
doubleDecimal(decimal);
reverse(decimal);
printf("%s", decimal);
return 0;
}
Output:
1267650600228229401496703205376
double is a (probably) 64bit value. You can't store 256 bits of precision in 64 bits. The reason that you are getting a number that is sort of close is because floating point numbers are stored with varying precision -- not all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.
What you want is either to use an arbitrary precision library or, since this is probably homework, you are expected to write your own.
A typical double, using 64-bit IEEE 754, has about 51 bits precision, IIRC.
Most probably the point of supporting exponents up to 256 is to exceed that precision, and also the precision of a long double or long long, so that you have to do things yourself.
As a homework exercise, then,
Store decimal digit values in an array + a digit count
Implement doubling of the value in such array + count
Start with 1 and double value appropriate number of times.
A few things you'll want to think about to solve this:
You are only dealing with integers so you should use an integer
representation (you will need to roll your own because you can't use
long long which is "only" 64 bits long).
Powers of 2 you say -how convenient - computers store numbers using powers of 2 (you'll
only need to use shift operations and bit fiddling .... no
multiplications will be needed).
How can you convert a base 2 number to a base 10 number for display purposes (think of division and outputting one number at a time (think about what a hardware divisor does in order to get the bit manipulations correct).
You can't the store 256 bits of precision in 64 bits. Reason that you are getting a number to close is because floating point numbers are stored with varying precision. To all sequential numbers can be represented, but you can represent very large numbers. Pretty useless in this case.
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//constants
#define MAX_DIGITS 1000
//big integer number struct
struct bigint {
char Digits[MAX_DIGITS];
};
//assign a value
void assign(struct bigint* Number,int Value) {
if (Value!=1) {
printf("Can not assign value other than 1\n");
exit(0);
}
memset(Number,0,sizeof(bigint));
Number->Digits[0] = Value;
}
//multiply the big integer number with value
void multiply(struct bigint* Number,int Value) {
int Digit,New_Digit;
int Carry = 0;
for (int Index=0; Index<MAX_DIGITS; Index++) {
Digit = Number->Digits[Index];
New_Digit = Digit*Value%10;
if (New_Digit+Carry<10) {
New_Digit = New_Digit+Carry;
Carry = Digit*Value/10;
}
else {
New_Digit = (New_Digit+Carry)%10;
Carry = (Digit*Value/10)+1;
}
//set the new digit
Number->Digits[Index] = New_Digit;
}//for loop
}
//print out the value of big integer type
void print(struct bigint* Number) {
int Index = MAX_DIGITS-1;
while (Number->Digits[Index]==0 && Index>=0)
Index--;
//the big integer value is zero
if (Index==-1) {
printf("0");
return;
}
while (Index>=0) {
printf("%u",Number->Digits[Index]);
Index--;
}
}
//main programme entry point
int main(int Argc,char** Args) {
int Power = 100;
struct bigint Number;
//assign the initial value
assign(&Number,1);
//do the multiplication
for (int Index=0; Index<Power; Index++)
multiply(&Number,2);
//print result
print(&Number);
getch();
}
//END-OF-FILE