以二进制转换为十进制的最快方法? [英] Fastest way to convert binary to decimal?

查看:297
本文介绍了以二进制转换为十进制的最快方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经有四个32位无符号整数重新presenting一个无符号的128位整数,用little endian顺序为:

  typedef结构{
    无符号整数部分[4];
} bigint_t;

我想这个数字转换成十进制字符串重新presentation并输出到一个文件中。

现在,我使用的是 bigint_divmod10 函数通过10来划分的数量,跟踪的其余部分。我反复调用此函数,输出其余部分作为一个数字,直到数为零。这是pretty缓慢。这是做的最快方法?如果是这样,有没有办法实现这个功能了,我没有看到一个聪明的办法?我试着寻找GMP的 get_str.c ,但我觉得它pretty坚不可摧的。

编辑:这里的最快的code,我能够拿出的divmod10功能:

 静态无符号uint128_divmod10(uint128 *值)
{
    unsigned int类型A =值 - >字[3];
    unsigned int类型B =值 - >字[2];
    unsigned int类型C =值 - >字[1];
    unsigned int类型D =值 - >字[0];    无符号整型天后= A / 5;
    unsigned int类型DIVB = B / 10;
    unsigned int类型DIVC = C / 5;
    unsigned int类型divd = D / 5;    值 - >字[3] =天后;
    值 - >字[2] = DIVB;
    值 - >字[1] = DIVC;
    值 - >字[0] = divd;    unsigned int类型MODA = A - 耍大牌* 5;
    unsigned int类型MODB = B - DIVB * 5;
    unsigned int类型的MoDC = C - DIVC * 5;
    unsigned int类型MODD = D - divd * 5;    unsigned int类型MOD = 0;
    MOD + = MODA;
    unsigned int类型carryb = MOD * 858993459;
    MOD + = MODB;
    如果(MOD> = 5){
        MOD - = 5;
        carryb ++;
    }
    unsigned int类型carryc = MOD * 858993459;
    MOD + =的MoDC;
    如果(MOD> = 5){
        MOD - = 5;
        carryc ++;
    }
    unsigned int类型carryd = MOD * 858993459;
    MOD + = MODD;
    如果(MOD> = 5){
        MOD - = 5;
        carryd ++;
    }    uint128_add(值,carryd,0);
    uint128_add(值,carryc,1);
    uint128_add(值,carryb,2);    如果(值 - >字[0]&放大器; 1){
        MOD + = 5;
    }
    uint128_shift(值,-1);
    返回MOD;
}

,其中附加功能定义为:

 静态无效uint128_add(uint128 *值,无符号整型K,无符号整型POS)
{
    unsigned int类型A =值 - >字[POS]
    值 - >字[POS] + = K;
    如果(值 - >字[POS]< A){
        //溢出
        的for(int i = POS + 1; I< 4;我++){
            值 - >字[I] ++;
            如果(值 - >字[I]){
                打破;
            }
        }
    }
}


解决方案

这要看你用数字做什么。你可以权衡的空间利用率和多precision运算效率的适度损失轻微损失,以换取非常有效的转换和从小数。关键是要进行多precision算术与碱是10的幂而不是2的幂。

例如,您可以使用基地万家,在那里你包一个数字变成16位字,你做你的算法在32位整数位。 (如果你是一个64位的机器上,你可以倍增,做基地10亿)。这种code是比较有效的时间上,虽然不太一样快,使用两个原生的权力,因为你不能采取对硬件进位的优势。
而无法重新present如在相同的比特数的许多整数。
但它在转换和从十进制高手,因为你到了单个数字转换没有任何长除法。

如果您需要将全方位从零号重新present到((1 <<;&LT; 128) - 1),你仍然可以做这一点,但添加一个额外的数字,让您的数字将更大。

如果事实证明你确实需要额外的空间/转速(也许你做了很多加密128位计算),那么点大DIV / MOD的10方法是我知道的最快方法。其他唯一的诀窍是,如果小整数是常见的,你可以专门处理它们。 (也就是说,如果三个最显著32位字都为零,只需用本机师进行转换。)


  

有没有办法实现这个功能了,我没有看到一个聪明的办法?


戴夫·汉森的 I2C接口和实现对多$ P $一个漫长的篇章pcision算术。由一个单一的数字除以大量是具有这种高效实现一种特殊情况:

  INT XP_quotient(INT N,T Z,的T x,int y)对{
    INT I;
    无符号的进位= 0;
    对于(i = N - 1; I&GT; = 0;我 - ){
        携带携带= * BASE + X [I]
        Z [i] =进/年;
        携带%= Y;
    }
    返回矣;
}

有关充分的认识,它确实有助于有这本书,但是的来源$ C ​​$ C 仍然是一个更容易理解比GNU源$ C ​​$ C。而你可以轻松地适应其使用基地10,000(它目前使用基地256)。

摘要:如果你的性能瓶颈是转换为十进制,实施多precision了基础,为10 功率计算。如果你的机器的本地字大小为32,使用的是C&NBSP; code,使用万&NBSP;以16位字

I've got four unsigned 32-bit integers representing an unsigned 128-bit integer, in little endian order:

typedef struct {
    unsigned int part[4];
} bigint_t;

I'd like to convert this number into its decimal string representation and output it to a file.

Right now, I'm using a bigint_divmod10 function to divide the number by 10, keeping track of the remainder. I call this function repeatedly, outputting the remainder as a digit, until the number is zero. It's pretty slow. Is this the fastest way to do it? If so, is there a clever way to implement this function that I'm not seeing? I've tried looking at GMP's get_str.c, but I find it pretty impenetrable.

EDIT: here's the fastest code I was able to come up with for the divmod10 function:

static unsigned uint128_divmod10(uint128 *value)
{
    unsigned int a = value->word[3];
    unsigned int b = value->word[2];
    unsigned int c = value->word[1];
    unsigned int d = value->word[0];

    unsigned int diva = a / 5;
    unsigned int divb = b / 5;
    unsigned int divc = c / 5;
    unsigned int divd = d / 5;

    value->word[3] = diva;
    value->word[2] = divb;
    value->word[1] = divc;
    value->word[0] = divd;

    unsigned int moda = a - diva*5;
    unsigned int modb = b - divb*5;
    unsigned int modc = c - divc*5;
    unsigned int modd = d - divd*5;

    unsigned int mod = 0;
    mod += moda;
    unsigned int carryb = mod*858993459;
    mod += modb;
    if (mod >= 5) {
        mod -= 5;
        carryb++;
    }
    unsigned int carryc = mod*858993459;
    mod += modc;
    if (mod >= 5) {
        mod -= 5;
        carryc++;
    }
    unsigned int carryd = mod*858993459;
    mod += modd;
    if (mod >= 5) {
        mod -= 5;
        carryd++;
    }

    uint128_add(value, carryd, 0);
    uint128_add(value, carryc, 1);
    uint128_add(value, carryb, 2);

    if (value->word[0] & 1) {
        mod += 5;
    }
    uint128_shift(value, -1);
    return mod;
}

where the add function is defined as:

static void uint128_add(uint128 *value, unsigned int k, unsigned int pos)
{
    unsigned int a = value->word[pos];
    value->word[pos] += k;
    if (value->word[pos] < a) {
        // overflow
        for (int i=pos+1; i<4; i++) {
            value->word[i]++;
            if (value->word[i]) {
                break;
            }
        }
    }
}

解决方案

It depends what else you're doing with the numbers. You can trade off a slight loss in space efficiency and a modest loss in efficiency of multiprecision arithmetic in return for very efficient conversion to and from decimal. The key is to do multiprecision arithmetic with a base that is a power of 10 rather than a power of 2.

For example, you might use base 10,000, where you pack one digit into a 16-bit word and you do your arithmetic on digits in 32-bit integers. (If you're on a 64-bit machine you can double that and do base 1,000,000,000.) This kind of code is relatively efficient timewise, although not quite as fast as using the native power of two because you can't take advantage of the carry bit on the hardware. And you can't represent as many integers in the same number of bits. But it's a whiz at converting to and from decimal, because you get to convert the individual digits without any long division.

If you need to represent the full range of numbers from zero to ((1 << 128) - 1), you can still do this, but add an extra digit, so your numbers will be bigger.

If it turns out you really need the extra space/speed (maybe you're doing a lot of cryptographic 128-bit calculations) then the method of simultanous div/mod by 10 is the fastest method I know. The only other trick is that if small integers are common, you can handle them specially. (That is, if the three most significant 32-bit words are all zero, just use the native division to convert.)

Is there a clever way to implement this function that I'm not seeing?

Dave Hanson's C Interfaces and Implementations has a lengthy chapter on multiprecision arithmetic. Dividing a large number by a single digit is a special case that has this efficient implementation:

int XP_quotient(int n, T z, T x, int y) {
    int i;
    unsigned carry = 0;
    for (i = n - 1; i >= 0; i--) {
        carry = carry*BASE + x[i];
        z[i] = carry/y;
        carry %= y;
    }
    return carry;
}

For full understanding, it really helps to have the book, but the source code is still a lot easier to understand than the GNU source code. And you could easily adapt it to use base 10,000 (it currently uses base 256).

Summary: if your performance bottleneck is conversion to decimal, implement multiprecision arithmetic with a base that is a power of 10. If your machine's native word size is 32 and you are using C code, use 10,000 in a 16-bit word.

这篇关于以二进制转换为十进制的最快方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆