I am trying to find primes using Sieve of Eratosthenes with bit arrays, but I am using unsigned int array. I need to be able to generate upto 2,147,483,647 primes. My code works and can generate around 10,000,000 but when I increase the size of my array to accommodate larger numbers it fails. Can someone guide me on how to use bit vectors with c (not c++).
Thanks
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#define MAXBYTES 2000000
#define MAX 50000000
#define BITSIZE 32
void ClearBit(unsigned int [], unsigned int);
void SetBit(unsigned int [], unsigned int);
int BitVal(unsigned int [], unsigned int);
void PrintBitStream(unsigned int [], unsigned long);
void PrintBitStreamData(unsigned int[], unsigned long);
int Sieve(unsigned int[], unsigned int, unsigned int);
int main(int argc, char ** argv) {
unsigned int maxsize = MAX;
unsigned int i;
//Set Bit Array
unsigned int BitArray[MAXBYTES] = {0};
SetBit(BitArray, 0);
SetBit(BitArray, 1);
i = 2;
for (;i < maxsize;i++){
if(Sieve(BitArray, i, maxsize)==0)
break;
}
PrintBitStreamData(BitArray, maxsize-1);
return EXIT_SUCCESS;
}
void PrintBitStreamData(unsigned int BitArray[], unsigned long maxsize) {
unsigned int i;
for (i = 0; i < maxsize; i++)
if (!BitVal(BitArray, i))
printf("%ld ", i);
printf("\n");
}
void PrintBitStream(unsigned int BitArray[], unsigned long maxsize) {
unsigned int i;
for (i = 2; i < maxsize; i+=2)
printf("%d", BitVal(BitArray, i));
printf("\n");
}
void SetBit(unsigned int BitArray[], unsigned int pos) {
BitArray[pos / BITSIZE] |= 1 << (pos % BITSIZE);
}
void ClearBit(unsigned int BitArray[], unsigned int pos) {
BitArray[pos / BITSIZE] &= ~(1 << (pos % BITSIZE));
}
int BitVal(unsigned int BitArray[], unsigned int pos) {
return ((BitArray[pos / BITSIZE] & (1 << (pos % BITSIZE))) != 0);
}
int Sieve(unsigned int BitArray[], unsigned int p, unsigned int maxsize) {
unsigned int i;
unsigned int j;
j = 0;
for (i = 2 * p; i < maxsize; i += p) {
SetBit(BitArray, i);
j++;
}
return j;
}
I definitely would NOT use a bit array, but an array of the native int (64-bit or 32-bit dependign on architecture) and wrapping around a function to remap normal numbers to the right place and bit with bitwise | and &.
Also consider leaving out the even numbers, almost none of them are prime. So you could store the first 128 numbers in the first 64-bit number, the next 128 in the second etc.
It sounds a bit complicated, but is a bit fun to get it work!
Project Euler seems to have produced some really nice solutions.
The good thing is: to sieve you don't need to recalculate the even-odd-transfer, but you can unset every third bit for sieving 3, every 5th bit for sieving 5 etc.
Come into chat if you want a quick java solution as a detailed reference.
EDIT4: corrected Working code, but yet slow. Memo: Remember using calloc!
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
typedef unsigned long long number;
number lookFor = 2147483648ULL;
number max = 2147483648ULL*10ULL; // hopefully more then every 10th uneven number is prime
unsigned long * isComposite;
number bitslong = CHAR_BIT*sizeof(long);
time_t rawtime;
struct tm * timeinfo;
char buffer[80];
// is not called during sieve, only once per sieving prime
// and needed for reading if a number is prime
inline long getParts(number pos, number *slot, unsigned int *bit){
*slot = pos / bitslong;
*bit = (unsigned int)(pos % bitslong);
}
int isPrime(number n){
if(n == 1){
return 0;
}
if(n < 4){
return 1;
}
if((n%2) == 0){
return 0;
}
number slot=0;
unsigned int bit=0;
number pos = (number)(n-3)/2;
getParts(pos, &slot, &bit);
// printf("? n=%lld pos = %lld slot = %lld bit = %lu ret %d \n", n, pos, slot, bit, !(isComposite[slot] & (1<<bit)));
return !(isComposite[slot] & (1UL<<bit));
}
// start sieving at offset (internal position) offset with width step
int doSieve(number offset, number step){
rawtime = time(0);
time (&rawtime);
timeinfo = localtime (&rawtime);
strftime(buffer, 80, "%Y-%m-%d %H:%I:%S", timeinfo);
unsigned int bit=0;
number slot=0;
getParts(offset, &slot, &bit);
printf("doSieve %s %lld %lld %lu \n", buffer, offset, step, isComposite[slot]);
while(slot < max/bitslong){
slot += (step + bit)/bitslong;
bit = (step + bit) % bitslong;
isComposite[slot] |= (1UL << bit);
}
return 1;
}
int sieve(){
number spot;
spot=1;
number pos;
pos = 0;
while(spot < 1 + sqrt((float)max)){
spot+=2;
if(! isPrime(spot)){
pos++;
continue;
}
doSieve(pos, spot);
pos++;
}
}
void main(int argc, char *argv[]){
if(argc > 1){
char *tp = malloc(sizeof(char*));
max = strtol(argv[1], &tp, 10);
}
printf("max %lld , sq %ld, malloc: %lld\n", max, (long)(1 + sqrt((float)max)), 1+max/bitslong);
isComposite = calloc((2+max/bitslong), sizeof(unsigned long)) ;
if(! isComposite){
printf("no mem\n");
exit(5);
}
sieve();
number i;
number found = 0;
for(i = 1; i<max && found < lookFor; i++){
if(isPrime(i)){
found++;
// printf(" %30lld %30lld \n", found, i);
if(found % 10000 == 0 ){
printf("%30lld %30lld \n", found, i);
}
}
/*
if(i % 1000 == 17){
printf("%5lld %5lld \n", i, found);
}
*/
}
}
Example using bit access into an integer
Note GetBit() and SetBit().
An optimizing compiler will make the / and % fast for powers of 2 are used.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ubitsize (sizeof(unsigned)*8)
unsigned GetBit(const unsigned *List, unsigned long index) {
return !!(List[index / ubitsize] & (1u << (index % ubitsize)));
}
void SetBit(unsigned *List, unsigned long index) {
List[index / ubitsize] |= (1u << (index % ubitsize));
}
void Sieve_of_Eratosthenes_via_bit_array(unsigned long MaxCandidatePrime) {
unsigned long uByteSize = MaxCandidatePrime/ubitsize + 1;
unsigned *List = calloc(uByteSize, sizeof *List);
if (List == 0) return;
unsigned long PrimeCount = 0;
unsigned long Index = 0;
for (Index = 2; Index <= MaxCandidatePrime; Index++) {
// If found a prime ...
if (GetBit(List, Index) == 0) {
PrimeCount++;
// let's see the progress
if ((PrimeCount % (256LU*1024)) == 0) printf("%lu\n", Index);
// Mark subsequent multiples as not--a-prime
unsigned long Index2 = Index*2;
while (Index2 <= MaxCandidatePrime) {
SetBit(List, Index2);
Index2 += Index;
}
}
}
printf("X %lu\n", Index);
free(List);
}
void test(void) {
Sieve_of_Eratosthenes_via_bit_array(200LU*1000*1000);
}
A re-write could employ usual suggestion to not save even numbers, treating 2 as a special case. This helps but I assume this is an exercise. I could save a factor of about 4 by saving using 1 byte to encode every 30th multiple as, after 30, for there are at most 8 primes every 30 integers. Other schemes exist.
Related
I am writing a small C program to count the number of bits which need to be flipped to make one number equal to another.
The program works very fine but i observe abnormal behaviour (Program hangs) when i pass ULONG_MAX as an argument. Why is this happening? See code below
#include <stdio.h>
#include <limits.h>
#include <stddef.h>
/**
* flip_bits - Count the number of bits to flip to equalize two numbers
* #n: First number
* #m: Second number
*
* Return: the number of bits to flip
*/
unsigned int flip_bits(unsigned long int n, unsigned long int m)
{
unsigned long int diff, count;
int i;
diff = n ^ m;
count = 0;
i = 0;
while (diff >> i)
{
if (diff >> i & 1)
count++;
i++;
}
return (count);
}
/**
* main - check the code
*
* Return: Always 0.
*/
int main(void)
{
unsigned int n;
n = flip_bits(1024, 1);
printf("%u\n", n);
n = flip_bits(402, 98);
printf("%u\n", n);
n = flip_bits(1024, 3);
printf("%u\n", n);
n = flip_bits(ULONG_MAX, 0);
printf("%u\n", n);
return (0);
}
Be explicit with signedness and size of all relevant types involved. Don't use bitwise arithmetic on signed numbers. You can simplify this whole code quite a bit by using a readable for loop instead:
#include <stdint.h>
uint32_t count_diff32 (uint32_t x, uint32_t y)
{
uint32_t diff = x ^ y;
uint32_t count = 0;
for(size_t i=0; i<32; i++)
{
if (diff & (1u<<i))
{
count++;
}
}
return count;
}
I need to compute the factorial of a number without using the multiplication operator. Because of this restriction, I directly tried to use repeated addition. It kind of works. However, my program is struggling to get the factorial of larger numbers. Is there a better way to solve the problem?
Here is my code:
void main(){
unsigned long num = 0, ans = 1, temp = 1;
printf("Enter a number: ");
scanf("%lu", &num);
while (temp <= num){
int temp2 = 0, ctr = 0;
while (ctr != temp){
temp2 += ans;
ctr ++;
}
ans = temp2;
temp ++;
}
printf("%lu! is %lu\n", num, ans);
}
You can implement a faster (than repeated addition) multiply function using bit shifts and addition to perform "long multiplication" in binary.
unsigned long long mul_ull(unsigned long long a, unsigned long long b)
{
unsigned long long product = 0;
unsigned int shift = 0;
while (b)
{
if (b & 1)
{
product += a << shift;
}
shift++;
b >>= 1;
}
return product;
}
EDIT: Alternative implementation of the above using single bit shifts and addition:
unsigned long long mul_ull(unsigned long long a, unsigned long long b)
{
unsigned long long product = 0;
while (b)
{
if (b & 1)
{
product += a;
}
a <<= 1;
b >>= 1;
}
return product;
}
In practice, whether or not this is faster than repeated addition depends on any optimizations done by the compiler. An optimizing compiler could analyze the repeated addition and replace it with a multiplication. An optimizing compiler could also analyze the code of the mul_ull function above and replace it with a multiplication, but that may be harder for the optimizer to spot. So in practice, it is perfectly reasonable for the repeated addition algorithm to end up faster than the bit-shift and addition algorithm after optimization!
Also, the above implementations of the mul_ull functions will tend to perform better if the second parameter b is the smaller of the numbers being multiplied when the one of the numbers is much larger than the other (as is typical for a factorial calculation). The execution time is roughly proportional to the log of b (when b is non-zero) but also depends on the number of 1-bits in the binary value of b. So for the factorial calculation, put the old running product in the first parameter a and the new factor in the second parameter b.
A factorial function using the above multiplication function:
unsigned long long factorial(unsigned int n)
{
unsigned long long fac = 1;
unsigned int i;
for (i = 2; i <= n; i++)
{
fac = mul_ull(fac, i);
}
return fac;
}
The above factorial function is likely to produce an incorrect result for n > 20 due to arithmetic overflow. 66 bits are required to represent 21! but unsigned long long is only required to be 64 bits wide (and that is typically the actual width for most implementations).
For large values of n, a big format is needed.
As you cannot use multiplications, it seems logical that you must implement it yourself.
In practice, as only additions are needed, it is not so difficult to implement, if we are not looking for a high efficiency.
A little difficulty anyway : you have to convert the input integer in an array of digits.
As modulo is not allowed I guess, I implemented it with the help of snprintf function.
Result:
100! is 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Note: this result is provided about instantaneously.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NDIGITS 1000 // maximum number of digits
struct MyBig {
int digits[NDIGITS + 2]; // "+2" to ease overflow control
int degree;
};
void reset (struct MyBig *big) {
big->degree = 0;
for (int i = 0; i <= NDIGITS; ++i) big->digits[i] = 0;
}
void create_with_div (struct MyBig *big, int n) { // not used here
reset (big);
while (n != 0) {
big->digits[big->degree++] = n%10;
n /= 10;
}
if (big->degree != 0) big->degree--;
}
void create (struct MyBig *big, int n) {
const int ND = 21;
char dig[ND];
snprintf (dig, ND, "%d", n);
int length = strlen (dig);
reset (big);
big->degree = length - 1;
for (int i = 0; i < length; i++) {
big->digits[i] = dig[length - 1 - i] - '0';
}
}
void print (struct MyBig *big) {
for (int i = big->degree; i >= 0; --i) {
printf ("%d", big->digits[i]);
}
}
void accumul (struct MyBig *a, struct MyBig *b) {
int carry_out = 0;
for (int i = 0; i <= b->degree; ++i) {
int sum = carry_out + a->digits[i] + b->digits[i];
if (sum >= 10) {
carry_out = 1;
a->digits[i] = sum - 10;
} else {
carry_out = 0;
a->digits[i] = sum;
}
}
int degree = b->degree;
while (carry_out != 0) {
degree++;
int sum = carry_out + a->digits[degree];
carry_out = sum/10;
a->digits[degree] = sum % 10;
}
if (a->degree < degree) a->degree = degree;
if (degree > NDIGITS) {
printf ("OVERFLOW!!\n");
exit (1);
}
}
void copy (struct MyBig *a, struct MyBig *b) {
reset (a);
a->degree = b->degree;
for (int i = 0; i <= a->degree; ++i) {
a->digits[i] = b->digits[i];
}
}
void fact_big (struct MyBig *ans, unsigned int num) {
create (ans, 1);
int temp = 1;
while (temp <= num){
int ctr = 0;
struct MyBig temp2;
reset (&temp2);
while (ctr != temp){
accumul (&temp2, ans);
ctr ++;
}
copy (ans, &temp2);
temp ++;
}
return;
}
unsigned long long int fact (unsigned int num) {
unsigned long long int ans = 1;
int temp = 1;
while (temp <= num){
int ctr = 0;
unsigned long long int temp2 = 0;
while (ctr != temp){
temp2 += ans;
ctr ++;
}
ans = temp2;
temp ++;
}
return ans;
}
void main(){
unsigned long long int ans;
unsigned int num;
printf("Enter a number: ");
scanf("%u", &num);
ans = fact (num);
printf("%u! is %llu\n", num, ans);
struct MyBig fact;
fact_big (&fact, num);
printf("%u! is ", num);
print (&fact);
printf ("\n");
}
I'm trying to get my program to work, where I shift bits to the left and add the shifted bits to the right. For example 00111000, if you shift it 4 positions to the left, the outcome should be 10000011. How can I make this work, I know that I need to use the bitwise OR. I have added the main function below.
#include <stdio.h>
#include <stdlib.h>
void printbits(int b){
int i;
int s = 8 * (sizeof b) - 1; /* 31 if int is 32 bits */
for(i=s;i>=0;i--)
putchar( b & 1<<i ? '1' : '0');
}
int main(){
char dir; /* L=left R=right */
int val, n, i;
scanf("%d %d %c",&val, &n, &dir);
printbits(val);putchar('\n');
for (i=0; i<10; i++){
if (dir=='L' || dir =='l')
rotateLeft(&val, n);
else
rotateRight(&val,n);
printbits(val); putchar('\n');
}
return;
}
This is the rotateLeft en rotateRight function.
#include <stdio.h>
#include <stdlib.h>
void rotateLeft(int *val, int N){
int num = val[0];
int pos = N;
int result = num << pos;
}
void rotateRight(int *val, int N){
int num = val[0];
int pos = N;
int result = num >> pos;
}
Here is a tested and non-optimized solution to complete your source code:
void rotateLeft(int *val, int N){
unsigned int num = val[0];
int pos = N;
unsigned int part1 = num << pos;
unsigned int part2 = (num >> ((sizeof(val[0])*CHAR_BIT)-pos));
if (N != 0) {
val[0] = part1 | part2;
}
}
void rotateRight(int *val, int N){
unsigned int num = val[0];
int pos = N;
unsigned int part1 = num >> pos;
unsigned int part2 = (num << ((sizeof(val[0])*CHAR_BIT)-pos));
if (N != 0) {
val[0] = part1 | part2;
}
}
To prevent automatic carry during the shift right, you have to
consider value as unsigned int.
To prevent N = 0 interference, assign the result to the entry only when (N != 0). (See remark on post ROL / ROR on variable using inline assembly in Objective-C)
MSB = (n >> (NUM_OF_BITS_IN_INT - 1))
n = (n << 1) | MSB;
Left bit rotation of n by 1 bit.
You are just shrugging off the MSB but not adding it back at LSB position.
use the functions in this link for performing the rotations:
https://en.wikipedia.org/wiki/Circular_shift
There are several fast algorithms to calculate prime numbers up to a given number n. But, what is the fastest implementation to list all the numbers r relatively prime to some number n in C? That is, find all the elements of the multiplicative group with n elements as efficiently as possible in C. In particular, I am interested in the case where n is a primorial.
The n primorial is like the factorial except only prime numbers are multiplied together and all other numbers are ignored. So, for example 12 primorial would be 12#=11*7*5*3*2.
My current implementation is very naive. I hard code the first 3 groups as arrays and use those to create the larger ones. Is there something faster?
#include "stdafx.h"
#include <stdio.h> /* printf, fgets */
#include <stdlib.h> /* atoi */
#include <math.h>
int IsPrime(unsigned int number)
{
if (number <= 1) return 0; // zero and one are not prime
unsigned int i;
unsigned int max=sqrt(number)+.5;
for (i = 2; i<= max; i++)
{
if (number % i == 0) return 0;
}
return 1;
}
unsigned long long primorial( int Primes[], int size)
{
unsigned long long answer = 1;
for (int k = 0;k < size;k++)
{
answer *= Primes[k];
}
return answer;
}
unsigned long long EulerPhi(int Primes[], int size)
{
unsigned long long answer = 1;
for (int k = 0;k < size;k++)
{
answer *= Primes[k]-1;
}
return answer;
}
int gcd( unsigned long long a, unsigned long long b)
{
while (b != 0)
{
a %= b;
a ^= b;
b ^= a;
a ^= b;
}
//Return whethere a is relatively prime to b
if (a > 1)
{
return false;
}
return true;
}
void gen( unsigned long long *Gx, unsigned int primor, int *G3)
{
//Get the magic numbers
register int Blocks = 30; //5 primorial=30.
unsigned long long indexTracker = 0;
//Find elements using G3
for (unsigned long long offset = 0; offset < primor; offset+=Blocks)
{
for (int j = 0; j < 8;j++) //The 8 comes from EulerPhi(2*3*5=30)
{
if (gcd(offset + G3[j], primor))
{
Gx[indexTracker] = offset + G3[j];
indexTracker++;
}
}
}
}
int main(int argc, char **argv)
{
//Hardcoded values
int G1[] = {1};
int G2[] = {1,5};
int G3[] = {1,7,11,13,17,19,23,29};
//Lazy input checking. The world might come to an end
//when unexpected parameters given. Its okey, we will live.
if (argc <= 1) {
printf("Nothing done.");
return 0;
}
//Convert argument to integer
unsigned int N = atoi(argv[1]);
//Known values
if (N <= 2 )
{
printf("{1}");
return 0;
}
else if (N<=4)
{
printf("{1,5}");
return 0;
}
else if (N <=6)
{
printf("{1,7,11,13,17,19,23,29}");
return 0;
}
//Hardcoded for simplicity, also this primorial is ginarmous as it is.
int Primes[50] = {0};
int counter = 0;
//Find all primes less than N.
for (int a = 2; a <= N; a++)
{
if (IsPrime(a))
{
Primes[counter] = a;
printf("\n Prime: : %i \n", a);
counter++;
}
}
//Get the group size
unsigned long long MAXELEMENT = primorial(Primes, counter);
unsigned long long Gsize = EulerPhi(Primes, counter);
printf("\n GSize: %llu \n", Gsize);
printf("\n GSize: %llu \n", Gsize);
//Create the list to hold the values
unsigned long long *GROUP = (unsigned long long *) calloc(Gsize, sizeof(unsigned long long));
//Populate the list
gen( GROUP, MAXELEMENT, G3);
//Print values
printf("{");
for (unsigned long long k = 0; k < Gsize;k++)
{
printf("%llu,", GROUP[k]);
}
printf("}");
return 0;
}
If you are looking for a faster prime number check, here is one that is reasonably fast and eliminates all calls to computationally intensive functions (e.g. sqrt, etc..)
int isprime (int v)
{
int i;
if (v < 0) v = -v; /* insure v non-negative */
if (v < 2 || !((unsigned)v & 1)) /* 0, 1 + even > 2 are not prime */
return 0;
for (i = 2; i * i <= v; i++)
if (v % i == 0)
return 0;
return 1;
}
(note: You can adjust the type as required if you are looking for numbers above the standard int range.)
Give it a try and let me know how it compares to the once you are currently using.
I have a function which calls another function and checks for condition to see if it's true, then it increments an integer. It's all fine and working but there will be a problem for very large results. It couldn't fit even in long long.
Example:
unsigned long long div(int num_first[], int num_second[])
{
unsigned long long div_result = 0;
while (compare(num_first, num_second) != -1)
{
divsub(num_first, num_second);
div_result++;
}
return div_result; // return div_result to main
}
That function works fine, but if div_result gets too large it crashes or causes undefined behavior. I want to store its result as array like so:
div_result = 25464878454
I want it to be:
div_result[max] = {2, 5, 4, 6, 4, 8, 7, 8, 4, 5, 4}
How do I achieve this?
EDIT:
I decided to use unsigned long long as folks suggest. That suits my case.
you can write your own little bigint plus increment functionality:
#include <iostream>
using namespace std;
const int MAXDIGITS=12;
void inc(int bignum[MAXDIGITS])
{
++bignum[MAXDIGITS-1];
int carry=0;
for(int i = MAXDIGITS-1; i>=0; --i)
{
bignum[i] += carry;
if(bignum[i]>9)
{
carry = 1;
bignum[i] = 0;
}
else
break;
}
}
int main()
{
int div_result[MAXDIGITS] = {0};
// test inc function
for(int i=0; i<9999991; ++i)
inc(div_result);
for(int i=0; i<MAXDIGITS; ++i)
cout << div_result[i];
return 0;
}
Well since I worked on your original question, I'll go ahead and post the results for that as well in case you change your mind. Converting a number to an array can be approached in a number of ways. Here is one scheme using a recursive function and a helper to correct the order of the digits.
note: for 32-bit OS, overflow will occurr due to x86 utilizing a 4-bit long, a 32-bit safe version using 8-bit long long is included below, a 3rd version using preprocessor directives integrating both versions is included at the end:
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
int main (void) {
long n = 25464878454;
long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %ld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
int digits2array_rev (long x, long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
Output/Results
$ ./bin/digits2array
array:
ar[ 0] : 2
ar[ 1] : 5
ar[ 2] : 4
ar[ 3] : 6
ar[ 4] : 4
ar[ 5] : 8
ar[ 6] : 7
ar[ 7] : 8
ar[ 8] : 4
ar[ 9] : 5
ar[10] : 4
32-bit Safe Version (using long long)
On 32-bit OS's overflow would still occur. Changing the types to long long (8-bit int on x86), allows the program to operate on x86 without issue.
#include <stdio.h>
#include <stdlib.h>
#define MAXDIG 32
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
int main (void) {
long long n = 25464878454;
long long ar[MAXDIG] = {0};
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
printf (" ar[%2d] : %lld\n", i, ar[i]);
return 0;
}
/* converts x to array of digits in a (reverse order) */
long long digits2array_rev (long long x, long long *a, size_t *i)
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}
64/32-bit Version w/Preprocessor Directives
You can accomplish the same thing for x86, while preserving the original types for x86_64 through the use of preprocessor directives. (understanding that there is actually no storage benefit -- long (8-bit on x86_64), long long (8-bit on x86)).
#include <stdio.h>
#include <stdlib.h>
#if defined(__LP64__) || defined(_LP64)
# define BUILD_64 1
#endif
#define MAXDIG 32
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx);
int digits2array_rev (long x, long *a, size_t *i);
#else
void digits2array (long long x, long long *a, size_t *idx);
long long digits2array_rev (long long x, long long *a, size_t *i);
#endif
int main (void) {
#ifdef BUILD_64
long n = 25464878454;
long ar[MAXDIG] = {0};
#else
long long n = 25464878454;
long long ar[MAXDIG] = {0};
#endif
size_t idx = 0;
int i = 0;
digits2array (n, ar, &idx); /* convert n to array */
printf ("\n array:\n\n");
for (i = 0; i < idx; i++) /* output results */
#ifdef BUILD_64
printf (" ar[%2d] : %ld\n", i, ar[i]);
#else
printf (" ar[%2d] : %lld\n", i, ar[i]);
#endif
return 0;
}
/* converts x to array of digits in a (reverse order) */
#ifdef BUILD_64
int digits2array_rev (long x, long *a, size_t *i)
#else
long long digits2array_rev (long long x, long long *a, size_t *i)
#endif
{
if (x < 10) {
a[(*i)++] = x;
return x;
}
a[(*i)++] = x % 10;
return digits2array_rev (x / 10, a, i);
}
/* helper function to reverse results of digits2array_rev */
#ifdef BUILD_64
void digits2array (long x, long *a, size_t *idx)
{
long tmp[MAXDIG] = {0};
#else
void digits2array (long long x, long long *a, size_t *idx)
{
long long tmp[MAXDIG] = {0};
#endif
int i = 0;
digits2array_rev (x, tmp, idx); /* fill array with digits (reversed) */
for (i = 0; i < *idx; i++) /* reverse to correct order */
a[*idx - 1 - i] = tmp[i];
}