C:在基数10中打印一个BigInteger

时间:2010-12-05 21:50:09

标签: c biginteger division integer-division

我使用这个结构来表示128位整数:

typedef struct {
    uint64_t low, high;
} uint128;

(除非你能指出一个快速的128位整数库,我无法改变它)

现在我想使用printf在基数10中打印这样的值。我可能需要除以10才能做到这一点,但尚未实施任何划分。

我该怎么做?只要有效,解决方案就不一定非常有效。

编辑:我喜欢你提出的所有解决方案。你太棒了。

4 个答案:

答案 0 :(得分:3)

如果您不想为128位值实现除法,可以预先计算几个(~40)128位值,表示10的幂,并使用减法。

实际上只有更高的qword才能以这种方式处理,因为对于较低的部分,你可以使用printf("%I64d")

编辑:这是一个示例(它将仅使用#{1}}上的算术打印short

char

您可以使用较少数量的预先计算的10次幂,但会使其变慢(例如,以100为步长使unsigned char pow10[][2] = { {0, 1}, // 1 {0, 10}, // 10 {0, 100}, // 100 {3, 0xE8}, // 1k {0x27, 0x10}}; // 10k == 0x2710 #define HIGH 0 #define LOW 1 void print_dec(unsigned char H, unsigned char L){ unsigned char L1; int pwr = 4, ctr = 0; while (pwr >= 0){ int c = pow10[pwr][LOW] > L; L1 = L - pow10[pwr][LOW]; if (H >= pow10[pwr][HIGH] + c){ H -= pow10[pwr][HIGH] + c; L = L1; ctr++; } else { printf("%d", ctr); ctr = 0; pwr--; //here we could add a check for H to be 0, so that we could use //printf() for lower half. we just have to be careful with //leading zeroes in L, the simpliest way is to use printf("%03d",L) }; }; printf("\n"); }; int main(){ unsigned short n = 12345; printf("%d should be ", n); print_dec((n >> 8) & 0xFF, n & 0xFF); return 0; }; 处于ctr范围内。

答案 1 :(得分:3)

void printu128(uint128 n) {
  int d[39] = {0}, i, j;
  for (i = 63; i > -1; i--) {
    if ((n.high >> i) & 1) d[0]++;
    for (j = 0; j < 39; j++) d[j] *= 2;
    for (j = 0; j < 38; j++) d[j+1] += d[j]/10, d[j] %= 10;
  }
  for (i = 63; i > -1; i--) {
    if ((n.low >> i) & 1) d[0]++;
    if (i > 0) for (j = 0; j < 39; j++) d[j] *= 2;
    for (j = 0; j < 38; j++) d[j+1] += d[j]/10, d[j] %= 10;
  }
  for (i = 38; i > 0; i--) if (d[i] > 0) break;
  for (; i > -1; i--) putchar('0'+d[i]);
}

答案 2 :(得分:2)

假设您已经实现了在uint128上执行数学运算的功能,您可以将数字分成3个部分并使用printf的内置64位打印功能。由于最大的64位数字是20位数字,这意味着所有19位十进制数字都可以这样打印,但由于最大的128位数字是39位数字,我们不能将它分成只有2个部分,因为我们有可能最终得到一个比最大的64位数字大20位的数字。

这是一种方法,首先除以10 20 得到一个不大于3,402,823,669,209,384,634的商。然后我们将剩余部分(本身不大于10 20 )除以10 10 得到另一个商,其余每个小于10 20 ,其中两者都适合64位整数。

void print_uint128(uint128 value)
{
    // First power of 10 larger than 2^64
    static const uint128 tenToThe20 = {7766279631452241920ull, 5ull};
    static const uint128 tenToThe10 = {10000000000ull, 0ull};

    // Do a 128-bit division; assume we have functions to divide, multiply, and
    // subtract 128-bit numbers
    uint128 quotient1 = div128(value, tenToThe20);
    uint128 remainder1 = sub128(value, mul128(quotient, tenToThe20));
    uint128 quotient2 = div128(remainder1, tenToThe10);
    uint128 remainder2 = sub128(remainder1, mul128(remainder1, tenToThe10));

    // Now print out theresult in 3 parts, being careful not to print
    // unnecessary leading 0's
    if(quotient1.low != 0)
        printf("%llu%010llu%010llu", quotient1.low, quotient2.low, remainder2.low);
    else if(quotient2.low != 0)
        printf("%llu%010llu", quotient2.low, remainder2.low);
    else
        printf("%llu", remainder2.low);
}

答案 3 :(得分:1)

您可以使用乘法来打印数字。

  1. 当2 128 约为340E36时,首先通过将数字与100E36,200E36和300E36边界进行比较来确定前导数字。写一个数字并减去最近的较小边界。 E. g。如果数字是234.6776E36,那么最近的较小的边界是200E36,数字是'2',减去后你应该得到34.6776E36。

  2. 现在使用与数字10E36 ... 90E36的比较获得下一个数字。当然是128位比较。写一个数字并减去最小的边界,如上所述。 (对于34.6776E36,以上数字为'3',边界为30E36,余数为4.6776E36)

  3. 然后将数字乘以10并从第2阶段重复,共计38次以打印每个数字。 (4.6776E36 - &gt; 46.776E36 ......)

  4. UPD:添加了我先错过的减法。和例子。

    UPD2:对于1位数字的专用步骤的需要是因为如果你将它旁边的数字相乘,你应该得到溢出,如果余数大于34E36。