之前写过一套“大实数”的算法,但那一套采用的是C++、只有加法与乘法、注释残缺不全(Δεν ξέρω καν τι γράφω)。还是以一种负责的态度将源码重置一下吧。
#include <stdlib.h>
#include <string.h>
// 设置大整数精度
#define PRECISION (25)
// 自定义类型
typedef struct {
int valueArray[PRECISION];
} BigInteger;
typedef char* String;
// 输入数值
BigInteger setValue(String _string) {
// 初始化大整数结构体实例,所有位被初始化为0
BigInteger temp;
memset(&temp, 0, sizeof(BigInteger));
// 获取大整数字符串的长度
int length = strlen(_string);
for (int i = length - 1, j = PRECISION - 1; i >= 0; i--, j--) {
// 从右向左提取字符串的每一位数字,存入大整数数组中
temp.valueArray[j] = (int)(_string[i] - '0');
}
return temp;
}
// 读取数值
String getValue(BigInteger _bigInteger) {
// 获取大整数长度
int length = 25;
for (; _bigInteger.valueArray[25 - length] == 0; length--) { }
if (length == 0) {
length = 1;
}
char* string = (char*)calloc(length + 1, sizeof(char));
string[length] = '\0';
for (int i = 0; i < length; i++) {
// 从左到右将大整数数组的每一位转化为字符
string[i] = (char)(_bigInteger.valueArray[25 - length + i] + '0');
}
return string;
}
// 大整数加法
BigInteger add(BigInteger _param1, BigInteger _param2) {
// 新建空结果
BigInteger result = setValue("0");
// 进位标记
int extra = 0;
// 加法运算从低位(右)向高位(左)进行
for (int i = PRECISION - 1; i >= 0; i--) {
int sum = _param1.valueArray[i] + _param2.valueArray[i] + extra;
result.valueArray[i] = sum % 10;
extra = sum / 10;
}
return result;
}
// 大整数减法
BigInteger minus(BigInteger _param1, BigInteger _param2) {
// 新建空结果
BigInteger result = setValue("0");
// 借位标记
int borrow = 0;
// 减法运算从低位(右)向高位(左)进行
for (int i = PRECISION - 1; i >= 0; i--) {
// 若被减数小于减数,则需要借位
if (_param1.valueArray[i] < _param2.valueArray[i]) {
result.valueArray[i] = 10 + _param1.valueArray[i] - _param2.valueArray[i] - borrow;
borrow = 1;
}
// 否则直接相减
else {
result.valueArray[i] = _param1.valueArray[i] - _param2.valueArray[i] - borrow;
borrow = 0;
}
}
return result;
}
// 大整数乘法
BigInteger multipy(BigInteger _param1, BigInteger _param2) {
// 新建空结果
// 由于乘法会导致数位快速增长,所以另外新建结果数组,清算后再截取
int temp[2 * PRECISION] = { 0 };
// 笛卡尔乘法,模拟竖式运算
// 第1步,乘数按位进行分配,得到各位的结果
for (int i = PRECISION - 1; i >= 0; i--) {
for (int j = PRECISION - 1; j >= 0; j--) {
// ★难点:此处需要通过下标对结果进行数位对齐
temp[i + j + 1] = temp[i + j + 1] + _param1.valueArray[j] * _param2.valueArray[i];
}
}
// 第2步,清算分配结果和进位
int extra = 0, sum = 0;
for (int i = 2 * PRECISION - 1; i >= 0; i--) {
sum = temp[i] + extra;
temp[i] = sum % 10;
extra = sum / 10;
}
// 新建空白结果
BigInteger result = setValue("0");
// 忽略真实结果左侧超出精度的值
for (int i = 0; i < PRECISION; i++) {
result.valueArray[PRECISION - i - 1] = temp[2 * PRECISION - i - 1];
}
return result;
}
// 大整数比较
int compare(BigInteger _param1, BigInteger _param2) {
// 从高位(左)向低位(右),逐位比对
for (int i = 0; i < 25; i++) {
// 小于为-1
if (_param1.valueArray[i] < _param2.valueArray[i]) {
return -1;
}
// 大于为1
else if (_param1.valueArray[i] > _param2.valueArray[i]) {
return 1;
}
}
// 完全相同则为0
return 0;
}
// 大整数除法
BigInteger divide(BigInteger _param1, BigInteger _param2) {
// 被除数小于除数,返回 0
if (compare(_param1, _param2) == -1) {
return (BigInteger) { { 0 } };
}
// 记录两个大整数的长度
int numberLength[2] = { 25, 25 };
while (_param1.valueArray[25 - numberLength[0]] == 0) {
numberLength[0] -= 1;
}
while (_param2.valueArray[25 - numberLength[1]] == 0) {
numberLength[1] -= 1;
}
// 两个整数的长度差
int expotential = numberLength[0] - numberLength[1];
// 结果寄存器
BigInteger result = setValue("0");
// 除数放大
for (int i = numberLength[1]; i >= 1; i--) {
_param2.valueArray[25 - i - expotential] = _param2.valueArray[25 - i];
}
for (int i = 1; i <= expotential; i++) {
_param2.valueArray[25 - i] = 0;
}
// 迭代减法
while (expotential >= 0) {
while (compare(_param1, _param2) >= 0) {
_param1 = minus(_param1, _param2);
result.valueArray[24 - expotential] += 1;
}
expotential -= 1;
// 除数缩小
for (int i = 24 - expotential; i >= 1; i--) {
_param2.valueArray[i] = _param2.valueArray[i - 1];
_param2.valueArray[0] = 0;
}
}
return result;
}