手工實現整除除法的比較

lt發表於2016-12-21
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
int test(int(*p)(int,int),const char s[],int a,int b)
{
    int t=clock();
    int c=p(a,b);
    printf("%s %ld ms\n",s,clock()-t);
    fflush(stdout);
    return c;
}
int divide(int a,int b)
{
    int s=1;
    while((a-(s)*b)>=0)
        s++;
    return s-1;
}

int divide2(int a,int b)
{
    int s=0;
    char ca[20];
    char cb[20];
    itoa(a,ca,10);
    itoa(b,cb,10);
    int t=strlen(ca)-strlen(cb);
    s=1;
    while(t-->1)s=10*s;
    printf("s=%d\n",s);
    while((a-(s)*b)>=0)
        s++;
    return s-1;
}
int divide3(int a,int b)
{
    int s=0;
    char ca[20];
    char cb[20];
    itoa(a,ca,10);
    itoa(b,cb,10);
    int t=strlen(ca)-strlen(cb);
    s=1;
    while(t-->1)s=10*s;
    printf("s=%d\n",s);
    int s0=s;
    while(a-s*b>=0)s=s+s0;
    s-=s0;
    printf("s=%d\n",s);
    while((a-(s)*b)>=0)
        s++;
    return s-1;
}
int main()
{
    int a=20e8,b=7;
    int c1=test(divide,"method 1",a,b);
    int c2=test(divide2,"method 2",a,b);
    int c3=test(divide3,"method 3",a,b);
    int c=a/b;
    printf("%d %d %d %d %d %d",a,b,c,c1,c2,c3);
    return 0;
}
---
D:\>a
method 1 4118 ms
s=100000000
method 2 3760 ms
s=100000000
s=1000000000
method 3 202 ms
2100000000 2 1050000000 1050000000 1050000000 1050000000
D:\>g++ divide.c

D:\>a
method 1 1107 ms
s=100000000
method 2 733 ms
s=100000000
s=200000000
method 3 328 ms
2000000000 7 285714285 285714285 285714285 285714285

方法1直接減去除數,方法2好一些,方法3再好一些。

int divide4(int a,int b)
{
    int s=1;
    char ca[20];
    char cb[20];
    int x[20];
    itoa(a,ca,10);
    itoa(b,cb,10);
    int t=strlen(ca)-strlen(cb);
    x[0]=1;
    for(int i=1;i<t;i++)
    {
        x[i]=10*x[i-1];

    }
    t--;

    while(t>=0)
    {

     a-=x[t]*b;
     s+=x[t];

     if(a<b)
     {
         a+=x[t]*b;
         s-=x[t];
         t--;
     }
    }
    return s;
}
---
D:\>g++ divide.c

D:\>a
method 1 470 ms
s=10000000
method 2 430 ms
s=10000000
s=110000000
method 3 30 ms
method 4 0 ms
2000000000 17 117647058 117647058 117647058 117647058 117647058
D:\>g++ divide.c

D:\>a
method 1 1150 ms
s=100000000
method 2 740 ms
s=100000000
s=200000000
method 3 330 ms
method 4 0 ms
2000000000 7 285714285 285714285 285714285 285714285 285714285

下面是https://github.com/soulmachine/acm-cheat-sheet 中提供的大數除法程式,思路與方法4類似.

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

#define BIGINT_RADIX 10000
#define RADIX_LEN 4
#define MAX_LEN (100/RADIX_LEN+1)
char a[MAX_LEN * RADIX_LEN], b[MAX_LEN * RADIX_LEN];
int x[MAX_LEN], y[MAX_LEN], z[MAX_LEN];


void bigint_print(const int x[], const int n)
{
    int i;
    int start_output = 0;
    for (i = n - 1; i >= 0; --i)
    {
        if (start_output)
        {
            printf("%04d", x[i]);
        }
        else if (x[i] > 0)
        {
            printf("%d", x[i]);
            start_output = 1;
        }
    }
    if(!start_output) printf("0");
}

void bigint_input(const char s[], int x[])
{
    int i, j = 0;
    const int len = strlen(s);
    for (i = 0; i < MAX_LEN; i++) x[i] = 0;
// for (i = len - 1; i >= 0; i--) a[j++] = s[i] - '0';
    for (i = len; i > 0; i -= RADIX_LEN)   /* [i-RADIX_LEN, i) */
    {
        int temp = 0;
        int k;
        const int low = i-RADIX_LEN > 0 ? i-RADIX_LEN : 0;
        for (k = low; k < i; k++)
        {
            temp = temp * 10 + s[k] - '0';
        }
        x[j++] = temp;
    }
}
static int length(const int x[])
{
    int i;
    int result = 0;
    for (i = MAX_LEN - 1; i >= 0; i--) if (x[i] > 0)
        {
            result = i + 1;
            break;
        }
    return result;
}
static int bigint_sub(int x[], const int y[])
{
    int i;
    const int lenx = length(x);
    const int leny = length(y);

    if (lenx < leny) return -1;
    else if (lenx == leny)
    {
        int larger = 0;
        for (i = lenx - 1; i >= 0; i--)
        {
            if (x[i] > y[i])
            {
                larger = 1;
            }
            else if (x[i] < y[i])
            {
                if (!larger) return -1;
            }
        }
    }
    for (i = 0; i < MAX_LEN; i++)
    {
        x[i] -= y[i];
        if (x[i] < 0)
        {
            x[i] += BIGINT_RADIX;
            x[i+1] --;
        }
    }
    return 1;
}


void bigint_div(int x[], const int y[], int z[])
{
    int i;
    int *yy;
    const int xlen = length(x);
    int ylen = length(y);
    const int times = xlen - ylen;
    for (i = 0; i < MAX_LEN; i++) z[i] = 0;
    if (times < 0) return;
    yy = (int*)malloc(sizeof(int) * MAX_LEN);
    memcpy(yy, y, sizeof(int) * MAX_LEN);

    for (i = xlen - 1; i >= 0; i--)
    {
        if (i >= times) yy[i] = yy[i - times];
        else yy[i] = 0;
    }
    ylen = xlen;
    for (i = 0; i <= times; i++)
    {
        int j;
        while (bigint_sub(x, yy) >= 0)
        {
            z[times - i]++;
        }

        for (j = 1; j < ylen; j++)
        {
            yy[j - 1] = yy[j];
        }
        yy[--ylen] = 0;
    }

    for (i = 0; i < MAX_LEN - 1; i++)
    {
        if (z[i] >= BIGINT_RADIX)
        {
            z[i+1] += z[i] / BIGINT_RADIX;
            z[i] %= BIGINT_RADIX;
        }
    }
    free(yy);
}
int main()
{
    int T;
    scanf("%d", &T);
    while (T-- > 0)
    {
        scanf("%s%s",a,b);
        bigint_input(a, x);
        bigint_input(b, y);
        bigint_div(x, y, z);
        bigint_print(z, MAX_LEN);
        printf("\n");
    }
    return 0;
}

----
D:\>g++ bigdiv.cpp

D:\>a
3
1 2
0
1000000000000000000000 7
142857142857142857142
976000094000000000000000000000 563493904
1732050847527890913971

相關文章