我使用这个结构来表示128位整数:
typedef struct {
uint64_t low, high;
} uint128;
(除非你能指出一个快速的128位整数库,我无法改变它)
现在我想使用printf
在基数10中打印这样的值。我可能需要除以10才能做到这一点,但尚未实施任何划分。
我该怎么做?只要有效,解决方案就不一定非常有效。
编辑:我喜欢你提出的所有解决方案。你太棒了。答案 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)
您可以使用乘法来打印数字。
当2 128 约为340E36时,首先通过将数字与100E36,200E36和300E36边界进行比较来确定前导数字。写一个数字并减去最近的较小边界。 E. g。如果数字是234.6776E36,那么最近的较小的边界是200E36,数字是'2',减去后你应该得到34.6776E36。
现在使用与数字10E36 ... 90E36的比较获得下一个数字。当然是128位比较。写一个数字并减去最小的边界,如上所述。 (对于34.6776E36,以上数字为'3',边界为30E36,余数为4.6776E36)
然后将数字乘以10并从第2阶段重复,共计38次以打印每个数字。 (4.6776E36 - &gt; 46.776E36 ......)
UPD:添加了我先错过的减法。和例子。
UPD2:对于1位数字的专用步骤的需要是因为如果你将它旁边的数字相乘,你应该得到溢出,如果余数大于34E36。