如何将任意大整数从基数10转换为基数16?

时间:2009-05-13 09:53:16

标签: c base

程序需要输入任意大的无符号整数,该整数在基数10中表示为一个字符串。输出是另一个表示基数为16的整数的字符串。

例如,输入为“1234567890987654321234567890987654321234567890987654321”, 输出应为“CE3B5A137DD015278E09864703E4FF9952FF6B62C1CB1”

算法越快越好。

如果输入限制在32位或64位整数范围内,那将非常容易;例如,以下代码可以进行转换:

#define MAX_BUFFER 16
char hex[] = "0123456789ABCDEF";

char* dec2hex(unsigned input) {
    char buff[MAX_BUFFER];
    int i = 0, j = 0;
    char* output;

    if (input == 0) {
        buff[0] = hex[0];
        i = 1;
    } else {
        while (input) {
            buff[i++] = hex[input % 16];
            input = input / 16;
        }
    }

    output = malloc((i + 1) * sizeof(char));
    if (!output) 
        return NULL;

    while (i > 0) {
        output[j++] = buff[--i];        
    }
    output[j] = '\0';

    return output;
}

真正具有挑战性的部分是“任意大”无符号整数。我用谷歌搜索,但大多数人都在谈论32位或64位的转换。没有找到运气。

任何人都可以给任何点击或任何可以阅读的链接吗?

提前致谢。

编辑这是我最近遇到的一个面试问题。谁能简单解释一下如何解决这个问题?我知道有一个gmp库,我之前使用过它;但作为面试问题,它不需要使用外部库。

7 个答案:

答案 0 :(得分:11)

  1. 分配整数数组,元素数等于输入字符串的长度。将数组初始化为全0。

    这个整数数组将值存储在16位。

  2. 将输入字符串中的十进制数字添加到数组的末尾。 Mulitply现有值加10个结转,在数组中存储新值,新的结转值为newvalue div 16.

    carryover = digit;
    for (i = (nElements-1); i >= 0; i--)
    {
        newVal = array[index] * 10) + carryover;
        array[index] = newval % 16;
        carryover = newval / 16;
    }
    
  3. 打印数组,从第0个条目开始并跳过前导0。


  4. 这里有一些可行的代码。毫无疑问,可能会有一些优化。但这应该是一个快速而肮脏的解决方案:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "sys/types.h"
    
    char HexChar [16] = { '0', '1', '2', '3', '4', '5', '6', '7',
                          '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    
    static int * initHexArray (char * pDecStr, int * pnElements);
    
    static void addDecValue (int * pMyArray, int nElements, int value);
    static void printHexArray (int * pHexArray, int nElements);
    
    static void
    addDecValue (int * pHexArray, int nElements, int value)
    {
        int carryover = value;
        int tmp = 0;
        int i;
    
        /* start at the bottom of the array and work towards the top
         *
         * multiply the existing array value by 10, then add new value.
         * carry over remainder as you work back towards the top of the array
         */
        for (i = (nElements-1); (i >= 0); i--)
        {
            tmp = (pHexArray[i] * 10) + carryover;
            pHexArray[i] = tmp % 16;
            carryover = tmp / 16;
        }
    }
    
    static int *
    initHexArray (char * pDecStr, int * pnElements)
    {
        int * pArray = NULL;
        int lenDecStr = strlen (pDecStr);
        int i;
    
        /* allocate an array of integer values to store intermediate results
         * only need as many as the input string as going from base 10 to
         * base 16 will never result in a larger number of digits, but for values
         * less than "16" will use the same number
         */
    
        pArray = (int *) calloc (lenDecStr,  sizeof (int));
    
        for (i = 0; i < lenDecStr; i++)
        {
            addDecValue (pArray, lenDecStr, pDecStr[i] - '0');
        }
    
        *pnElements = lenDecStr;
    
        return (pArray);
    }
    
    static void
    printHexArray (int * pHexArray, int nElements)
    {
        int start = 0;
        int i;
    
        /* skip all the leading 0s */
        while ((pHexArray[start] == 0) && (start < (nElements-1)))
        {
            start++;
        }
    
        for (i = start; i < nElements; i++)
        {
            printf ("%c", HexChar[pHexArray[i]]);
        }
    
        printf ("\n");
    }
    
    int
    main (int argc, char * argv[])
    {
        int i;
        int * pMyArray = NULL;
        int nElements;
    
        if (argc < 2)
        {
            printf ("Usage: %s decimalString\n", argv[0]);
            return (-1);
        }
    
        pMyArray = initHexArray (argv[1], &nElements);
    
        printHexArray (pMyArray, nElements);
    
        if (pMyArray != NULL)
            free (pMyArray);
    
        return (0);
    }
    

答案 1 :(得分:3)

我编写了一个article,它描述了一个简单的Python解决方案,可用于从一系列数字转换为任意数字基数。我最初在C中实现了解决方案,并且我不希望依赖于外部库。我认为你应该能够用C语言或任何你喜欢的方式重写非常简单的Python代码。

这是Python代码:

import math
import string

def incNumberByValue(digits, base, value):
   # The initial overflow is the 'value' to add to the number.
   overflow = value
   # Traverse list of digits in reverse order.
   for i in reversed(xrange(len(digits))):
      # If there is no overflow we can stop overflow propagation to next higher digit(s).
      if not overflow:
         return
      sum = digits[i] + overflow
      digits[i] = sum % base
      overflow = sum / base

def multNumberByValue(digits, base, value):
   overflow = 0
   # Traverse list of digits in reverse order.
   for i in reversed(xrange(len(digits))):
      tmp = (digits[i] * value) + overflow
      digits[i] = tmp % base
      overflow = tmp / base

def convertNumber(srcDigits, srcBase, destDigits, destBase):
   for srcDigit in srcDigits:
      multNumberByValue(destDigits, destBase, srcBase)
      incNumberByValue(destDigits, destBase, srcDigit)

def withoutLeadingZeros(digits):
   for i in xrange(len(digits)):
      if digits[i] != 0:
         break
   return digits[i:]

def convertNumberExt(srcDigits, srcBase, destBase):
   # Generate a list of zero's which is long enough to hold the destination number.
   destDigits = [0] * int(math.ceil(len(srcDigits)*math.log(srcBase)/math.log(destBase)))
   # Do conversion.
   convertNumber(srcDigits, srcBase, destDigits, destBase)
   # Return result (without leading zeros).
   return withoutLeadingZeros(destDigits)


# Example: Convert base 10 to base 16
base10 = [int(c) for c in '1234567890987654321234567890987654321234567890987654321']
base16 = convertNumberExt(base10, 10, 16)
# Output list of base 16 digits as HEX string.
hexDigits = '0123456789ABCDEF'
string.join((hexDigits[n] for n in base16), '')

答案 2 :(得分:2)

  

真正具有挑战性的部分是“任意大的”无符号整数。

您是否尝试过使用GNU MP Bignum库?

答案 3 :(得分:1)

这是一个BigInt库:

http://www.codeproject.com/KB/cs/BigInt.aspx?msg=3038072#xx3038072xx

不知道它是否有效,但它是我在Google上找到的第一个。它似乎具有解析和格式化大整数的函数,因此它们也可以支持不同的基础。

编辑:啊,你正在使用C,我的错误。但是你可以从代码中获取想法,或者使用.NET的人可能有同样的问题,所以我会把它留在这里。

答案 4 :(得分:1)

Unix dc能够对任意大整数进行基本转换。开放BSD源代码可用here

答案 5 :(得分:0)

的Python:

>>> from string import upper
>>> input = "1234567890987654321234567890987654321234567890987654321"
>>> output = upper(hex(int(input)))[2:-1]
>>> print output
CE3B5A137DD015278E09864703E4FF9952FF6B62C1CB1

答案 6 :(得分:0)

以下是用javascript实现的上述算法:

function addDecValue(hexArray, value) {
  let carryover = value;
  for (let i = (hexArray.length - 1); i >= 0; i--) {
    let rawDigit = ((hexArray[i] || 0) * 10) + carryover;
    hexArray[i] = rawDigit % 16;
    carryover = Math.floor(rawDigit / 16);
  }
}

function toHexArray(decimalString) {
  let hexArray = new Array(decimalString.length);
  for (let i = 0; i < decimalString.length; i++) {
    addDecValue(hexArray, Number(decimalString.charAt(i)));
  }
  return hexArray;
}

function toHexString(hexArray) {
  const hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'];
  let result = '';
  for (let i = 0; i < hexArray.length; i++) {
    if (result === '' && hexArray[i] === 0) continue;
    result += hexDigits[hexArray[i]];
  }
  return result
}

toHexString(toHexArray('1234567890987654321234567890987654321234567890987654321'));