目前我所掌握最全的高精度(大数)运算(第一次)

开学成功加入acm组,有一种有一种内心 牵挂已久的东西尘埃落定 却又被更大 的力量 牢牢抓住的 压迫感!(妈蛋 寒假没做题! 开学也没怎么做题! 同组已被甩一截! 现在神马都不会 !马上校赛! 还要组队! 没人要我怎么办1 省赛 也要来了! 还有几本书没看! 心中满是 ????)

第一篇这样的开头          会不会 压迫我更加努力抓狂!就这样纪念 我的第一篇 报告吧!

前言 是我从网上 看到 对 高精度 觉得 还不错的 描述

前言:由于计算机运算是有模运算,数据范围的表示有一定限制,如整型int(C++中int 与long相同)表达范围是(-2^31~2^31-1),unsigned long(无符号整数)是(0~2^32-1),都约为几十亿.如果采用实数型,则能保存最大的double只能提供15~16位的有效数字,即只能精确表达数百万亿的数.因此,在计算位数超过十几位的数时,不能采用现有类型,只能自己编程计算.
高精度计算通用方法:高精度计算时一般用一个数组来存储一个数,数组的一个元素对应于数的一位(当然,在以后的学习中为了加快计算速度,也可用数组的一个元素表示数的多位数字,暂时不讲),表示时,由于数计算时可能要进位,因此为了方便,将数由低位到高位依次存在数组下标对应由低到高位置上,另外,我们申请数组大小时,一般考虑了最大的情况,在很多情况下,表示有富余,即高位有很多0,可能造成无效的运算和判断,因此,我们一般将数组的第0个下标对应位置来存储该数的位数.如数:3485(三千四百八十五),表达在数组a[10]上情况是:
下标  0    1    2    3     4    5    6    7    8    9  
内容  4    5    8    4     3    0    0    0    0    0
说明:位数   个位  十位  百位 千位
具体在计算加减乘除时方法就是小学时采用的列竖式方法.
注:高精度计算时一般用正数,对于负数,通过处理符号位的修正.

下面 就用代码和讲解 说明 大数的加减乘 :

大数 首先 我们一般会用 字符串数组 来 保存 它,原因前言就有~! 而且 进行运算时 每一位对应 应该是倒序的 原因 前言也有~!

using namespace std;
const int N=1000;
char str1[N],str2[N];//存大数 的字符串数组
int a[N],b[N];//具体进行模拟每一位运算的整型数组
int compare(int a[],int b[]);//大数比较大小的函数
void add(int a[],int b[]);//
void gminus(int a[],int b[]);
int main()
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    cin>>str1>>str2;
    a[0]=strlen(str1);
    b[0]=strlen(str2);
    for(int i=1;i<=a[0];i++)
        a[i]=str1[a[0]-i]-'0';
    for(int i=1;i<=b[0];i++)
        b[i]=str2[b[0]-i]-'0';//以上是将存在字符串里的大数逆序读入整型数组

}

//比较两个大数谁大,想法代码都很简单!

int compare(int a[],int b[])
{
    int i;
    if(a[0]>b[0])
      cout<<"前一个数更大"<<endl;
    if(a[0]<b[0])
      cout<<"后一个数更大"<<endl;
    for(i=a[0];i>0;i--)
    {
        if(a[i]>b[i])
      cout<<"前一个数更大"<<endl;
        if(a[i]<b[i])
      cout<<"后一个数更大"<<endl;
    }
      cout<<"两个数一样大"<<endl;//两数相等
}

//模拟两个大数的加法过程,也很简单

void add(int a[],int b[])
{
    int len_max;
    len_max=a[0]>b[0]?a[0]:b[0];//判断哪个大数长一些,加到那一步
    for(int i=1;i<=len_max;i++)
    {
      a[i+1]+=(a[i]+b[i])/10;
      a[i]=(a[i]+b[i])%10;
    }
    if(a[len_max+1]>0) //如果大于0,就进一位
        a[0]=len_max+1;
    else
        a[0]=len_max;

     for(int i=a[0];i>0;i--)
        printf("%d",a[i]);
}

//模拟减法也很容易可以想到,如果是负数,输出的时候加个负号-.

void gminus(int a[],int b[])//大数减法
{
    int flag2=compare(a,b);
    printf("%d\n",flag2);
    if(flag2==0)
    {
        memset(a,0,sizeof(a));
        a[0]=1;
        for(int i=a[0];i>0;i--)
        printf("%d",a[i]);
    }
    if(flag2==1)//a比b大 正常减 a=a-b;
    {
       for(int i=1;i<=a[0];i++)
       {
           if(a[i]<b[i])
           {
               a[i+1]--;
               a[i]+=10;
           }
           a[i]=a[i]-b[i];
       }
       if(a[a[0]]==0)
        a[0]--;
      for(int i=a[0];i>0;i--)
        printf("%d",a[i]);
    }
    if(flag2==-1)//b比a大 a=-(b-a)
    {
        for(int i=1;i<=b[0];i++)
        {
            if(b[i]<a[i])
            {
                b[i+1]--;
                b[i]+=10;
            }
           a[i]=b[i]-a[i];
        }
        a[0]=b[0];
        if(a[a[0]]==0)
            a[0]--;
      printf("-");
      for(int i=a[0];i>0;i--)
        printf("%d",a[i]);
    }
}

//大数乘以小数

int multi1(int a[],long  key) //a=a*key,key是单精度数  
{int i,k;
if (key==0){memset(a,0,sizeof(a));a[0]=1;return 0;} //单独处理key=0
for(i=1;i<=a[0];i++)

a[i]=a[i]*key;//先每位乘起来
for(i=1;i<=a[0];i++)

{a[i+1]+=a[i]/10;a[i]%=10;} //进位
//注意上一语句退出时i=a[0]+1
while(a[i]>0)

{a[i+1]=a[i]/10;a[i]=a[i]%10;i++;a[0]++];}  //继续处理超过原a[0]位数的进位,修正a的位数
return 0;
}

模拟大数乘法,其实一点都不难 (弄懂了之后是不是都会这样说)说实话 之前以为很复杂  还特地百度 问大神 ~!各种离奇的算法 吓得我以为很难 校赛绝对不会出这种 虐心的题 也没管 以为 我要一直不会 还好今天 队友 给了 xxz大神学长的一个模板 看了一下 推了一遍 竟然 发现我看懂了 就是模拟乘法 竖式计算 很巧妙 运用0这个下表 对 注意 这个地方不能 用前面 a[0]来保存 数组 a的长度 因为    这个算法最核心的部分 就是 利用0的下标 不说那么高深 其实真不难 看一遍就会了 但不知道能记多久!

直接上全部代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1000;
char str1[N],str2[N];
int a[N],b[N],c[N];
int main()
{
    cin>>str1;
    cin>>str2;
    memset(a,0,sizeof(a));
    memset(a,0,sizeof(b));
    int len_str1=strlen(str1);
    int len_str2=strlen(str2);
    for(int i=0;i<len_str1;i++)
     a[i]=str1[len_str1-i-1]-'0';
    for(int i=0;i<len_str2;i++)
     b[i]=str2[len_str2-i-1]-'0';
     for(int i=0;i<len_str1;i++)//核心代码 模拟竖式 乘法 过程 记住这里下标必须从0开始 不能是1
     {
         for(int j=0;j<len_str2;j++)
         {
             c[i+j]+=a[i]*b[j];
             c[i+j+1]+=c[i+j]/10;
             c[i+j]%=10;
         }
     }
      int len=len_str1+len_str2;
     while(!c[len])len--;
     for(int i=len;i>=0;i--)
        cout<<c[i];
        cout<<endl;
}


终于 打完 所有我想记录下的 代码和话语~!算了解 这两天的心愿 ,好吧 我承认 我就算写完 这一篇很水的报告,我的a题能力不会有任何的提高,大神们也根本不懈不会来这里看这种没有营养的报告,不管怎样 我终于迈出了写博客的第一步~!(妈蛋 明天 还有c++上机实验 我书都没看~!)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
密码学分为两类密码:对称密码和非对称密码。对称密码主要用于数据的加/解密,而非对称密码则主要用于认证、数字签名等场合。非对称密码在加密和解密时,是把加密的数据当作一个大的正整数来处理,这样就涉及到大整数的加、减、乘、除和指数运算等,同时,还需要对大整数进行输出。请采用相应的数据结构实现大整数的加、减、乘、除和指数运算,以及大整数的输入和输出。 【基本要求】 1.要求采用链表来实现大整数的存储运算,不允许使用标准模板类的链表类(list)和函数。 同时要求可以从键盘输入大整数,也可以文件输入大整数,大整数可以输出至显示器,也可以输出至文件。大整数的存储运算和显示,可以同时支持二进制和十进制,但至少要支持十进制。大整数输出显示时,必须能清楚地表达出整数的位数。测试时,各种情况都需要测试,并附上测试截图;要求测试例子要比较详尽,各种极限情况也要考虑到,测试的输出信息要详细易懂,表明各个功能的执行正确。 2.要求大整数的长度可以不受限制,即大整数的十进制位数不受限制,可以为十几位的整数,也可以为500多位的整数,甚至更长;大整数的运算和显示时,只需要考虑正的大整数。如果可能的话,请以秒为单位显示每次大整数运算的时间。 3.要求采用类的设计思路,不允许出现类以外的函数定义,但允许友元函数。主函数中只能出现类的成员函数的调用,不允许出现对其它函数的调用。 4.要求采用多文件方式:.h文件存储类的声明,.cpp文件存储类的实现,主函数main存储在另外一个单独的cpp文件中。如果采用类模板,则类的声明和实现都放在.h文件中。 5.不强制要求采用类模板,也不要求采用可视化窗口;要求源程序中有相应注释。 6.要求采用Visual C++ 6.0及以上版本进行调试。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值