数学问题

本文详细介绍了大整数的存储与运算方法,包括加、减、乘、除及比较大小,同时提供了求反序数、最大公约数、最小公倍数和判断素数的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 求反序数

int Reverse(int x){    //求反序数
    int revx = 0;
    while (x != 0){
        revx *= 10;
        revx += x % 10;
        x /= 10;
    }
    return revx;
}



2 最大公约数gcd

求解最大公约数常用欧几里得算法(即辗转相除法)

欧几里得算法基于以下定理:

  • 设a、b均为正整数,则gcd(a, b) = gcd(b, a%b)。
int gcd (int a, int b){
  if (b == 0) return a;
  else return gcd(a, a%b);
}



3 最小公倍数lcm

最小公倍数往往通过通过最大公约数来求,假设a、b均为正整数,如果a和b的最大公约数为d,那么a和b的最小公倍数为a*b/d。

int lcm (int a, int b){
  return a / gcd(a, b) * b;
}



4 判断是否为素数

//判断是否为素数
bool isPrime(int n){
    if (n < 2)
        return false;
    int bound = sqrt(n);
    for (int i = 2; i <= bound; i++){
        if (n % i == 0)
            return false;
    }
    return true;
}



5 大整数运算

5.1 大整数的存储

使用数组即可(定义int类型数组d[1000])。

需要注意的是,存储时需要顺位存储的,即整数的高位存储在数组的高位 (如将235存储在数组中,则有d[0] = 5, d[1] = 3, d[2] = 2);而把整数按字符串%s读入的时候,实际上是逆位存储的,(即d[0] = 2, d[1] = 3, d[2] = 5),因此在读入后需要再另存为至d[]数组的时候反序一下。

为了方便随时获取大整数的长度,一般都会定义一个int型变量len来记录其长度,并和d数组结合成一个结构体。

//大整数结构体
struct bignum {
  int d[1000];
  int len;
  //构造函数
  bignum() {
    memset(d, 0, sizeof(d));
    len = 0;
  }
};

//将读入的字符串存储在数组中
bignum change(string str) {
  bignum a;
  a.len = str.size();
  for (int i = 0; i < a.len; i++){
    a.d[i] = str[a.len - i - 1] - '0';    //逆着赋值
  }
  return a;
}

//比较两个bignum变量的大小, a>b返回1, a==b返回0, a<b返回-1
int compare (bignum a, bignum b){
  if (a.len > b.len) return 1;
  else if (a.len < b.len) return -1;
  else {
    for (int i = a.len - 1; i >= 0; i--){
      if(a.d[i] > b.d[i]) return 1;
      else if(a.d[i] < b.d[i]) return -1;
    }
    return 0;
  }
}

//输出bignum
void print(bignum a){
  for (int i = a.len - 1; i >= 0; i--){
    printf("%d", a.d[i]);
  }
}



5.2 高精度加法

如果有有一个是负数,则可以在转换到数组这一步时,将负号去掉,然后采用高精度减法。

如果两个数都是负的,就都去掉负号用高精度加法,最后再把负号加回去即可。

bignum add(bignum a, bignum b) {    //高精度a + b
  bignum c;
  int carry = 0;     //carry表示进位
  for (int i = 0; i < a.len || i < b.len; i++){
    int temp = a.d[i] + b.d[i] + carry;    //对应位相加
    c.d[c.len++] = temp % 10;    //个位数为该位结果
    carry = temp / 10;
  }
  if (carry != 0) {
    c.d[c.len++] = carry;
  }
  return c;
}



5.3 高精度减法

使用sub函数前需要比较两个数的大小,如果被减数小于减数,需要交换两个变量,然后输出负号,再使用sub函数。

bignum sub(bignum a, bignum b) {    //高精度a - b
  bignum c;
  for (int i = 0; i < a.len || i < b.len; i++){    //以较长的为界限
    if (a.d[i] < b.d[i]) {    //如果不够减
      a.d[i + 1]--;    //向高位借位
      a.d[i] += 10;    //当前位加10
    }
    c.d[c.len++] = a.d[i] - b.d[i];
  }
  while (c.len - 1 >= 1 && c.d[c.len - 1] == 0){
    c.len--;
  }
  return c;
}



5.4 高精度与低精度的乘法

如果a和b中存在负数,需要先记录下其负号,运算之后再加上负号。

bignum multi(bignum a, int b){    //高精度 a * b
    bignum c;
    int carry = 0;  //进位
    for (int i = 0; i < a.len; i++){
        int temp = a.d[i] * b + carry;
        c.d[c.len++] = temp % 10;   //个位作为该位结果
        carry = temp / 10;  //高位部分作为新的进位
    }
    while (carry != 0) {    //和加法不一样,乘法的进位可能不止一位,因此用while
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}



5.5 高精度与低精度的除法
bignum divide(bignum a, int b, int &r) {    //高精度除法,r为余数
    bignum c;
    c.len = a.len;  //被除数的每一位和商的每一位是一一对应的,因此先令长度相等
    for (int i = a.len - 1; i >= 0; i--){   //从高位开始
        r = r * 10 + a.d[i];    //和上一位遗留的余数组合
        if (r < b) c.d[i] = 0;  //不够除,该位为0
        else {  //够除
            c.d[i] = r / b; //商
            r = r % b;  //获得新的余数
        }
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0) {
        c.len--;    //去除高位的0,同时至少保留一位最低位
    }
    return c;
}



5.6 大整数运算例题
  • PAT B1017 A除以B (20)
  • PAT A1023 Have Fun with Numbers (20)
  • PAT A1024 Palindromic Number (25)
5.7 大整数加法完整代码
#include <cstdio>
#include <iostream>
using namespace std;

//大整数结构体
struct bignum {
    int d[1000];
    int len;
    //构造函数
    bignum() {
        memset(d, 0, sizeof(d));
        len = 0;
    }
};

//将读入的字符串存储在数组中
bignum change(string str) {
    bignum a;
    a.len = str.size();
    for (int i = 0; i < a.len; i++){
        a.d[i] = str[a.len - i - 1] - '0';  //逆着赋值
    }
    return a;
}

//大整数加法
bignum add(bignum a, bignum b) {
    bignum c;
    int carry = 0;  //carry表示进位
    for (int i = 0; i < a.len || i < b.len; i++){
        int temp = a.d[i] + b.d[i] + carry; //对应位相加
        c.d[c.len++] = temp % 10;   //个位数为该位结果
        carry = temp / 10;
    }
    if (carry != 0) {
        c.d[c.len++] = carry;
    }
    return c;
}

//输出bignum
void print(bignum a){
    for (int i = a.len - 1; i >= 0; i--){
        printf("%d", a.d[i]);
    }
}


int main(){
    string str1, str2;
    cin >> str1 >> str2;
    bignum a = change(str1);
    bignum b = change(str2);
    print(add(a, b));
    return 0;
}
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值