I know about 'strtoll' but that is converting any Radix Base Number (between 2 and 36) to Decimal and I need to do the opposite by converting Decimal to Any Radix Base Number,
an example would be decimal 130 radix 12 = AA
Decimal to Other Base SystemStep 1 − Divide the decimal number to be converted by the value of the new base. Step 2 − Get the remainder from Step 1 as the rightmost digit (least significant digit) of new base number. Step 3 − Divide the quotient of the previous divide by the new base.
Try this.
#include <stdio.h>
#include <string.h>
static void decimal_to_radix_base(char *s,int x,int base,int maxlen);
static void insert_char(char *s,int c,int maxlen);
static int digit(int x);
void main(void)
{
int x,base;
char s[128];
x=130;
base=12;
decimal_to_radix_base(s,x,base,127);
printf("%d base %d = %s\n",x,base,s);
}
static void decimal_to_radix_base(char *s,int x,int base,int maxlen)
{
int sign;
sign= (x<0) ? -1 : 1;
if (x<0)
x=-x;
s[0]='\0';
if (x==0)
{
if (maxlen > 0)
strcpy(s,"0");
return;
}
while (x>0)
{
int r;
r=x%base;
insert_char(s,digit(r),maxlen);
x /= base;
}
if (sign<0)
insert_char(s,'-',maxlen);
}
static void insert_char(char *s,int c,int maxlen)
{
int len;
len=strlen(s);
if (len>=maxlen)
memmove(&s[1],s,len-1);
else
memmove(&s[1],s,len+1);
s[0]=c;
}
static int digit(int x)
{
if (x<10)
return('0'+x);
return('A'+x-10);
}
The following code does it using a temporary buffer to build the string, then returning a duplicate. The string is built by working backwards from the end and setting each digits by indexing into another string. That should be much more efficient than all that repeated short string copying and appending the Java version does. You need to free the returned strings when you're done with them and check for NULL return if there's any chance the radix might be out of range... to avoid allocating new strings all the time you might want to adapt it to use a buffer you supply for the result.
/* return string representation of num in base rad as new string (or NULL) */
char *toBaseWhatever(int num, int rad)
{
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int i;
char buf[66]; /* enough space for any 64-bit in base 2 */
/* bounds check for radix */
if (rad < 2 || rad > 62)
return NULL;
/* if num is zero */
if (!num)
return strdup("0");
/* null terminate buf, and set i at end */
buf[65] = '\0';
i = 65;
if (num > 0) { /* if positive... */
while (num) { /* until num is 0... */
/* go left 1 digit, divide by radix, and set digit to remainder */
buf[--i] = digits[num % rad];
num /= rad;
}
} else { /* same for negative, but negate the modulus and prefix a '-' */
while (num) {
buf[--i] = digits[-(num % rad)];
num /= rad;
}
buf[--i] = '-';
}
/* return a duplicate of the used portion of buf */
return strdup(buf + i);
}
If it is not required that you create you own, 'strtoll' or 'strtoull' will do a conversion for you:
long long i64 = 0x8000000000000000LL;
unsigned long long u64 = 0xFFFFFFFFFFFFFFFFULL;
printf("Signed long long: %lld\n", i64);
printf("Unsigned long long: %llu\n", u64);
printf("\n");
char buffer[30];
sprintf(buffer, "%lld", i64);
i64 = atoll(buffer);
i64 = strtoll(buffer, NULL, 10);
u64 = strtoull(buffer, NULL, 10);
[EDIT] This edit is in response (purely for fun) to @willus comments regarding timing between his and @dmitri's solutions, and adds a third into the mix.
In terms of pure speed, Dmitri's offering wins hand's down, but includes memory leaks. It uses the strdup() function in such a way where the memory is not freed. strdupa() is an alternative that frees its allocated memory, and would be a good replacement here. And, if strdup()
or strdupa()
were not used at all, @Dmitri's code (as pointed out by @willus) would run even faster.
Credit to this implementation for the AnyRadixConvert functions.
Here are the resuts for each of the three running through integers 0 - 5001:
Here is the code that produced these results: (_note: minor changes exist eg. where i did not have strdup()
, but had StrDup()
)
#include "toolbox.h" //StrDup(), delete otherwise
#include <ansi_c.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXLEN_127 127
void delaySome(void); //test the timers...
int AnyRadixConvert(const char* oldNumber, int oldRadix,
char* newNumber, int newRadix);
///Willus
static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen);
static void insert_char(char *s,int c,int maxlen);
static int digit(int x);
////Dmitri
char *dmitri_toBaseWhatever(int num, int rad);
int main(void)
{
char dataIn[66]="5001";
char dataOut[66];
int radixFrom = 10;
int radixTo = 2;
long long int i=0;
//support willus_decimal_to_radix_base
int x;
//support Dmitri
char demitri_result[66];
demitri_result[0]=0;
int dataInNum;
int maxInAll = 5001;
/*Converts from base x to base y*/ //values from 2 to 36 for either parameter
//time it
// Delay(1);
clock_t start, end;
long double elapsed1, elapsedWillus, elapsedDimitri;
start = clock();
//end time it
for(i=0;i<=maxInAll;i++)
{
sprintf(dataIn, "%lld", i);
AnyRadixConvert(dataIn,radixFrom,dataOut,radixTo);
}
//end timeit
end = clock();
elapsed1 = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("AnyRadixConvert:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n" ,radixFrom,dataIn,radixTo, dataOut, elapsed1);
//willus_decimal_to_radix_base
x=atol(dataIn);
dataOut[0]=0;
start = clock();
for(i=0;i<=maxInAll;i++)
{
willus_decimal_to_radix_base(dataOut,(int)i,radixTo,MAXLEN_127);
}
end = clock();
elapsedWillus = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("willus_decimal_to_radix_base:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n",radixFrom,dataIn,radixTo, dataOut, elapsedWillus);
//dimitri_toBaseWhatever
dataInNum = atol("123123132");
start = clock();
for(i=0;i<=maxInAll;i++)
{
strcpy(demitri_result, dmitri_toBaseWhatever((int)i, radixTo));
}
end = clock();
elapsedDimitri = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("dimitri_toBaseWhatever:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n" ,radixFrom,dataIn,radixTo, demitri_result, elapsedDimitri);
//////////////////////////
getchar();
return 0;
}
int AnyRadixConvert(const char* oldNumber, int oldRadix, char* newNumber, int newRadix)
{
long dataIn = 0L;
char digit = 0;
int i = 0;
int size=strlen(oldNumber);
char* reverseNew = NULL;
/*Checks if base if within bounds*/
if((oldRadix<=1 || oldRadix>36)||(newRadix<=1 || newRadix>36))
{
return 0;
}
/*Convert to base 10 from old base*/
for(i=0;i<size;i++)
{
if(oldNumber[i]>='0' && oldNumber[i]<='9')
{
dataIn+=(oldNumber[i]-'0')*pow(oldRadix,size-i-1);
}
else if(oldNumber[i]>='A' && oldNumber[i]<='Z')
{
dataIn+=(oldNumber[i]-'A' + 10)*pow(oldRadix,size-i-1);
}
else
{
return -1;
}
}
i=0;
/*Convert from base 10 to new base*/
while(dataIn>0)
{
digit = dataIn % newRadix;
(digit<10)?(newNumber[i] = digit + '0')
:(newNumber[i] = digit + 'A' -10);
dataIn=dataIn/newRadix;
i++;
}
newNumber[i]='\0';
/*Reverses newNumber*/
reverseNew = (char*)(malloc(sizeof(char)*strlen(newNumber)+1));
reverseNew[0]=0;
size = strlen(newNumber);
for(i=size-1; i>=0; i--)
{
reverseNew[i] = newNumber[size-1-i];
}
reverseNew[size]='\0';
strcpy(newNumber,reverseNew);
free(reverseNew);
return 1;
}
static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen)
{
int sign;
sign= (x<0) ? -1 : 1;
if (x<0)
x=-x;
s[0]='\0';
if (x==0)
{
if (maxlen > 0)
strcpy(s,"0");
return;
}
while (x>0)
{
int r;
r=x%base;
insert_char(s,digit(r),maxlen);
x /= base;
}
if (sign<0)
insert_char(s,'-',maxlen);
}
static void insert_char(char *s,int c,int maxlen)
{
int len;
len=strlen(s);
if (len>=maxlen)
memmove(&s[1],s,len-1);
else
memmove(&s[1],s,len+1);
s[0]=c;
}
static int digit(int x)
{
if (x<10)
return('0'+x);
return('A'+x-10);
}
////Dimitri
/* return string representation of num in base rad as new string (or NULL) */
char *dmitri_toBaseWhatever(int num, int rad)
{
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int i;
char buf[66]; /* enough space for any 64-bit in base 2 */
buf[0]=0;
/* bounds check for radix */
if (rad < 2 || rad > 62)
return NULL;
/* if num is zero */
if (!num)
return StrDup("0");
//return strdup("0");
/* null terminate buf, and set i at end */
buf[65] = '\0';
i = 65;
if (num > 0) { /* if positive... */
while (num) { /* until num is 0... */
/* go left 1 digit, divide by radix, and set digit to remainder */
buf[--i] = digits[num % rad];
num /= rad;
}
} else { /* same for negative, but negate the modulus and prefix a '-' */
while (num) {
buf[--i] = digits[-(num % rad)];
num /= rad;
}
buf[--i] = '-';
}
/* return a duplicate of the used portion of buf */
return StrDup(buf + i);
//return strdup(buf + i);
}
void delaySome(void) //test the timer
{
time_t x = clock();
while ((clock() - x)<1000);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With