c语言中的高精度数据的存储

ANSI标准定义int是占2个字节,TC是按照ANSI的标准。但是VC中的int是4个字节。

类型 Bytes Area
int 型 2字节 16位 范围是-2^15~2^15-1 (-32768~32767)
long int 型 4字节 32位 范围是-2^31~2^31-1 (-2147483648~2147483647)
float 型 4字节 32位(存储的数据并不完整,6位精度)
double 型 8字节 64位(17位精度)

当需要在个人机上,对超过长整型的多位数(高精度数据)操作时,只能借助数组才能精确存储计算。


书上说:计算机为实型数据提供4字节32位,其精度是6位。
为双精度型数据提供8字节64位,其精度是17位
如给出:3.1415146116952445
计算机是如何存储的?
printf默认是输出6位小数,通过格式控制是可以控制小数的精度。

问题一:

问题描述:
2的100次方是一个很大的数,不用大数据类,计算机无法直接计算出来,编程求该式的准确结果(从最高位到最低位每一位都要打印出来)。

参考代码;

#include 
#include 
int main(){
    //一维数组的初始化 有三种形式 
    /*
    int num[] = {1,2,3};用数据填充 
    int num[3] = {0};全部默认 
        ------>初始化值的个数可少于数组元素个数.
        当初始化值的个数少于数组元素个数时,前面的按序初始化相应值, 
        后面的初始化为0(全局或静态数组)或为不确定值(局部数组).但是在实际处理局部数组的时候 如果初始化时指定的的元素个数比数组大小少,剩下的元素也都会被初始化为 0; 
    int num[3] = {1,2,3};指定大小 
    */
    int num[10000] = {0};
    //二维数组的初始化 
    /*
    同一维数组的初始化
    */ 

    //求乘方的准备工作 
    num[0] = 1;
    int len = 1;
    int n=100;//100次方 
    int i,j,m;
    for(i=0;i<100;i++){//做乘2,100次 
        for(j =0;j//每一位都乘2 
            num[j] = num[j] *2;
        }   
        for(m=0;m1;m++){//判断进位 
            if(num[m]>=10){
                num[m+1] += num[m]/10;
                num[m] = num[m]%10; 
            }
        }
        if(num[len-1]>=10){//判断数组需要扩容否 
            len++;
            num[m+1] += num[m]/10;
            num[m] = num[m]%10; 
        }
    } 
    //输出数组 
    for(int i=len-1;i>=0;i--){
        printf("%d",num[i]);
    }
    printf("\n");
    system("pause");
    return 0;
}

上面的算法是:将每一位都乘以2,全部乘完之后再进行判断是否需要进位。算法相对下面的来说复杂一些。


#include 
#include 
/*
模拟人工乘法计算,每一位等于乘数*被乘数+前面产生的进位
数组num存储计算结果
初始值是1
length表示占用的数组元素空间的个数
b存储计算的中间变量
d存储进位
思想:
乘方就是一直乘一个数,本题乘100次
被乘数的每一位num[i]乘以乘数在加上前面的进位
当最后一位乘过之后,进位变量d不一定是0
处理进位分解存储到数组元素空间中。 
*/

int main(){
    int num[1000];
    num[0] = 1;
    int n=100;
    int length=1;
    int d=0;
    while(n--){
        for(int i=0;i<length;i++){
            int b = num[i]*2+d;
            num[i] = b%10;
            d = b/10; 
        }   
        while(d!=0){
            num[length++] = d%10;
            d = d/10;
        }
    }

    for(int i=length-1;i>=0;i--){
        printf("%d",num[i]);
    }
    system("pause");
    return 0;
} 

第一眼看到这道题目想到的就是用数组存储大数据。平时没练习过,没做过类似的题目。总之脑袋是一片浆糊。有想到使用数组存储大数据,有想到使用一个数据元素存储一位数据还是多位数据…..等等脑袋里面是什么东西都飘过,感觉能想得到但是不会…自己把自己给吓着了…….

大整数存储最常用的方法是:每一位数字用一个数组元素来存储。数组是int型,而int型范围是-32768~32767,故而可以最多应该可以存储四位。

例如:将大整数的每一位都存放到一个数组空间中。

    #include 
    #include 
    /****
    $表示输入的截至。在大数据的长度未知的情况下使用“字符到数值”的转换可以很好的解决此类问题。(这样做的好处是可以不限长度的输入,也可以直接存储到字符数组中但是这样字符数组的长度后限制大整数的位数)
    用length来记录使用的数组空间个数。
    *****/
    int main(){
        int num[10000];
        int length=0;
        char c;
        scanf("%c",&c);
        while(c!='$'){
            num[length++] = c-'0';
            scanf("%c",&c);
        }
        for(int i=0;i"%d",num[i]);
        }
        system("pause");
        return 0;
    }

本题就可以使用最简单直接的方式:每一位占用一个数组元素,求2的100次方,需要乘2 100次,每一位都乘以2,在低位开始逐一判断是否有进位,最后一位需要进位就增加数组的长度。需要注意的是最后的进位不可能很大,但不一定是一位,稳妥起见还是需要逐一分割放到数组元素空间中。

例如:将大数据类每四位都存放到一个数组空间中。数组是int型

#include 
#include 
#include 

/*
函数名: strncpy
功  能: 串拷贝
用  法: char *strncpy(char *destin, char *source, int maxlen);
程序例:
#include 
#include 
int main(void)
{
   char string[10];
   char *str1 = "abcdefghi";
   strncpy(string, str1, 3);
   string[3] = '\0';
   printf("%s\n", string);
   return 0;
}
*/


/*
函数名: strcpy
功  能: 串拷贝
用  法: char *strcpy(char *str1, char *str2);
程序例:
#include 
#include 
int main(void)
 {
    char string[10];
    char *str1 = "abcdefghi";
    strcpy(string, str1);
    printf("%s\n", string);
    return 0;
 }
*/


/*
函数名: strtol
功  能: 将串转换为长整数
用  法: long strtol(char *str, char **endptr, int base);
程序例:
#include 
#include 
int main(void)
{
   char *string = "87654321", *endptr;
   long lnumber;
   /* strtol converts string to long integer  
   lnumber = strtol(string, &endptr, 10);
   printf("string = %s  long = %ld\n", string, lnumber);
   return 0;
}
*/


int main(){

    char str[100] = "1616516590000000065219521962195";//处理的字符串 
    int num[100];//四位一存储的结果数组 
    int length = strlen(str);//存储需要处理的长度 
    int m=0;//控制字符串的截取 
    int l=0;//结果数组使用的空间个数 
    while(m<length){
        char ss[5],*endptr;
        strncpy(ss,str+m,4);
        ss[4] = '\0';
        num[l++] = strtol(ss,&endptr,10);
        m = m+4;
    }
    /*
    需要注意的是在截取字符串的时候,四个字符,0的位置至关重要,0在高位决定了strtol转换后 整数的位数。
    这样在显示的时候0会被忽略掉。 
    */
    for(int i=0;i1;i++){
        if(num[i]>999){//4printf("%d ",num[i]);
        } 
        else if(num[i]>99){//3printf("0%d ",num[i]);
        }
        else if(num[i]>9){//2printf("00%d ",num[i]);
        }
        else if(num[i]>0){//1printf("000%d ",num[i]);
        }
        else{//0
            printf("0000 ");
        }
    }
    printf("%d",num[l-1]); //最后一位不进行处理 
    system("pause");
    return 0;
} 

高精度数据X长整数

设计思想:

  • 使用字符数组对高精度数据的存储,避免需要对高精度数据进行分段输入。
  • 乘法运算是从低位到高位进行的,数据最好是从低位到高位进行存储。
  • 在进行字符数组与数字数组的转换的过程中,可以进行低高位的转换。
  • 数字字符-48 or 数字字符-‘0’:可以将数字字符转换位数字(char->int)
    • char 类型之间的加减运算:
  • 既然使用的是一位数字占一个数组元素空间,那么最后的进位d应该逐一分解存储,如果放在一个数组元素空间中,对数组元素的数据类型由要求。

修改注意:
-48是不合标准的。-‘0’才是正解。因为C语言标准根本没有规定char字符一定要以ASCII或者兼容ASCII的编码方式进行编码。也就是说如果在某个环境下的char字符编码方案不兼容ASCII,那这段code就显然没有移植性。再说为什么数字字符与’0’相减可以得到该数字字符的数字值,这是因为C标准规定0-9这十个数字的字符char值必须是连续递增的,也就是说’1’-‘0’等于1是标准保证一定成立的。顺便说下C标准没有规定字母的char值一定要连续,也就是说标准不保证’B’-‘A’ == 1一定成立。
作者:Gomo Psivarh
链接:https://www.zhihu.com/question/29746929/answer/45492751
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

代码:

/*
    Name: 高精度数据x长整型 
    Copyright: 
    Author: zhangbo 
    Date: 27/11/17 18:54
    Description: 
        在用数组存储高精度数据时,由计算的方便性决定将数据是由 低到高还是由高到低存储到数组中;
        可以每位占一个数组元素空间 ,也可以几位数字占一个数组元素空间。
        若需从键盘输入要处理的高精度数据,一般用字符型数组存储,这样无须对高精度数据进行分段输入。
        当然这样存储后,需要由类型转换的操作,不同语言转换的操作差别虽然较大,但都是利用数字字符的ASCII码进行的。 
*/
#include 
#include 
#include 
int main(){
    long int x;
    scanf("%d",&x);//输入一般数 
    getchar();
    char c[256];
    gets(c);//输入高精度数据 
    int num[256];
    int length = strlen(c);
    int i,j;//转化位整型数据 
    for(i=0,j=length-1;i=0;i++,j--){
        num[i] = c[j] - 48;
    }
    int a=0;
    int d=0;
    for(int i=0;i//每一位做乘法运算 
        a = num[i] * x+d;
        num[i] = a%10;
        d = a/10;
    }
    //最后的进位扩容数组的长度 
    while(d!=0){
        num[length] = d%10;
        d = d/10; 
        length++;
    }
    //输出数组 
    for(int i=length-1;i>=0;i--){
        printf("%d",num[i]);
    }printf("\n");
    system("pause");
    return 0;
} 

求阶乘(一位数字占用一个数组元素空间)

/*
    Name: 大数据存储之求阶乘 
    Copyright: 
    Author: 张波 
    Date: 27/11/17 20:57
    Description: 
    每一位占用一个数组元素空间。 
*/

#include 
#include 
int main() {
    int result[10000] = { 0 };//结果数组 

    result[0] = 1;
    int n = 0;
    int length = 1;
    int len = length;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {//求阶乘 
        for (int j = 0; j<length; j++) {//每一位数字都乘以i 
            result[j] = result[j] * i;
        }
        for (int m = 0; m<=length - 1; m++) {//判断是否需要进位 (主要问题)
            if (result[m] >= 10) {
                result[m + 1] += result[m] / 10;//这个是由先后顺序的
                result[m] = result[m] % 10;
                if (m == length - 1) {
                    len++;
                    length = len;
                }
            }
        }
    }
    for (int i = length - 1; i >= 0; i--) {//输出结果 
        printf("%d", result[i]);
    }printf("\n");
    system("pause");
    return 0;
}

更新上面算法:


#include 
#include 

int main(){

    int n;
    scanf("%d",&n);
    int num[10000];//结果 
    int i,j;
    int d=0; //进位 
    int b=0;//计算中间结果

    num[0]=1;
    int length = 1;
    for(i=1;i<=n;i++){
        for(j=0;j<length;j++){
            b = num[j] * i+d;
            num[j] = b%10;
            d = b/10;
        }
        while(d!=0){
            num[length++] = d%10;
            d = d/10;
        }
    }
    for(i=length-1;i>=0;i--){
        printf("%d",num[i]);
    }

    system("pause");
    return 0;
}

求阶乘(六位数字占用一个数组元素空间)

#include 
#include 
#include 
int main(){
    long int a[256],b,d;
    int m,n,i,j,r;
    scanf("%d",&n);//求n的阶乘 
    m = log(n) * n/6 +2;//判断需要数组元素空间的个数 
    a[1] = 1;
    for(i=2;i<=m;i++){
        a[i] = 0;
    }
    d =0;//进位 
    for(i=2;i<=n;i++){//求阶乘 
        for(j=1;j<=m;j++){//每个数组元素都要相乘 
            b =a[j]*i+d;
            a[j] = b % 1000000;
            d = b/1000000;
        }
        if(d!=0){//最后一位直接扩容放入 
            a[j] = d;
        }
    }
    for(i = m;i>=1;i--){//找到实际的使用的数组元素空间的个数 
        if(a[i]==0){
            continue;
        }
        else{
            r =i;
            break;
        }
    }
    printf("%d!=%d",n,a[r]);//对最高位输出 
    //对其他位输出 
    for(i =r-1;i>=1;i--){//相当于集合操作 
        if(a[i]>99999){
            printf("%d ",a[i]);
            continue;
        }
        if(a[i]>9999){
            printf("0%d ",a[i]);
            continue;
        }
        if(a[i]>999){
            printf("00%d ",a[i]);
            continue;
        }
        if(a[i]>99){
            printf("000%d ",a[i]);
            continue;
        }
        if(a[i]>9){
            printf("0000%d ",a[i]);
            continue;
        }
        printf("00000%d ",a[i]);
    }
    system("pause");
    return 0;
} 

你可能感兴趣的:(蓝桥杯,基础练习)