高精度 加减乘, 除法只提供商

测试网址
https://www.luogu.com.cn/problem/P2142
https://www.luogu.com.cn/problem/P1601
https://www.luogu.com.cn/problem/P1480
https://www.luogu.com.cn/problem/P1303

https://www.acwing.com/problem/content/795/
https://www.acwing.com/problem/content/794/
https://www.acwing.com/problem/content/793/

// bigNum.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cstring>

using namespace std;

#define MAXDIGITS   100110
#define PLUS        1
#define MINUS       -1

typedef struct {
    char digits[MAXDIGITS];
    int signbit;
    int lastdigit;
}bignum;

void initialize_bignum(bignum* c) {
    memset(c, 0, sizeof(bignum));
    c->signbit = PLUS;
}
void print_bignum(const bignum* const n) {
    int i;
    if (n->signbit == MINUS) printf("-");
    for (i = n->lastdigit; i >= 0; i--)
        printf("%c", '0' + n->digits[i]);
    printf("\n");
}

void zero_justify(bignum* n) {
    while ((n->lastdigit > 0) && (n->digits[n->lastdigit] == 0))
        n->lastdigit--;
    if ((n->lastdigit == 0) && (n->digits[0] == 0))
        n->signbit = PLUS;
}

int compare_bignum(bignum* a, bignum* b) {
    int i;

    if ((a->signbit == MINUS) && (b->signbit == PLUS)) return PLUS;
    if ((a->signbit == PLUS) && (b->signbit == MINUS)) return MINUS;

    if ((b->lastdigit > a->lastdigit)) return (PLUS * a->signbit);
    if ((a->lastdigit > b->lastdigit)) return (MINUS * a->signbit);

    for (i = a->lastdigit; i >= 0; i--) {
        if (a->digits[i] > b->digits[i])
            return (MINUS * a->signbit);
        if (b->digits[i] > a->digits[i])
            return (PLUS * a->signbit);
    }

    return 0;
}

void add_bignum(bignum* a, bignum* b, bignum* c);
void subtract_bignum(bignum* a, bignum* b, bignum* c) {
    int borrow;
    int v; int i;

    if ((a->signbit == MINUS) || (b->signbit == MINUS)) {
        b->signbit = -1 * b->signbit;
        add_bignum(a, b, c);
        b->signbit = -1 * b->signbit;
        return;
    }
    if (compare_bignum(a, b) == PLUS) {
        subtract_bignum(b, a, c);
        c->signbit = MINUS;
        return;
    }
    c->lastdigit = max(a->lastdigit, b->lastdigit);
    borrow = 0;

    for (i = 0; i <= (c->lastdigit); i++) {
        v = (a->digits[i] - borrow - b->digits[i]);
        if (a->digits[i] > 0)
            borrow = 0;
        if (v < 0) {
            v = v + 10;
            borrow = 1;
        }
        c->digits[i] = (char)v % 10;
    }
    zero_justify(c);
}




void add_bignum(bignum* a, bignum* b, bignum* c) {
    int carry;
    int i;

    initialize_bignum(c);

    if (a->signbit == b->signbit) c->signbit = a->signbit;
    else {
        if (a->signbit == MINUS) {
            a->signbit = PLUS;
            subtract_bignum(b, a, c);
            a->signbit = MINUS;
        }
        else {
            b->signbit = PLUS;
            subtract_bignum(a, b, c);
            b->signbit = MINUS;
        }
        return;
    }

    c->lastdigit = max(a->lastdigit, b->lastdigit) + 1;
    carry = 0;

    for (i = 0; i <= (c->lastdigit); i++) {
        c->digits[i] = (char)
            (carry + a->digits[i] + b->digits[i]) % 10;
        carry = (carry + a->digits[i] + b->digits[i]) / 10;
    }

    zero_justify(c);
}

void digit_shift(bignum* n, int d) {
    int i;
    if ((n->lastdigit == 0) && (n->digits[0] == 0)) return;

    for (i = n->lastdigit; i >= 0; i--)
        n->digits[i + d] = n->digits[i];

    for (i = 0; i < d; i++) n->digits[i] = 0;

    n->lastdigit = n->lastdigit + d;
}

void multiply_bignum(bignum* a, bignum* b, bignum* c) {
    bignum row;
    bignum tmp;
    int i, j;
    initialize_bignum(c);

    row = *a;

    for (i = 0; i <= b->lastdigit; i++) {
        for (j = 1; j <= b->digits[i]; j++) {
            add_bignum(c, &row, &tmp);
            *c = tmp;
        }
        digit_shift(&row, 1);
    }

    c->signbit = a->signbit * b->signbit;
    zero_justify(c);
}

void divide_bignum(bignum* a, bignum* b, bignum* c) {
    bignum row;
    bignum tmp;
    int asign, bsign;
    int i;  // j;

    initialize_bignum(c);

    asign = a->signbit;
    bsign = b->signbit;

    a->signbit = PLUS;
    b->signbit = PLUS;

    initialize_bignum(&row);
    initialize_bignum(&tmp);

    c->lastdigit = a->lastdigit;

    for (i = a->lastdigit; i >= 0; i--) {
        digit_shift(&row, 1);
        row.digits[0] = a->digits[i];
        c->digits[i] = 0;
        while (compare_bignum(&row, b) != PLUS) {
            c->digits[i]++;
            subtract_bignum(&row, b, &tmp);
            row = tmp;
        }
    }

    zero_justify(c);

    a->signbit = asign;
    b->signbit = bsign;
}

void int_to_bignum(int s, bignum* n) {
    int i;
    int t;
    if (s >= 0) n->signbit = PLUS;
    else n->signbit = MINUS;

    for (i = 0; i < MAXDIGITS; i++) n->digits[i] = (char)0;

    n->lastdigit = -1;

    t = abs(s);

    while (t > 0) {
        n->lastdigit++;
        n->digits[n->lastdigit] = (t % 10);
        t = t / 10;
    }
    if (s == 0) n->lastdigit = 0;
}


void string_to_bignum(string s, bignum* n) {
    int i;
    int t;
    if (s.size() >= MAXDIGITS) return;
    if (s[0] == '-') n->signbit = MINUS;
    else n->signbit = PLUS;

    for (i = 0; i < MAXDIGITS; i++) n->digits[i] = (char)0;
    n->lastdigit = -1;

    if (s[0] == '-' || s[0] == '+') s.erase(s.begin());

    int len = s.size()-1;
    for (; len >= 0; len--) {
        n->lastdigit++;
        n->digits[n->lastdigit] = s[len]-'0';
    }

    if(s=="0")n->lastdigit = 0;

    return;
}



int main()
{
    string sa, sb;
    cin >> sa >> sb;

    bignum a, b, c;
    string_to_bignum(sa, &a);
    string_to_bignum(sb, &b);
    //int_to_bignum(2,&a);
    //int_to_bignum(1, &b);
    divide_bignum(&a, &b, &c);
    print_bignum(&c);

    return 0;
}

c++ 大数类

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

using namespace std;

#define PLUS 	1	// 正数。
#define MINUS 	-1	// 负数。

// 大数类。
class integer
{
	friend ostream& operator<<(ostream&, const integer&);
	friend istream& operator>>(istream&, integer&);

	friend int compare(const integer, const integer);
	friend bool operator<(const integer, const integer);
	friend bool operator<=(const integer, const integer);

	friend integer operator<<(integer, int);

	friend integer operator+(integer, integer);
	friend integer operator-(integer, integer);
	friend integer operator*(integer, integer);
	friend integer operator/(integer, integer);
	friend integer operator^(integer, int);

public:
	integer() {};

	integer(string s) {
		if (s[0] == '-') signbit = MINUS;
		else signbit = PLUS;

		if (s[0] == '-' || s[0] == '+') s.erase(s.begin());
		if (s == "0") {digits.push_back(0); return;}
		int len = s.size();
		for (int i = len - 1; i >= 0; i--) {
			digits.push_back(s[i]-'0');
		}
	}

	integer(int a)
	{
		signbit = (a >= 0 ? PLUS : MINUS);
		a = abs(a);
		if (a == 0) { digits.push_back(0); return; }
		while (a)
		{
			digits.push_back(a % 10);
			a /= 10;
		}
	};

	~integer() {};

	void zero_justify(void);

private:
	// 表示大数的结构。数位按低位到高位的顺序存放。存储的是数位值,而不是数位的字符值。
	// 数字 1 用 ASCII 码为 1 的字符,而不是 ‘1’ 来表示。
	vector < char > digits;	// 存放数位值。
	int signbit;		// 符号位。
};

integer operator+(integer, integer);
integer operator-(integer, integer);

// 重载输出符号<<。
ostream& operator<<(ostream& os, const integer& n)
{
	// 当为自然数时,不输出“+”号。
	os << (n.signbit > 0 ? "" : "-");
	for (int i = n.digits.size() - 1; i >= 0; i--)
		// 存放的是数位值,输出时要转换为数位的字符值。
		os << (char)('0' + n.digits[i]);
	return os;
}

// 重载输入符号>>。
istream& operator>>(istream& in, integer& n)
{
	// 读入表示大整数的字符串。
	string s;
	in >> s;

	if (s.length() == 0)
	{
		// 若长度为0,表示读入的是一个空字符串,应该要给予错误提示,但对于本题来说,不
		// 存在这种情况,故不考虑。若要完善,需要进一步处理此种情况。
	}

	// 在解析之前,理应判断该字符串是否是一个合法的大数表示,即开始一位为符号位,为“+”或
	// “-”,正整数“+”可以忽略,后面应该全部是数字字符,且不包含前导0。由于本题不存在此种情
	// 况,故不考虑,若要完善需进一步处理此种情况。

	// 解析符号位。
	if (isdigit(s[0]))
		n.signbit = PLUS;
	else
	{
		n.signbit = (s[0] == '+' ? PLUS : MINUS);
		s.erase(s.begin());
	}

	// 解析数字位,从低位到高位存放于动态数组中。
	n.digits.clear();
	for (int i = s.length() - 1; i >= 0; i--)
		n.digits.push_back((char)(s[i] - '0'));

	return in;
}

// 移除大数运算产生的前导0。
void integer::zero_justify(void)
{
	for (int i = digits.size() - 1; i >= 1; i--)
		if (digits[i] == 0)
			digits.erase(digits.begin() + i);
		else
			break;

	if (digits.size() == 1 && digits[0] == 0)
		signbit = PLUS;
}

// 比较两个数的大小,若相等,返回 0,若 a 大于 b,返回 1,若 a 小于 b,返回 -1。
int compare(const integer a, const integer b)
{
	// 若 a 为正,b 为负,则有 a 大于 b。
	if (a.signbit == PLUS && b.signbit == MINUS)
		return PLUS;

	// 若 a 为负,b 为正,则 a 小于 b。
	if (a.signbit == MINUS && b.signbit == PLUS)
		return MINUS;

	// 若两数符号相同,则 a 的数位长度大于 b 的数位长度,若 a 为正数,则有 a 大于 b,若 a
	// 为负数,有 a 小于 b,则将 a 的符号位乘以1作为结果返回即可。  
	if (a.digits.size() > b.digits.size())
		return PLUS * a.signbit;

	// 若两数符号相同,若a的数位长度小于b的数位长度,若 a 为正数,则 a 小于 b,若 a 为负数,
	// 则 a 大于 b,则将 a 的符号位乘以 -1 作为结果返回即可。    
	if (a.digits.size() < b.digits.size())
		return MINUS * a.signbit;

	// 两个数的数位长度相等,符号相等,则从低位到高位逐个比较数位值的大小。
	int marker = a.digits.size() - 1;
	while (marker >= 0)
	{
		if (a.digits[marker] > b.digits[marker])
			return PLUS * a.signbit;

		if (a.digits[marker] < b.digits[marker])
			return MINUS * a.signbit;

		marker--;
	}

	return 0;
}

// 小于比较符。
bool operator<(const integer a, const integer b)
{
	return compare(a, b) < 0;
}

// 小于等于比较符。
bool operator<=(const integer a, const integer b)
{
	return compare(a, b) <= 0;
}

// 左移操作。b 表示左移的位数。即将 a 乘以 10^b。
integer operator<<(integer a, int b)
{
	integer c = a;

	// 若 a 等于 0,则移位后仍为 0。
	if (a.digits.size() == 1 && a.digits[0] == 0)
		return c;

	// 向左移动 b 位,相当于在数位数组前插入 b 个 0。
	for (int i = 0; i < b; i++)
		c.digits.insert(c.digits.begin(), (char)(0));

	return c;
}

// 加法运算。从低位往高位进行,每一位相加产生的进位向高位传递,注意负数的处理,可以相应的
// 转变为减法来简化操作。
integer operator+(integer a, integer b)
{
	integer c;

	// 两数符号位相等,则最终符号位和原来的加数符号位相同。
	if (a.signbit == b.signbit)
		c.signbit = a.signbit;
	else
	{
		// 若两个加数为一正一负,则将其转换为减法操作。
		if (a.signbit == MINUS)
		{
			a.signbit = PLUS;
			c = b - a;
		}
		else
		{
			b.signbit = PLUS;
			c = a - b;
		}

		return c;
	}

	// 从动态数组的开始即低位开始相加,逐渐往前进位,如果有的话。
	int carry = 0;		// 进位。
	int maxsize = max(a.digits.size(), b.digits.size());
	int marker = 0;

	// 为两数添加前导 0,以使得数位相同,便于计算。
	while (a.digits.size() < maxsize)
		a.digits.push_back(char(0));
	while (b.digits.size() < maxsize)
		b.digits.push_back(char(0));

	// 逐位相加。
	while (marker < maxsize)
	{
		int t = a.digits[marker] + b.digits[marker] + carry;
		carry = t / 10;
		c.digits.push_back((char)(t % 10));

		marker++;
	}

	// 若最后一次进位为 1,则需在最高位加 1。
	if (carry)
		c.digits.push_back((char)(1));

	c.zero_justify();

	return c;
}

// 减法。为了保证借位能够成功终止,最好确保被减数不小于减数。同样可以在适当情况转变为加法来简化操作。
integer operator-(integer a, integer b)
{
	integer c;

	// 当某一个数为负数时,转换为加法。
	if (a.signbit == MINUS || b.signbit == MINUS)
	{
		b.signbit = MINUS * b.signbit;
		c = a + b;

		return c;
	}

	// 两个都为正数,若 a < b,则尽量保证被减数大于减数。
	if (a < b)
	{
		c = b - a;
		c.signbit = MINUS;

		return c;
	}
	else
		c.signbit = PLUS;

	int borrow = 0;		// 借位。
	int maxsize = a.digits.size();	// 被减数大于减数。
	int marker = 0;		// 计数器。

	// 为减数添加前导 0,便于计算。因为先前已经使得 a > b 且 a 和 b 均为正数。
	while (b.digits.size() < maxsize)
		b.digits.push_back(char(0));

	// 从低位开始逐位相减,不够的向高位借位。
	while (marker < maxsize)
	{
		int v = a.digits[marker] - borrow - b.digits[marker];
		if (v < 0)
		{
			v += 10;
			borrow = 1;
		}
		else
			borrow = 0;

		c.digits.push_back((char)(v % 10));

		marker++;
	}

	c.zero_justify();

	return c;
}

// 乘法,采用一行一行算的方法比单纯的反复加法更快且编写代码不会变复杂许多。每次操作都把第一个
// 乘数左移一个数位,然后把左移后的数乘以x的积加到最终结果中,其中x是第二个乘数对应的数字。尽
// 管用反复加法来实现这一步看起来不够精巧,但由于对于第二个乘数的每个数字,内层循环最多执行 9
// 次,实际上并没有浪费太多的时间,左移一个数位等价于用它乘以进位制的基数,在十进制里就是乘以 10。
integer operator*(integer a, integer b)
{
	integer c = integer(0), row = a;
	row.signbit = PLUS;

	for (int i = 0; i < b.digits.size(); i++)
	{
		for (int j = 0; j < b.digits[i]; j++)
			c = (c + row);

		row = row << 1;
	}

	c.signbit = a.signbit * b.signbit;
	c.zero_justify();

	return c;
}

// 除法运算。将余数和商不断左移,余数加上被除数的下一个数字,然后尝试减去除数。
integer operator/(integer a, integer b)
{
	integer c, row;
	row.signbit = PLUS;

	// 商的符号为 a 的符号乘以 b 的符号。
	c.signbit = a.signbit * b.signbit;

	int v;
	// 从数a的最高位开始除。
	for (int i = a.digits.size() - 1; i >= 0; i--)
	{
		row = row << 1;
		row.digits[0] = a.digits[i];

		// 当除数小于被除数,减去除数,对应位的商增 1。
		v = 0;
		while (b <= row)
		{
			v++;
			row = row - b;
		}

		// 将商左移 1 位,刚得到的商即为最低位。
		c = c << 1;
		c.digits[0] = (char)(v);
	}

	c.zero_justify();

	return c;
}

// 幂计算。幂就是反复作乘法,利用:a^n = a^(n / 2) * a^(n / 2) * a^(n mod 2),可以减少乘
// 的次数。
integer operator^(integer a, int b)
{
	if (b == 0)
		return integer(1);

	if (b == 1)
		return a;

	if (b == 2)
		return a * a;

	return ((a ^ (b / 2)) ^ 2) * (a ^ (b % 2));
}

int main(int ac, char* av[])
{
	string a, b;
	cin >> a >> b;
	integer biga(a), bigb(b);

	cout << biga * bigb << endl;

	return 0;
}

posted on   itdef  阅读(6)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2017-11-14 c++沉思录 学习笔记 第六章 句柄(引用计数指针雏形?)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示