待补充:“浮点数高精度运算”
参见这里==>
大整数四则运算各举例: http://www.cnblogs.com/vongang/archive/2011/08/17/2143303.html
大整数出发还可以参考这里的解释:http://blog.sina.com.cn/s/blog_7393daaf0100sutp.html
当对很大的数(比如100位)进行运算时,肯定不能c/c++内的数据类型直接运算(当然Java里的BigNumber可以。。。)这时就要用数组模拟运算过程。+, - ,*, /,运算貌似是小学学的东西,童鞋们,现在要用到小学的知识啦!!
先说加法,大体的操作包括逆序、对位、求和、进位(其实就是小学的加法运算,不过是把数倒过来算,至于为什么要逆序。。。)
例题:http://poj.grids.cn/practice/2981
代码:
#include <string>
#include <iostream>
using namespace std;
#define MAX 200
int an1[MAX+10];
int an2[MAX+10];
char s1[MAX+10];
char s2[MAX+10];
/*
i.e. s1= "1234"
s2= "2345"
ans1=0...01234
ans2=0...02345
*/
int main()
{
//1. 输入
scanf("%s", s1);
scanf("%s", s2);
//2. 求和
int i, j;
memset( an1, 0, sizeof(an1));
memset( an2, 0, sizeof(an2));
int len1 = strlen( s1); //strlen(string str)函数
j = 0;
for( i = len1 - 1;i >= 0 ; i --) //逆置
an1[j++] = s1[i] - '0'; //char转int的秘密
int len2 = strlen(s2);
j = 0;
for( i = len2 - 1;i >= 0 ; i --) //逆置
an2[j++] = s2[i] - '0';
len1 = max(len1,len2);
for( i = 0;i < len1 ; i ++ )
{
an1[i] += an2[i]; //求和
if( an1[i] >= 10 ) //进位
{
an1[i] -= 10;
an1[i+1] ++;
}
}
//3. 输出
int flag = 0;
for (i = len1 ; i >= 0; i--) //输出。注意:从len1开始,∵可能求得的和有一个进位:)
{
if (flag || an1[i]) //这个判断可以保证:对于有进位和没有进位的情况,都一旦有数字就开始输出
{
flag = 1;
printf("%d",an1[i]);
}
}
//特殊情况: 和为0仍要输出
if (!flag)
{
printf("0");
}
printf("\n");
system("pause");
return 0;
}
减法同加法类似
例题:http://poj.grids.cn/practice/2736
代码:
#include <stdio.h>
#include <string.h>
#define MAX 100
int ans1[MAX+10];
int ans2[MAX+10];
char s1[MAX+10];
char s2[MAX+10];
/*
i.e. s1= "2345"
s2= "1111"
ans1=0...02345
ans2=0...01111
==> ans1=0...01234
*/
void sub(){
//1. char[]转int[](逆序)
int len1=strlen(s1);
int len2=strlen(s2);
memset(ans1,0,sizeof(ans1));
memset(ans2,0,sizeof(ans2));
int i;
for(i=0;i<len1;i++){
ans1[len1-1-i]=s1[i]-'0';
}
for(i=0;i<len2;i++){
ans2[len2-1-i]=s2[i]-'0';
}
//2. 求差 (从低位减起,不够借位)
//注意:∵s1>s2,∴len1>=len2
for(i=0;i<len1;i++){
ans1[i]-=ans2[i];
if(ans1[i]<0){
ans1[i]+=10;
ans1[i+1]--;
}
}
//3. 输出差
int flag=0;//是否有至少一个数字输出(只要差不为0,flag最终被置true)
for(i=len1-1;i>=0;i--){
if(ans1[i]!=0 || flag==1){
printf("%d",ans1[i]);
flag=1;
}
}
if(flag==0)
printf("0");
}
int main()
{
int time=0;
scanf("%d",&time);
while(time-->0){
scanf("%s%s",s1,s2);
sub();
printf("\n");
}
//system("pause");
return 0;
}
乘法同加法类似,不过进位时mod10而不是 -10:
例题:http://poj.grids.cn/practice/2980
代码:
#include <stdio.h>
#include <string.h>
#define max 200
int an1[max+10];
int an2[max+10];
int result[max*2+10];
char s1[max+10];
char s2[max+10];
int main()
{
gets(s1);
gets(s2);
int i, j;
memset(an1,0,sizeof(an1));
memset(an2,0,sizeof(an2));
memset(result,0,sizeof(result));
int len1 = strlen(s1);
j = 0;
for(i = len1-1; i >= 0; i--)
an1[j++] = s1[i] - '0';
int len2 = strlen(s2);
j = 0;
for(i = len2-1; i >= 0; i--)
an2[j++] = s2[i] - '0';
//遍历两个乘数的位置,每个位置乘积都暂不做进位处理
for(i = 0; i < len2; i++)
for(j = 0; j < len1; j++)
result[i+j] += an2[i]*an1[j];
//算完后,统一进行进位处理
for(i = 0; i < len1*len2; i++)
{
if(result[i] >= 10)
{
result[i+1] += result[i]/10;
result[i] %= 10;
}
}
int flag = 0;
for(i = len1*len2; i >= 0; i--)
{
if(flag)
printf("%d",result[i]);
else if(result[i])
{
printf("%d",result[i]);
flag = 1;
}
}
if(!flag)
printf("0");
printf("\n");
return 0;
}
除法:
除法可以看作是循环相减,不过在做减法之前有一个判断两数大小的操作;
还是例题:http://poj.grids.cn/practice/2737
代码:
#include <stdio.h>
#include <string.h>
#define max 200
char s1[max + 10];
char s2[max + 10];
int an1[max + 10];
int an2[max + 10];
int result[max + 10];
/*
尝试a-=b,如果不够减则不减(我称之为“试差”)。返回 a-b(差)的长度.
注: 当 a<b时,返回-1.
当 a=b时,返回0.
当 a>b时,返回差的长度.
*/
int jianfa(int a[], int b[], int len1, int len2){
int i;
if(len1 < len2) //----------以下判断大小-------------
return -1; //a<b
int flag = 0;
if(len1 == len2){
for(i = len1 - 1; i >= 0; i--){
if(a[i] > b[i])
flag = 1;
else if(a[i] < b[i]){
if(!flag) return -1; //a<b
}
}
}
//-------------以上判断大小-------------
for(i = 0; i < len1; i++)//减法
{
a[i] -= b[i];
if(a[i] < 0){
a[i] += 10;
a[i+1]--;
}
}
for(i = len1 - 1; i >= 0; i--)
if(a[i])
return i+1;
return 0;
}
int main()
{
int i, j, n;
scanf("%d",&n);
while(n--)
{
scanf("%s",s1);
scanf("%s",s2);
memset(an1, 0, sizeof(an1));
memset(an2, 0, sizeof(an2));
memset(result, 0, sizeof(result));
int len1 = strlen(s1);
j = 0;
for(i = len1 - 1; i >= 0; i--)
an1[j++] = s1[i] - '0';
int len2 = strlen(s2);
j = 0;
for(i = len2 - 1; i >= 0; i--)
an2[j++] = s2[i] - '0';
//1. “试差”一次
/*
为什么先要试差一次,然后再去按照传统手算试商呢:
i.e. 求 68/32商:
68-32-32-...反复尝试减即可
i.e. 求 680/32商
680-320-320-...反复尝试减
40-32-32-...反复尝试减
i.e. 求 10/32商
10-?-?-... ==> 哈哈,原来是因为当“被除数 < 除数”的情况 ,试商(循环试差)根本无从试起,所以一上来先要减去被除数试试看,如果>0则知道可以开展试商。
下面代码中的注解以 "2345/32"为例 ,
2345-32=2313>0,可以开展试商。
(1)第一轮试商,2313尝试循环减去 3200(后面补的0的个数是 len(2345-32)=4得到的),可惜发现不够减 ==>本轮剩下2313 (2313-0*3200)
(2)第二轮试商,2313尝试循环减去320(3200去掉一个0),可以减去7次 ==> 本轮剩下73 (2313-7*320)
(3)第三轮试商,73尝试循环减去32(320去掉一个0),可以减去2次 ==> 本轮剩下9(73-2*32)
(4)9已经是余数了。收工:)
*/
if(len1 < len2)
{
printf("0\n");
continue;
}
len1 = jianfa(an1, an2, len1, len2); //2345-32=2313 --> len1=4位
if(len1 < 0)
{
printf("0\n");
continue;
}else if(len1 == 0)
{
printf("1\n");
continue;
}
result[0]++; //减掉一次,商加1
//减去一次后结果的长度是len1
int n = len1 - len2; //len1-len2=len(2313)-len(32)=4-2=2
if(n < 0) //不能再减时,诸如35/32的情况,减去一次后len1-len2=len(3)-len(32)=1-2=-1 <0
{
//处理进位 (后面有一段与此完全一样的代码)
for(i = 0;i < max; i++){
if(result[i] >= 10){
result[i+1] += result[i]/10;
result[i] %= 10;
}
}
}else if(n > 0){ //还可以减,诸如 2345/32的情况,减去一次后 len1-len2=len(2313)-len(32)=4-2=2 >0
for(i = len1 - 1; i >= 0; i--){ //i=3,2,1,0 ; an2[]=32
if(i >= n)
an2[i] = an2[i-n];
else
an2[i] = 0;
}
//结束时,an2[]=3200
}
//2. 反复试商(循环试差)
len2 = len1; //an2[]=3200; len2=len1=len(2313)=4
for(j = 0; j <= n; j++){
//尝试算出
//j=0, result[n] , t=jianfa(an1, an2+0, len1, len-0) , an1=2313尝试循环减去 an2=3200 ==> t=-1(不够减) ,直接跳到下一次循环
//j=1, result[n-1] , t=jianfa(an1, an2+1, len1, len-1) , an2=2313尝试循环减去 an2=320 ==> 减了7次 ,退出while时, result[n-1]=7
// ...
//j=n, result[0] , t=jianfa(an1, an2+n, len1, len-n) , an2=73尝试循环减去 an2=32 ==> 减了2次 ,退出while时, result[0]=2
int t;
while((t = jianfa(an1, an2+j, len1, len2-j)) >= 0){ //int jianfa(int a[], int b[], int len1, int len2)
// an2+j 表示把数组的头指针向后移j个位置,即删掉j个an2补上的0
// len2 同时减小j
len1 = t;
result[n-j]++;
}
}
//处理进位
for(i = 0;i < max; i++)//进位
{
if(result[i] >= 10)
{
result[i+1] += result[i]/10;
result[i] %= 10;
}
}
//输出商
int flag = 0;
for(i = max; i >= 0; i--)//输出
if(flag)
printf("%d",result[i]);
else if(result[i])
{
printf("%d",result[i]);
flag = 1;
}
if(!flag)
printf("0\n");
printf("\n");
}
return 0;
}