Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a Decimal to Any Radix Base Number? [closed]

Tags:

c++

c

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

like image 885
flylib Avatar asked Sep 28 '13 22:09

flylib


People also ask

How do you convert a decimal number into a number in any other system with base B?

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.


3 Answers

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);
    }
like image 43
willus Avatar answered Oct 09 '22 20:10

willus


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);
}
like image 125
Dmitri Avatar answered Oct 09 '22 22:10

Dmitri


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:
enter image description here

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); 
}
like image 2
ryyker Avatar answered Oct 09 '22 21:10

ryyker