定点机二进制数加减乘除法的C语言实现

main函数是空的,内容都被写进各个子函数里。在这里稍微说一下各个运算的原理:

加法:

写了三种加法,分别是严格格式(bin_plus_limit),右对齐(bin_plus_right),和左对齐(bin_plus_left)。只有严格格式有溢出检测。加法的原理都是最基础的进位。

减法:

即对减数B补码做加法。调用的是右对齐加法。
加减法不分原码或补码。

乘法(原码):
  1. 先初始化一个部分积S,长度为输入码长的2倍。
    部分积前半部分为0,后半部分为乘数B。

假设被乘数A=001011,被乘数B=000101
在这里插入图片描述

  1. 进入循环:
    观察S的最后一位
  • 如果是1,则先给S左对齐地加上A,再将S右移1位。
  • 如果是0,则单纯将S右移1位。

在这里插入图片描述

  1. 当部分积S中整个B都向右移干净时,循环过程结束。

在这里插入图片描述
最后应指出,符号位独立于数值计算。做一个异号得负同号得正的判断即可。

乘法(补码):

乘法的补码运算本质上和原码是一样的,但是在循环判别上稍稍复杂了一点。本算法即Booth算法。

  1. 对被乘数A和乘数B都要进行一些处理。
  • 如果A符号位只有1位,需要拓展为2位符号位
  • B末尾必须加一位0(必需)
  • 计算出-A的补码
  1. (与原码乘法相同)初始化一个前部分为0,后部分为B的部分积S

在这里插入图片描述

  1. 进入循环:
  • 如果S[bit-1]-S[bit-2]==-1
    (这里bit指的是S合并后的总位数,并不是给定数的位数)则先给S-A(加-A的补码),再将S向右位移1位。
  • 如果S[bit-1]-S[bit-2]==0,则只把S向右位移1位。
  • 如果S[bit-1]-S[bit-2]==1,则先给S+A,再把S向右位移1位。

在这里插入图片描述

  1. 循环到B还剩最后1位的时候,循环结束,最后再把S向右位移1位,得到最终结果

在这里插入图片描述

除法(整数/原码):

在这里插入图片描述
因为是整数定点机,所以除法结果不能出现小数。我们要限定,A>B才能A/B。
如上图所示,对于本来就位数相等的两个数,可以直接做除法。但是对于位数不等的两个数,必须先经历一个“左对齐做减法”的步骤,如下图
在这里插入图片描述
为了解决这个问题,我采用的办法是,对B进行填充,使之与A有效位相同,如下图
在这里插入图片描述
我们设这个扩充后的B为opB(option 操作)
此时做opA=A-opB,>0,如下图
opA就是操作过的A的意思,也就是这一步的余数。
在这里插入图片描述
之后我们让B向右位移1位,再做opA=opA-opB。明显这次<0
在这里插入图片描述
我们不对opA操作,继续把opB右移1位,如图
在这里插入图片描述
到此为止,opB==B,循环结束。即10111/100=101…11

总结刚刚的做法

  1. 给B进行处理(opB),删除左边多余的0(保留符号位的位置),右边填上0
  2. 进入循环:
  • 如果opA-opB<0,则对opA不操作,对opB右移1位。上商为0。
  • 如果opA-opB>0,则opA=opA-opB,对opB右移1为,上商为1。
  1. 在opB==B的时候,循环终止。得到答案

最后应指出,符号位独立于数值计算。做一个异号得负同号得正的判断即可。

在这里插入图片描述

除法(小数/原码):

小数的除法与整数的除法原理上是一样的,但是也有不同。
首先,因为是小数定点机,所以除法结果不能出现整数。我们要限定,A<B才能A/B。
因为小数从0.XXX开始,其左端是自然对齐的,不需要人工对齐。
但是小数有另外一个问题:至少需要一个双倍长度的寄存器才能存下余数,因为余数会比数值本身长。如下图

在这里插入图片描述
如果我们要完整保存余数,需要保存0.00000111。这里我们采用一种比较巧的办法:
把之前对opB右移改为对opA左移!!
这样我们只需要运算下面框选区域即可,但是这样不能得到一个正确的余数
在这里插入图片描述
如图,我们最终得到的余数是00111,是不正确的。
具体的操作办法我们总结如下

  1. 如果opA-opB<0,则仅对opA左移一位,上商0
  2. 如果opA-opB>0,则opA=opA-opB,再对opA左移一位,上商1
  3. 直到把B全部遍历一遍结束。

在这里插入图片描述

符号位独立于数值计算。做一个异号得负同号得正的判断即可。
最后要注意的是,刚刚的描述里有个细节:要判断opA-opB的大小,得计算一遍。这里又分了两个办法:

  1. 先opA=opA-opB,如果<0,再opA=opA+opB,这个就是恢复法

  2. 考虑到如果<0,opA=2*(opA+opB)-opB=2opA+opB,而如果>0,opA=2opA-opB,达成了对称性,所以可以减少恢复的次数,这个就是不恢复法。

最后代码如下:代码比较长,里面函数的含义都在注释里,主函数留给读者自行发挥

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 64
//名称说明:bin是指不区分补码或原码的二进制码
//补码称code 原码称truecode
//整数称int 小数称dec

char* bin_plus_right(char* A, char* B);
char* bin_plus_left(char* A,char* B);
void bin_move(char* A, int n, int type,int signal);

//对二进制字符串某位置反
void reverse_digit(char* code, int digit){
   
    if(code[digit]=='0'){
   
        code[digit]='1';
    }else if(code[digit]=='1'){
   
        code[digit]='0';
    }
}

//2的幂
int power_by_2(int subnum){
   
    int res=2;
    while((--subnum)>0){
   
        res=2*res;
    }
    return res;
}

//由补码 输出十进制整数
int code_to_int(char* code,int signal){
   
    //不能改变传来的code指针
    int bit=strlen(code);
    char* modecode=malloc((bit+1)*sizeof(char));
    strcpy(modecode,code);

    //生成补码的反码
    int weight=1;

    if(modecode[signal-1]=='1'){
   
        weight=-1;
        for(int i=signal;i<bit;i++){
   
            reverse_digit(modecode,i);
        }
    }
    //生成补码的补码(原码)
    char* one="1";
    if(modecode[signal-1]=='1'){
   
        modecode=bin_plus_right(modecode,one);
    }
    //由原码生成十进制数
    int flag=1;
    int res=0;
    int i=bit-1;
    while(i>signal-1){
   
        res+=(modecode[i--]-'0')*flag;
        flag*=2;
    }
    if((res==0)&&(weight==-1)){
   
        res=power_by_2(bit-signal);
    }
    res*=weight;
    free(modecode);
    return res;
}

//由原码 输出十进制整数
int truecode_to_int(char* code,int signal){
   
    int bit=strlen(code);
    int weight=1;
    if(code[0]=='1'){
   
        weight=-1;
    }
    int flag=1;
    int res=0;
    int i=bit-1;
    while(i>signal-1){
   
        res+=(code[i--]-'0')*flag;
        flag*=2;
    }
    res*=weight;
    return res;
}

//由原码 输出十进制小数
double truecode_to_dec(char* code,int signal){
   
    int bit=strlen(code);
    int weight=1;
    if(code[0]=='1'){
   
        weight=-1;
    }
    int i=1;
    double res=0;
    double flag=0.5;
    while(i<bit){
   
        res+=(code[i++]-'0')*flag;
        flag/=2;
    }
    res*=weight;
    return res;
}

//十进制 整数输出其补码
char* int_to_code(int num,int bit,int signal){
   //num 十进制整数 bit 总位数 signal 符号位(算在总位数内)(一般为1)
    char* modecode=(char*)malloc((bit+1)*sizeof(char));
    //符号位及最后一位处理
    if(num>=0){
   
        for(int i=0;i<=signal-1;i++){
   
            modecode[i]='0';
        }
    }else{
   
        for(int i=0;i<=signal-1;i++){
   
            modecode[i]='1';
        }
        num*=-1;
    }
    modecode[bit]='\0';

    //生成原码
    int i=bit-1;
    while(i>=signal){
   
        modecode[i--]=num%2+'0';
        num/=2;
    }
    if(num!=0){
   
        printf("<Error>:输入溢出,输入数±%d\n",power_by_2(bit-signal)-1);
    }

    //生成反码
    if(modecode[signal-1]=='1'){
   
        for(int i=signal;i<bit;i++){
   
            reverse_digit(modecode,i);
        }
    }

    //生成补码
    char* one="1";
    if(modecode[signal-1]=='1'){
   
        modecode=bin_plus_right(modecode,one);
    }

    return modecode;
}

//给一个补码求其负数的补码
char* code_to_negative(char* code){
   
    //不能改变传来的code指针
    int bit=strlen(code);
    char* modecode=malloc((bit+1)*sizeof(char));
    strcpy(modecode,code);

    int i=bit-1;
    while(modecode[i--]!='1'){
   
        ;
    }
    while(i>=0){
   
        reverse_digit(modecode,i--);
    }
    return modecode;
}

//原码乘法
char* truecode_multi(char* A,char* B,int bit,int signal){
   
    //A*B A:被乘数 B:乘数
    char* res=malloc((2*bit+1)*sizeof(
<think>好的,我需要帮助用户找到如何在C语言实现多项式除法的信息或代码示例。首先,我应该回顾用户提供的引用内容,看看是否有相关的信息。根据引用[1],用户提到了多项式的结构体定义,包括Term和Polynomial结构体,这可以作为实现多项式除法的基础数据结构。 接下来,用户提到了引用[2]关于C语言中的除法运算和定点运算的问题,这可能涉及到多项式除法中的系数处理,需要注意浮点数的处理方式,但多项式除法通常是整数系数,所以可能不需要浮点运算。不过,引用[2]中的定点运算方可能在处理某些特殊情况时有参考价值。 然后,引用[3]提到了乘法逆元,这可能多项式除法中的模运算有关,但不确定是否有直接关联。引用[4]详细描述了CRC算中的模2多项式除法,这直接涉及到多项式除法实现,尤其是模2除法,这可能是一个关键点。 用户需要的是多项式除法的C语言实现示例,而引用[4]中的CRC算使用的是模2除法,但多项式除法通常更一般化,支持不同系数的除法。不过,模2除法是多项式除法的一种特例,适用于二进制系数的情况。如果用户需要的是通用的多项式除法,可能需要更一般的实现,而不仅仅是模2。 首先,我需要确认多项式除法的基本算。多项式除法通常涉及将被除数多项式除以除数多项式,得到商和余数,满足被除数=除数×商+余数,其中余式的次数低于除数的次数。这类似于整数的除法。 接下来,考虑如何在C语言中表示多项式。引用[1]中的结构体已经定义了Term(系数和指数)和Polynomial(项数组、长度、容量),这可以用来表示多项式。因此,在实现多项式除法时,可以基于这个结构体进行操作。 然后,算的步骤大致如下: 1. 将被除式和除式按降幂排列。 2. 比较被除式的最高次项除式的最高次项,确定商的当前项。 3. 用当前商的项乘以除式,再从被除式中减去,得到新的被除式。 4. 重复上述步骤,直到被除式的次数小于除式的次数。 在实现过程中,需要注意系数的运算,例如整数除法或浮点除法。根据引用[2],C语言中的整数除法会截断小数部分,所以如果系数是整数,可能需要处理余数的情况,或者用户可能需要使用浮点数。不过,在多项式除法中,如果系数是整数且除式的首项系数不整除被除式的首项系数,可能需要使用分数系数,或者保持余数的形式。 例如,假设被除式是$x^2 + 2x + 1$,除式是$x + 1$,那么商是$x + 1$,余数为0。但如果被除式是$2x^2 + 3x + 1$,除式是$x + 1$,则商是$2x + 1$,余数0。但如果被除式是$x^3 + 2x + 1$,除式是$x^2 + x$,那么商是$x -1$,余数是$3x +1$。每一步的处理需要计算当前项的系数和指数。 在C语言中,可能需要动态管理多项式项数组,因为每一步操作可能会添加或删除项。例如,在每一步中,从被除式中提取最高次项,除式的最高次项比较,得到商的项,然后将除式乘以该商的项,生成一个临时多项式,再从被除式中减去这个临时多项式,得到新的被除式。重复直到被除式的次数低于除式。 此外,多项式减需要合并同类项,这可能涉及到遍历两个多项式的项,并按指数排序。因此,可能需要实现多项式相加、相减、乘单项式(即乘以一个项)的功能。 现在,根据引用[1]的结构体,可以编写相应的函数。例如,创建一个多项式除法的函数,输入被除式和除式,输出商和余数。这可能需要动态分配内存来存储商和余数的项数组。 考虑到用户可能需要一个示例代码,我需要基于引用[1]的结构体,编写一个简化的多项式除法函数。同时,需要注意错误处理,例如除式为零多项式的情况。 此外,引用[4]中的模2多项式除法可能是一个特例,其中系数是二进制,使用异或运算。但用户可能需要的是通用多项式除法,因此需要区分这两种情况。但用户的问题没有明确说明是哪种,所以可能需要询问,但根据用户提供的引用,可能更倾向于通用情况,但需要确认。 总结步骤: 1. 定义多项式结构体(已存在)。 2. 实现多项式减函数。 3. 实现多项式乘单项式函数。 4. 实现多项式除法函数,循环处理每一步,生成商和余数。 在代码实现中,需要注意内存管理,例如动态数组的扩展(capacity的处理),以及项的排序(按指数降序排列)。 可能的代码结构如下: - 初始化商和余数多项式。 - 将余数初始化为被除式的副本。 - 当余数的次数大于等于除式的次数时,执行循环: a. 获取余数的最高次项current_lead。 b. 获取除式的最高次项divisor_lead。 c. 计算商的当前项temp_term:系数为current_lead.coefficient / divisor_lead.coefficient,指数为current_lead.exponent - divisor_lead.exponent。 d. 将temp_term添加到商多项式中。 e. 创建临时多项式temp_poly,包含temp_term一个项。 f. 将temp_poly乘以除式,得到temp_product。 g. 从余数多项式中减去temp_product,得到新的余数。 - 循环结束后,余数即为最终的余数。 需要注意的是,每次减操作后,余数可能发生变化,需要重新排序和合并同类项。 此外,除法中可能涉及到系数为浮点数的情况,但根据引用[1]中的结构体,系数是整数,所以可能需要处理整数除法的情况,或者修改结构体以支持浮点数。例如,如果系数是整数,那么商的系数可能为分数,这时候可能需要使用浮点数类型,或者保持余数的形式,但这样余数的系数可能为分数。这可能比较复杂,因此可能示例代码仅处理系数为整数的情况,且除式的首项系数能整除余数的首项系数,否则余数可能非零。 例如,在实现中,如果被除式无被除式整除,余数将保留余下的项。 考虑到这些因素,可能需要编写一个简化的示例代码,假设系数为整数,并且除式的首项系数能整除余数的当前首项系数。这可能不够健壮,但作为示例是可以的。 现在,基于引用[1]的结构体,编写代码: 首先,需要实现多项式的减函数,多项式乘以单项式函数,以及辅助函数如获取最高次项,复制多项式等。 例如: Term结构体包含coefficient和exponent,Polynomial结构体包含terms数组,length等。 函数可能包括: - Polynomial create_polynomial(int capacity); // 创建多项式 - void add_term(Polynomial *p, int coeff, int exp); // 添加项 - Term get_leading_term(const Polynomial *p); // 获取最高次项 - Polynomial multiply_term(const Polynomial *p, Term t); // 多项式乘以单项式 - Polynomial subtract_polynomials(const Polynomial *p1, const Polynomial *p2); // 多项式相减 - void free_polynomial(Polynomial *p); // 释放内存 然后,多项式除法函数: void polynomial_divide(const Polynomial *dividend, const Polynomial *divisor, Polynomial *quotient, Polynomial *remainder) { // 初始化余数为被除式的副本 copy_polynomial(dividend, remainder); while (remainder->length > 0 && get_leading_term(remainder).exponent >= get_leading_term(divisor).exponent) { Term r_lead = get_leading_term(remainder); Term d_lead = get_leading_term(divisor); Term q_term; q_term.coefficient = r_lead.coefficient / d_lead.coefficient; q_term.exponent = r_lead.exponent - d_lead.exponent; add_term(quotient, q_term.coefficient, q_term.exponent); Polynomial temp = create_polynomial(1); add_term(&temp, q_term.coefficient, q_term.exponent); Polynomial product = multiply_polynomials(&temp, divisor); free_polynomial(&temp); Polynomial new_remainder = subtract_polynomials(remainder, &product); free_polynomial(remainder); *remainder = new_remainder; free_polynomial(&product); } } 这只是一个简化的示例,实际实现中需要处理内存管理、错误检查、多项式项的合并和排序等问题。 此外,用户提供的引用[4]中的模2除法可能更简单,因为系数是0或1,使用异或操作,但用户的问题可能更关注通用情况。 因此,结合用户提供的引用和需求,可以给出一个基于结构体的多项式除法实现示例,强调算步骤和关键操作,同时指出可能的限制,如整数系数处理。</think>### C语言实现多项式除法的算步骤及示例 在C语言实现多项式除法需要以下关键步骤: 1. **数据结构定义** 使用结构体存储多项式项和多项式整体结构: ```c typedef struct { int coefficient; // 系数 int exponent; // 指数 } Term; typedef struct { Term *terms; // 项数组 int length; // 当前项数 int capacity; // 数组容量 } Polynomial; ``` 2. **核心算逻辑** 多项式除法遵循以下公式: $$ \text{被除式} = \text{除式} \times \text{商} + \text{余数} $$ 算步骤如下: - 比较被除式除式的最高次项 - 计算商的当前项并更新余数 - 重复直至余数次数低于除式 3. **关键函数实现** ```c // 多项式减(需合并同类项) Polynomial subtract_polynomials(const Polynomial *a, const Polynomial *b) { // 实现项合并符号处理 } // 多项式乘以单项式 Polynomial multiply_term(const Polynomial *p, Term t) { // 遍历多项式项t相乘 } // 多项式除法主函数 void polynomial_division(const Polynomial *dividend, const Polynomial *divisor, Polynomial *quotient, Polynomial *remainder) { // 初始化余数为被除式副本 copy_polynomial(dividend, remainder); while (remainder->length > 0 && get_leading_term(remainder).exponent >= get_leading_term(divisor).exponent) { Term q_term = { .coefficient = remainder_lead.coeff / divisor_lead.coeff, .exponent = remainder_lead.exp - divisor_lead.exp }; add_term(quotient, q_term.coefficient, q_term.exponent); Polynomial temp = multiply_term(divisor, q_term); Polynomial new_remainder = subtract_polynomials(remainder, &temp); free_polynomial(remainder); *remainder = new_remainder; } } ``` 4. **应用示例** 假设计算 $(x^3 + 2x + 5) ÷ (x + 1)$: ```c Polynomial dividend = { /* 初始化x³+2x+5 */ }; Polynomial divisor = { /* 初始化x+1 */ }; Polynomial quotient = create_polynomial(10); Polynomial remainder = create_polynomial(10); polynomial_division(&dividend, &divisor, &quotient, &remainder); ``` ### 特别说明 - 系数处理需注意整数除法截断特性[^2] - 模2多项式除法需改用异或运算(见CRC算实现[^4]) - 完整实现需包含动态数组管理和错误处理
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值