如何在C语言中将128位整数转换为十进制ascii字符串?

如何在C语言中将128位整数转换为十进制ascii字符串?,c,string,int,ascii,C,String,Int,Ascii,我正在尝试将存储为4个无符号整数数组的128位无符号整数转换为C中的十进制字符串表示形式: unsigned int src[] = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 }; printf("%s", some_func(src)); // gives "53072739890371098123344" (上面的输入和输出示例完全是虚构的;我不知道输入会产生什么。) 如果我要使用十六进制、二进制或八进制,这将是一个简单的问题,即屏蔽和

我正在尝试将存储为4个无符号整数数组的128位无符号整数转换为C中的十进制字符串表示形式:

unsigned int src[] = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
printf("%s", some_func(src)); // gives "53072739890371098123344"
(上面的输入和输出示例完全是虚构的;我不知道输入会产生什么。)


如果我要使用十六进制、二进制或八进制,这将是一个简单的问题,即屏蔽和位移位来剥离最不重要的字符。然而,在我看来,我需要做10基地师。不幸的是,我不记得如何跨多个int执行此操作,而且我使用的系统不支持大于32位的数据类型,因此不可能使用128位类型。使用不同的语言也是不可能的,我宁愿为了这一个操作而避免使用大的数字库。

实际上不需要实现长除法。您需要实现二次幂的乘法和加法。您有四个
uint\u 32
。首先将它们转换为字符串。将它们分别乘以
(2^32)^3
(2^32)^2
(2^32)^1
,和
(2^32)^0
,然后将它们相加。你不需要做基础转换,你只需要处理把四个部分放在一起。显然,您需要确保字符串可以处理高达
UINT_32_MAX*(2^32)^3的数字

一种缓慢但简单的方法是使用减法从最高有效到最低有效打印数字。基本上,您需要一个函数来检查
x>=y
,在这种情况下,还需要另一个函数来计算
x-=y
。 然后你可以开始计算减去10^38的次数(这将是最有效的数字),然后计算减去10^37的次数。。。减少到你可以减去1的次数

以下是该方法的全面实施:

#include <stdio.h>

typedef unsigned ui128[4];

int ge128(ui128 a, ui128 b)
{
    int i = 3;
    while (i >= 0 && a[i] == b[i])
        --i;
    return i < 0 ? 1 : a[i] >= b[i];
}

void sub128(ui128 a, ui128 b)
{
    int i = 0;
    int borrow = 0;
    while (i < 4)
    {
        int next_borrow = (borrow && a[i] <= b[i]) || (!borrow && a[i] < b[i]);
        a[i] -= b[i] + borrow;
        borrow = next_borrow;
        i += 1;
    }
}

ui128 deci128[] = {{1u,0u,0u,0u},
                   {10u,0u,0u,0u},
                   {100u,0u,0u,0u},
                   {1000u,0u,0u,0u},
                   {10000u,0u,0u,0u},
                   {100000u,0u,0u,0u},
                   {1000000u,0u,0u,0u},
                   {10000000u,0u,0u,0u},
                   {100000000u,0u,0u,0u},
                   {1000000000u,0u,0u,0u},
                   {1410065408u,2u,0u,0u},
                   {1215752192u,23u,0u,0u},
                   {3567587328u,232u,0u,0u},
                   {1316134912u,2328u,0u,0u},
                   {276447232u,23283u,0u,0u},
                   {2764472320u,232830u,0u,0u},
                   {1874919424u,2328306u,0u,0u},
                   {1569325056u,23283064u,0u,0u},
                   {2808348672u,232830643u,0u,0u},
                   {2313682944u,2328306436u,0u,0u},
                   {1661992960u,1808227885u,5u,0u},
                   {3735027712u,902409669u,54u,0u},
                   {2990538752u,434162106u,542u,0u},
                   {4135583744u,46653770u,5421u,0u},
                   {2701131776u,466537709u,54210u,0u},
                   {1241513984u,370409800u,542101u,0u},
                   {3825205248u,3704098002u,5421010u,0u},
                   {3892314112u,2681241660u,54210108u,0u},
                   {268435456u,1042612833u,542101086u,0u},
                   {2684354560u,1836193738u,1126043566u,1u},
                   {1073741824u,1182068202u,2670501072u,12u},
                   {2147483648u,3230747430u,935206946u,126u},
                   {0u,2242703233u,762134875u,1262u},
                   {0u,952195850u,3326381459u,12621u},
                   {0u,932023908u,3199043520u,126217u},
                   {0u,730304488u,1925664130u,1262177u},
                   {0u,3008077584u,2076772117u,12621774u},
                   {0u,16004768u,3587851993u,126217744u},
                   {0u,160047680u,1518781562u,1262177448u}};

void print128(ui128 x)
{
    int i = 38;
    int z = 0;
    while (i >= 0)
    {
        int c = 0;
        while (ge128(x, deci128[i]))
        {
            c++; sub128(x, deci128[i]);
        }
        if (i==0 || z || c > 0)
        {
            z = 1; putchar('0' + c);
        }
        --i;
    }
}

int main(int argc, const char *argv[])
{
    ui128 test = { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 };
    print128(test);
    return 0;
}

Python同意这是正确的值(当然,这并不意味着代码是正确的!!!;-)

不需要除法:

#include <string.h>
#include <stdio.h>

typedef unsigned long uint32;

/* N[0] - contains least significant bits, N[3] - most significant */
char* Bin128ToDec(const uint32 N[4])
{
  // log10(x) = log2(x) / log2(10) ~= log2(x) / 3.322
  static char s[128 / 3 + 1 + 1];
  uint32 n[4];
  char* p = s;
  int i;

  memset(s, '0', sizeof(s) - 1);
  s[sizeof(s) - 1] = '\0';

  memcpy(n, N, sizeof(n));

  for (i = 0; i < 128; i++)
  {
    int j, carry;

    carry = (n[3] >= 0x80000000);
    // Shift n[] left, doubling it
    n[3] = ((n[3] << 1) & 0xFFFFFFFF) + (n[2] >= 0x80000000);
    n[2] = ((n[2] << 1) & 0xFFFFFFFF) + (n[1] >= 0x80000000);
    n[1] = ((n[1] << 1) & 0xFFFFFFFF) + (n[0] >= 0x80000000);
    n[0] = ((n[0] << 1) & 0xFFFFFFFF);

    // Add s[] to itself in decimal, doubling it
    for (j = sizeof(s) - 2; j >= 0; j--)
    {
      s[j] += s[j] - '0' + carry;

      carry = (s[j] > '9');

      if (carry)
      {
        s[j] -= 10;
      }
    }
  }

  while ((p[0] == '0') && (p < &s[sizeof(s) - 2]))
  {
    p++;
  }

  return p;
}

int main(void)
{
  static const uint32 testData[][4] =
  {
    { 0, 0, 0, 0 },
    { 1048576, 0, 0, 0 },
    { 0xFFFFFFFF, 0, 0, 0 },
    { 0, 1, 0, 0 },
    { 0x12345678, 0x90abcdef, 0xfedcba90, 0x8765421 }
  };
  printf("%s\n", Bin128ToDec(testData[0]));
  printf("%s\n", Bin128ToDec(testData[1]));
  printf("%s\n", Bin128ToDec(testData[2]));
  printf("%s\n", Bin128ToDec(testData[3]));
  printf("%s\n", Bin128ToDec(testData[4]));
  return 0;
}

直接除法基数2^32,按相反顺序打印十进制数字,使用64位算术,复杂性
O(n)
其中
n
是表示法中的十进制数字数:

#include <stdio.h>

unsigned int a [] = { 0x12345678, 0x12345678, 0x12345678, 0x12345678 };

/* 24197857161011715162171839636988778104 */

int
main ()
{
  unsigned long long d, r;

  do
    {
      r = a [0];

      d = r / 10;
      r = ((r - d * 10) << 32) + a [1];
      a [0] = d;

      d = r / 10;
      r = ((r - d * 10) << 32) + a [2];
      a [1] = d;

      d = r / 10;
      r = ((r - d * 10) << 32) + a [3];
      a [2] = d;

      d = r / 10;
      r = r - d * 10;
      a [3] = d;

      printf ("%d\n", (unsigned int) r);
    }
  while (a[0] || a[1] || a[2] || a[3]);

  return 0;
}
#包括
无符号整数a[]={0x12345678,0x12345678,0x12345678,0x12345678};
/* 24197857161011715162171839636988778104 */
int
主要()
{
无符号长d,r;
做
{
r=a[0];
d=r/10;

r=((r-d*10)同样的事情,但使用32位整数算法:

#include <stdio.h>

unsigned short a [] = { 
  0x0876, 0x5421,
  0xfedc, 0xba90,
  0x90ab, 0xcdef,
  0x1234, 0x5678
};

int
main ()
{
  unsigned int d, r;

  do
    {
      r = a [0];

      d = r / 10;
      r = ((r - d * 10) << 16) + a [1];
      a [0] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [2];
      a [1] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [3];
      a [2] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [4];
      a [3] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [5];
      a [4] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [6];
      a [5] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [7];
      a [6] = d;

      d = r / 10;
      r = r - d * 10;
      a [7] = d;

      printf ("%d\n", r);
    }
  while (a[0] || a[1] || a[2] || a[3] || a [4] || a [5] || a[6] || a[7]);


  return 0;
}
#包括
无符号短a[]={
0x0876,0x5421,
0xfedc,0xba90,
0x90ab,0xcdef,
0x1234,0x5678
};
int
主要()
{
无符号整数d,r;
做
{
r=a[0];
d=r/10;

r=((r-d*10)假设您有一个快速的32位乘法和除法,通过实现bigint除法/模10000,然后使用(s)printf输出数字组,一次可以计算出4位数字的结果

这种方法也很容易扩展到更高(甚至可变)的精度

#include <stdio.h>

typedef unsigned long bigint[4];

void print_bigint(bigint src)
{
    unsigned long int x[8];   // expanded version (16 bit per element)
    int result[12];           // 4 digits per element
    int done = 0;             // did we finish?
    int i = 0;                // digit group counter

    /* expand to 16-bit per element */
    x[0] = src[0] & 65535;
    x[1] = src[0] >> 16;
    x[2] = src[1] & 65535;
    x[3] = src[1] >> 16;
    x[4] = src[2] & 65535;
    x[5] = src[2] >> 16;
    x[6] = src[3] & 65535;
    x[7] = src[3] >> 16;

    while (!done)
    {
        done = 1;
        {
            unsigned long carry = 0;
            int j;
            for (j=7; j>=0; j--)
            {
                unsigned long d = (carry << 16) + x[j];
                x[j] = d / 10000;
                carry = d - x[j] * 10000;
                if (x[j]) done = 0;
            }
            result[i++] = carry;
        }
    }

    printf ("%i", result[--i]);
    while (i > 0)
    {
        printf("%04i", result[--i]);
    }
}

int main(int argc, const char *argv[])
{
    bigint tests[] = { { 0, 0, 0, 0 },
                       { 0xFFFFFFFFUL, 0, 0, 0 },
                       { 0, 1, 0, 0 },
                       { 0x12345678UL, 0x90abcdefUL, 0xfedcba90UL, 0x8765421UL } };
    {
        int i;
        for (i=0; i<4; i++)
        {
            print_bigint(tests[i]);
            printf("\n");
        }
    }
    return 0;
}
#包括
typedef无符号长整型[4];
无效打印_bigint(bigint src)
{
无符号长整型x[8];//扩展版本(每个元素16位)
int结果[12];//每个元素4位数字
int done=0;//我们完成了吗?
int i=0;//数字组计数器
/*扩展到每个元素16位*/
x[0]=src[0]&65535;
x[1]=src[0]>>16;
x[2]=src[1]&65535;
x[3]=src[1]>>16;
x[4]=src[2]&65535;
x[5]=src[2]>>16;
x[6]=src[3]&65535;
x[7]=src[3]>>16;
而(!完成)
{
完成=1;
{
无符号长进位=0;
int j;
对于(j=7;j>=0;j--)
{
无符号长d=(进位0)
{
printf(“%04i”,结果[--i]);
}
}
int main(int argc,const char*argv[]
{
bigint测试[]={{0,0,0,0},
{0xFFFFFFFFUL,0,0,0},
{ 0, 1, 0, 0 },
{0x12345678UL,0x90abcdefule,0xfedcba90UL,0x8765421UL};
{
int i;

对于(i=0;i@Alexey Frunze的方法很简单,但速度非常慢。您应该使用上面@chill的32位整数方法。另一种不带任何乘法或除法的简单方法是。这可能比chill的算法慢,但比Alexey的算法快得多。运行后,您将在github上有一个十进制数的压缩BCD

是一个开放的source项目(c++),为数据类型
uint265\u t
uint128\u t
提供一个类


不,我不是那个项目的成员,但我正是为了这个目的而使用它的,但我想它也可以对其他人有用。

如果你不想要一个bignum库,你必须自己实现长除法。它的工作原理与纸笔算法类似,只是因为它是二进制的,所以你不必进行太多的运算ses。你会发现你需要减法和移位。你确定你不想使用bignum库吗?你将自己实现一个相当完整的库。十进制是给人类的。他们在第7位之后往往会失去兴趣。这到底有什么意义?上面的内容应该如何打印出来?如“0x1234567890abcdef…”?作为十进制?@ephemient”(上面的输入和输出示例完全是虚构的;我不知道该输入会产生什么结果。)“他不知道您可以使用+1。定制的base-10 bignum库是个好主意,但“乘以2的幂”在10进制中并不特别容易。运算必须进行一般乘法。无论如何,必须实现“字符串”的乘法。也就是说,将字符串视为十进制数字并进行乘法。
无符号
不保证包含32位,16位是它所需的最小值。请使用
无符号长
,每个标准至少包含32位。我认为
#include <stdio.h>

unsigned short a [] = { 
  0x0876, 0x5421,
  0xfedc, 0xba90,
  0x90ab, 0xcdef,
  0x1234, 0x5678
};

int
main ()
{
  unsigned int d, r;

  do
    {
      r = a [0];

      d = r / 10;
      r = ((r - d * 10) << 16) + a [1];
      a [0] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [2];
      a [1] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [3];
      a [2] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [4];
      a [3] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [5];
      a [4] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [6];
      a [5] = d;

      d = r / 10;
      r = ((r - d * 10) << 16) + a [7];
      a [6] = d;

      d = r / 10;
      r = r - d * 10;
      a [7] = d;

      printf ("%d\n", r);
    }
  while (a[0] || a[1] || a[2] || a[3] || a [4] || a [5] || a[6] || a[7]);


  return 0;
}
#include <stdio.h>

typedef unsigned long bigint[4];

void print_bigint(bigint src)
{
    unsigned long int x[8];   // expanded version (16 bit per element)
    int result[12];           // 4 digits per element
    int done = 0;             // did we finish?
    int i = 0;                // digit group counter

    /* expand to 16-bit per element */
    x[0] = src[0] & 65535;
    x[1] = src[0] >> 16;
    x[2] = src[1] & 65535;
    x[3] = src[1] >> 16;
    x[4] = src[2] & 65535;
    x[5] = src[2] >> 16;
    x[6] = src[3] & 65535;
    x[7] = src[3] >> 16;

    while (!done)
    {
        done = 1;
        {
            unsigned long carry = 0;
            int j;
            for (j=7; j>=0; j--)
            {
                unsigned long d = (carry << 16) + x[j];
                x[j] = d / 10000;
                carry = d - x[j] * 10000;
                if (x[j]) done = 0;
            }
            result[i++] = carry;
        }
    }

    printf ("%i", result[--i]);
    while (i > 0)
    {
        printf("%04i", result[--i]);
    }
}

int main(int argc, const char *argv[])
{
    bigint tests[] = { { 0, 0, 0, 0 },
                       { 0xFFFFFFFFUL, 0, 0, 0 },
                       { 0, 1, 0, 0 },
                       { 0x12345678UL, 0x90abcdefUL, 0xfedcba90UL, 0x8765421UL } };
    {
        int i;
        for (i=0; i<4; i++)
        {
            print_bigint(tests[i]);
            printf("\n");
        }
    }
    return 0;
}