大规模整型无溢出无误差求均值

来源:互联网 发布:淘宝警察钱包 编辑:程序博客网 时间:2024/05/15 06:15

传统求均值的方法及缺陷:

1.(a1+a2+....+aN)/N: 如果ai较大或者N较大,会溢出。

2.a1/N+a2/N+.....+aN/N:精度有限

3.a1/N+a2/N+.....+aN/N+(a1%N+a2%N+.....+aN%N)/N;(此处a1/N只表示相除后的整数部分,%表示取余运算) 当N很大时,余数求和部分同样会溢出。

上述三种方法有一个共同缺点:只能一次性等待所有数据输入后一次性求平均,不能每读入一个数求取当前所有已读入数的均值。

本文方法:可以在读取当前数据后,及时计算当前已读入所有数据的均值,且保证不会溢出和零误差。

在用32位表示int型的系统中,signed int型的最大正整数为2147483647,程序测试了1亿个比该值略小的数的均值,结果完全正确,误差为0

主要思想:任意d个整数的均值可以 表示为avrg(d)=m+n/d. 再读入一个数X0,则(d+1)个数的均值为 d*avrg(d)/(d+1)+X0/(d+1)

有时间补充推导过程。

/************************************************************************
* File Name                : qiupingjun.c
* Copyright                : All Rights Reserved.
* Module Name            :
*
*CPU                    : X86 32_bits
*RTOS                    : windows/linux
*
* Create Date            : 2012/09/14
* Author/Corporation    : wonderyoung
*
* Abstract Description : calculate the average of large scale of big integer
*                         numbers without error.
*
*-----------------------Revision History---------------------------------
* No Version Date Revised By Item Description
* 1 V0.95 08.05.18 WhoAmI abcdefghijklm WhatUDo
*
************************************************************************/
#include<stdio.h>
#define NUM_OF_DATA 3
#define INTEGER_MAX  2147483647
typedef struct result /* a result A represents (A.m+A.n/A.d) */
{
    int m;
    int n;
    int d;
} result;

result average(int arry[],int arry_len)
{
    result tmp;
    int m=arry[0];
    int n=0,d=1,tmp_m,tmp_n;      /*(m,n,d) stand for (m+n/d)*/
    int i;
    for( i = 1; i < arry_len; i++ )
    {
        if(m%(i+1)<INTEGER_MAX/i)//(m%(i+1))*i does't overflow
        {
            n=n+(m%(i+1))*i+arry[i]%(i+1);
            m=(m/(i+1))*i+arry[i]/(i+1);
        }
        else  //(m%(i+1))*i overflow,split (m%(i+1))*i
        {
            tmp_n=n+arry[i]%(i+1)-m%(i+1);
            tmp_m=(m/(i+1))*i+arry[i]/(i+1)+m%(i+1);
            n=tmp_n;
            m=tmp_m;
        }
        d=i+1;
        if(n>=d)
        {
            m=m+n/d;
            n=n%d;
        }
    }
    tmp.m=m;
    tmp.n=n;
    tmp.d=d;
    return tmp;
}

int gcd(int m,int n)  //calculate max common divisor
{
    if(m%n==0)
        return n;
    else
        return gcd(n,m%n);
}

void main()
{
    int i,gcd_=1;
    result tmp;
    int *a=NULL;

    a=(int*)malloc(NUM_OF_DATA*sizeof(int));
    //assert(NULL!=a);
    
    for(i=0;i<NUM_OF_DATA;i++)
        a[i]=2147483647-i%10;
    tmp=average(a,NUM_OF_DATA);
    if(tmp.n!=0)
    gcd_=gcd(tmp.d,tmp.n);
    if (tmp.n!=0)          //numerator == 0
    printf("the average is:%d+%d/%d\n",tmp.m,tmp.n/gcd_,tmp.d/gcd_);
    else
        printf("the average is:%d\n",tmp.m);

}