将十进制转换为任何Radix基数?

时间:2013-09-28 22:29:02

标签: c++ c

我知道' strtoll'但是这会将任何Radix Base Number(2到36之间)转换为Decimal,我需要通过将Decimal转换为Any Radix Base Number来执行相反的操作,

一个例子是十进制130基数12 = AA

3 个答案:

答案 0 :(得分:5)

以下代码使用临时缓冲区来构建字符串,然后返回重复项。该字符串是通过从末尾向后工作并通过索引到另一个字符串来设置每个数字来构建的。这应该比重复短字符串复制和附加Java版本更有效。当你完成它们时你需要释放返回的字符串,并且如果基数可能超出范围则检查NULL返回...以避免在你可能想要调整它以使用它时始终分配新字符串你提供的缓冲结果。

/* 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);
}

答案 1 :(得分:2)

如果您不需要创建自己的,'strtoll'或'strtoull'将为您进行转换:

   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);  

[编辑] 这个编辑是对@willus关于他和@ dmitri解决方案之间时间安排的评论的回应(纯粹是为了好玩),并在混音中添加了第三个。
就纯粹的速度而言,德米特里的产品赢得了手,但包括内存泄漏。它以不释放内存的方式使用strdup()函数。 strdupa()是一种可以释放其分配的内存的替代方案,并且在这里是一个很好的替代品。并且,如果根本没有使用strdup()strdupa(),@ Dmitri的代码(由@willus指出)将运行得更快。

感谢 this implementation AnyRadixConvert 函数。

以下是三个贯穿整数0 - 5001的每一个的结果:
enter image description here

以下是产生这些结果的代码:( _note:存在微小变化,例如我没有strdup(),但有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); 
}

答案 2 :(得分:2)

试试这个。

#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);
    }