大数运算类-大整数减法的依托答辩记录

文章讨论了在C语言中使用%d与%lld格式化字符串处理负数时遇到的问题,特别是在sscanf和printf函数中的表现。作者通过补码的概念解释了负数在不同大小整数类型间转换可能导致的计算错误,并提供了一个自定义结构体来处理这个问题。
摘要由CSDN通过智能技术生成

吐槽:

关于它给我弄不会了,我的脑海里上演一场数学大厦崩溃的大剧。


问题点:

后来发现是%d和%lld的问题。sscanf和printf这两个小烧杯;

int是四字节;long long是八字节;

他们的正整数表达没问题,但是他们的负数表达就有大问题了;

当前,计算机内部储存方式是以二进制形式。我们将int和long long以二进制角度展开考虑问题;

联系一个远古的知识店——补码。在int里的负数在long long里就会发现天翻地覆的改变;


思路:

把整数-整数的问题拆解为:

①4个小问题:正正、正负、负正、负负;

②1个关键公式:A-B=-(B-A);

其中我把正负性用类似补码形式另外储存->结构体里的sign(1,-1);


代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#define int64 long long
#define i8 100000000
using namespace std;
struct number_struct{
    int64 part[10000]={0};
    int64 sign=1;
    int count=0;
    
    void show();
    number_struct &operator = (char s[]){ 
        int i;
        char fmt[]="%8lld";
        memset(part,0,sizeof(part));
        i=strlen(s)-8;
        for(;i>0;i-=8){
            sscanf(s+i,fmt,part+count);
            count++;    
        }
        i=i+8;
        fmt[1]=i+'0';

        if(i==1){
            if(s[0]=='-') sign=-1;
            else if(s[0]!='-'){
                sscanf(s,fmt,part+count);
                count++;
            }
        }
        else if(i>1){
            if(s[0]=='-'){
                sign=-1;
                sscanf(s,fmt,part+count);
                part[count]*=-1;
                count++;
            }
            else if(s[0]!='-') sscanf(s,fmt,part+count);
        }
        return *this;
    }
};

number_struct operator - (number_struct a,number_struct b){
    number_struct c;
    int i,j;    //  i 循环数  j 循环变量 
    int64 d,c_sum;  // d 单元间差 sum单元差
    i=a.count>=b.count?a.count:b.count;
    c.count=i,c.sign=a.sign,d=0;
    memset(c.part,0,sizeof(c.part));
    for(j=0;j<i;j++){
        //printf(" a.part[j]:%lld\n a.part[j]*a.sign:%lld\n b.part[j]:%lld\n b.part[j]*b.sign:%lld\n",a.part[j],a.part[j]*a.sign,b.part[j],b.part[j]*b.sign);
        c_sum=(a.part[j]*a.sign-b.part[j]*b.sign+d)*c.sign;    
        //printf("---c_sum/c.sign:%lld c_sum:%lld d:%lld ---\n",c_sum,c_sum,d);    
        if(c_sum>=0) {d=c_sum/i8*c.sign,c_sum=c_sum%i8;}
        else if(c_sum<0) {d=-1*c.sign,c_sum=c_sum+i8;}
        c.part[j]=c_sum;    
    }
    d*=c.sign;
    if(d>=0) c.count+=d,c.part[j]=d;
    else if(d<0){
        memset(c.part,0,sizeof(c.part));
        d=0,c.sign*=-1;
        for(j=0;j<i;j++){
            c_sum=(a.part[j]*a.sign-b.part[j]*b.sign+d)*c.sign;    
                
            if(c_sum>=0) {d=c_sum/i8*c.sign,c_sum=c_sum%i8;/*printf("%d>=0 c_sum:%d d:%d\n\n",c_sum,c_sum,d);*/}
            else if(c_sum<0) {/*printf("%d<0 c_sum:%d d:%d\n\n",c_sum,c_sum,d)*/;d=-1*c.sign,c_sum=c_sum+i8;}
            c.part[j]=c_sum;
        }        
    } 
    j=c.count-1;
    while(c.part[j--]==0&&c.count>1) c.count--;
    return c;
}

void number_struct::show(){
    int i;
    i=count-1;
    if(sign==-1) printf("-%lld",part[i]);else printf("%lld",part[i]);
    for(i--;i>=0;i--) printf("%08lld",part[i]);    
}

int main(){
    char a[1000]={0};
    char b[1000]={0};
    number_struct x,y,z;
    cin>>a;
    cin>>b;
    x=a;
    y=b;
    z=x-y;
    z.show();
}

结语:

珍爱生命,远离编程。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值