当前位置: 首页 > news >正文

【C#】利用数组实现大数数据结构

文章目录

  • 前言
  • 一、各部分实现
    • 1.1 字段
    • 1.2 构造函数
    • 1.3 加减法
    • 1.4 乘法
    • 1.5 除法
  • 二、完整的实现

前言

由于数字在特别大的时候会溢出,所以需要用到大数。但是很多文章都是字符串实现大数数据结构,其运行效率过低,故而开发一种用数组实现的大数结构。包含有小数的大数数据结构。如果想实现整数的大数,把我写的小数部分去掉即可,太长就不单独放出来了。

由于是主要用来记录的文章,并不会过多解释实现的原理。我测试过的案例并不算多,若测出有bug,欢迎来告知。


一、各部分实现

1.1 字段

/// <summary>
/// <para>含有小数的大数, num为空表示无限大</para>
/// <para>一个Number对象只能表示一个数, 不能在内部修改num数组等字段, 只能通过构造函数传入</para>
/// </summary>
public class Number
{// 数字数组,从低位到高位存储(12345 -> [5, 4, 3, 2, 1])public readonly sbyte[] num;public readonly string stringNum;// 表示小数点后有多少位数(12345.6789 -> 5)public readonly int lend;// 表示小数点前有多少位数(12345.6789 -> 4)public readonly int leni;public bool isPositive;public static Number Zero = new Number(new sbyte[1] { 0 }, true, 0);public static Number Inf = new Number(new sbyte[0], true, 0);public static Number One = new Number(new sbyte[1] { 1 }, true, 0);
}

1.2 构造函数

无参构造为0
参数num是小端存储,每一位只能写一位十进制数字,num为空表示无限大

public Number()
{num = new sbyte[] { 0 };stringNum = "0";lend = 0;leni = 1;isPositive = true;
}/// <param name="reverse">为true表示是正序排列的数字</param>
public Number(sbyte[] num, bool isPositive, int lend = 0, bool reverse = false)
{// 无穷大if (num == null || num.Length == 0){this.num = new sbyte[0];this.lend = lend;leni = 0;this.isPositive = isPositive;return;}// 零if (num.Count(x => x == 0) == num.Length){this.num = new sbyte[1] { 0 };this.lend = 0;leni = 1;this.isPositive = true;}if (reverse) { num = num.Reverse().ToArray(); }int len = 1, start = 0;// 前导零不够位数if (lend < 0){sbyte[] newNum = new sbyte[num.Length - lend];Array.Copy(num, 0, newNum, -lend, num.Length);num = newNum;lend = 0;}// 去除前导0for (int i = 0; i < num.Length; i++){if (lend > i && num[i] != 0) { lend = Math.Max(lend - i, 0); start = i; break; }}// 后导0不够位数if (lend >= num.Length - start){sbyte[] newNum = new sbyte[lend + start + 1];Array.Copy(num, 0, newNum, 0, num.Length);num = newNum;}// 去除后导0for (int i = num.Length - 1; i >= 0; i--){if (num[i] != 0 || i <= lend + start) { len = i + 1; break; }}// 截取有效数字部分this.num = num.Where((x, i) => i >= start).Take(len - start).ToArray();// 计算字符串表示stringNum = string.Join("", this.num.Reverse());if (lend == 0)stringNum = (isPositive ? "" : "-") + stringNum[..(stringNum.Length - lend)];elsestringNum = (isPositive ? "" : "-") + stringNum[..(stringNum.Length - lend)] + "." + stringNum[(stringNum.Length - lend)..];// 计算长度this.lend = lend;leni = len - start - lend;// 标注正负信息this.isPositive = isPositive;
}/// <param name="reverse">为true表示是正序排列的数字</param>
public Number(string num, bool isPositive, int lend = 0, bool reverse = false)
{// 无穷大if (num == null || num.Length == 0){this.num = new sbyte[0];this.lend = lend;leni = 0;this.isPositive = isPositive;return;}// 零if (num.All(x => x == '0')){this.num = new sbyte[1] { 0 };this.lend = 0;leni = 1;this.isPositive = true;}if (reverse) { num = num.Reverse().ToString(); }int len = 1, start = 0;// 前导零不够位数if (lend < 0){num = num.PadLeft(num.Length - lend, '0');lend = 0;}// 去除前导0for (int i = 0; i < num.Length; i++){if (lend > i && num[i] != '0') { lend = Math.Max(lend - i, 0); start = i; break; }}// 后导0不够位数if (lend >= num.Length - start) num = num.PadRight(lend + start + 1, '0');// 去除后导0for (int i = num.Length - 1; i >= 0; i--){if (num[i] != '0' || i < lend + start) { len = i + 1; break; }}// 截取有效数字部分this.num = num.Substring(start, len).Select(c => (sbyte)(c - '0')).ToArray();// 计算字符串表示stringNum = string.Join("", this.num.Reverse());stringNum = stringNum[..(stringNum.Length - lend)] + "." + stringNum[(stringNum.Length - lend)..];stringNum = (isPositive ? "" : "-") + (stringNum[0] == '.' ? "0" : "") + stringNum;// 计算长度this.lend = lend;leni = len - start - lend;// 标注正负信息this.isPositive = isPositive;
}

1.3 加减法

加法:
1、符号相同采用加法
2、符号相反采用减法
减法和加法相反:
1、符号相同采用减法
2、符号相反采用加法
加法没有需要特别注意的,减法则需要用绝对值更大的一方减小的一方,否则会出错

/// <summary>
/// 正数相加, 无论Number.isPositive是否为true, 一律按照正数运算
/// 例: 
/// 12345.6789  lend=5  leni=4
///   123.321   lend=3  leni=3
/// --------------------------
/// 12468.9999  lend=5  leni=4
/// </summary>
private static (sbyte[], int) Add(Number a, Number b)
{// 最长整数长度、最长小数长度int maxLeni = Math.Max(a.leni, b.leni);int maxLend = Math.Max(a.lend, b.lend);// 计算最大长度 = 最大整数部分长度 + 最大小数部分长度 + 进位int maxLength = maxLeni + maxLend;if (a.leni == b.leni && a.num[^1] + b.num[^1] >= 10) maxLength++;// 结果sbyte[] retNum = new sbyte[maxLength];// 计算整数部分for (int i = 0; i < maxLeni; i++){retNum[maxLend + i] += (i < a.leni) ? a.num[a.lend + i] : (sbyte)0;retNum[maxLend + i] += (i < b.leni) ? b.num[b.lend + i] : (sbyte)0;}// 计算小数部分for (int i = 0; i < maxLend; i++){retNum[maxLend - i - 1] += (i < a.lend) ? a.num[a.lend - i - 1] : (sbyte)0;retNum[maxLend - i - 1] += (i < b.lend) ? b.num[b.lend - i - 1] : (sbyte)0;}// 进位for (int i = 0; i < maxLength; i++){if (retNum[i] >= 10){retNum[i + 1] += (sbyte)(retNum[i] / 10);retNum[i] %= 10;}}return (retNum, maxLend);
}/// <summary>
/// 正数相减, 无论Number.isPositive是否为true, 一律按照正数运算
/// 例:
///  12345.6789  lend=5  leni=4
/// -  123.321   lend=3  leni=3
/// ---------------------------
///  12222.3579  lend=5  leni=4
private static (sbyte[], int, bool) Sub(Number a, Number b)
{// 比较两数绝对值大小, 判断是否够减bool isPos = false;if (a.leni > b.leni) isPos = true;else if (a.leni == b.leni){for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { break; }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { isPos = true; break; }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { isPos = false; break; }// 两数相等if ((i + 1) == a.num.Length && a.num.Length == b.num.Length &&a.num[^(i + 1)] == b.num[^(i + 1)]){isPos = true;break;}}}// 分清楚大数和小数Number bigNum = isPos ? a : b;Number smallNum = isPos ? b : a;// 结果int maxLend = Math.Max(bigNum.lend, smallNum.lend);int maxLength = maxLend + Math.Max(bigNum.leni, smallNum.leni);sbyte[] retNum = new sbyte[maxLength];// 用大数减小数int bs = bigNum.lend - maxLend, ss = smallNum.lend - maxLend;for (int i = 0; i < maxLength; i++){// 减法retNum[i] += bs + i >= 0 ? bigNum.num[bs + i] : (sbyte)0;retNum[i] -= ss + i >= 0 && ss + i < smallNum.num.Length ? smallNum.num[ss + i] : (sbyte)0;// 借位if (retNum[i] < 0) { retNum[i] += 10; retNum[i + 1]--; }}return (retNum, maxLend, isPos);
}public static Number operator +(Number a, Number b)
{sbyte[] retNum; int maxLend; bool isPos;// 计算结果if (a.isPositive == b.isPositive) { (retNum, maxLend) = Add(a, b); isPos = a.isPositive; }else { (retNum, maxLend, isPos) = Sub(a, b); isPos = !(a.isPositive ^ isPos); }return new Number(retNum, isPos, maxLend);
}public static Number operator -(Number a, Number b)
{sbyte[] retNum; int maxLend; bool isPos;if (a.isPositive != b.isPositive) { (retNum, maxLend) = Add(a, b); isPos = a.isPositive; }else { (retNum, maxLend, isPos) = Sub(a, b); isPos = !(a.isPositive ^ isPos); }return new Number(retNum, isPos, maxLend);
}

1.4 乘法

使用FFT(快速傅里叶变换)实现复杂度为(n*logn)的乘法,具体可以b站找视频。
需要注意的是大数的位数不能特别大(百万级别),否则由于精度问题容易出错,一般来说是足够用的。
数字位数过大,不光是精度问题,FFT计算的复数中的值超过了double的上限,也会计算出错。

private static int NextPowerOfTwo(int n)
{if (n == 0) return 1;n--; // 处理已经是 2 的幂的情况(如 16 → 16)n |= n >> 1;n |= n >> 2;n |= n >> 4;n |= n >> 8;n |= n >> 16;return n + 1;
}private static Complex[] FFT(Complex[] a, bool inverse = false)
{int n = a.Length;if (n == 1){return new Complex[] { a[0] };}// 添0if ((n & (n - 1)) != 0){n = NextPowerOfTwo(n);Complex[] newA = new Complex[n];Array.Copy(a, newA, a.Length);a = newA;}// 分奇偶下标Complex[] pe = a.Where((x, i) => (i & 1) == 0).ToArray();Complex[] po = a.Where((x, i) => (i & 1) == 1).ToArray();// 递归Complex[] qe = FFT(pe, inverse);Complex[] qo = FFT(po, inverse);// 参数double angle = 2 * Math.PI / n * (inverse ? -1 : 1);Complex omegaBase = new Complex(Math.Cos(angle), Math.Sin(angle));Complex omega = Complex.One;// 合并结果Complex[] ret = new Complex[n];for (int i = 0; i < n >> 1; i++){ret[i] = qe[i] + omega * qo[i];ret[i + (n >> 1)] = qe[i] - omega * qo[i];omega *= omegaBase;}return ret;
}public static Number operator *(Number a, Number b)
{int n = NextPowerOfTwo(a.num.Length + b.num.Length);Complex[] aComplex = new Complex[n];for (int i = 0; i < a.num.Length; i++){aComplex[i] = new Complex(a.num[i], 0);}Complex[] bComplex = new Complex[n];for (int i = 0; i < b.num.Length; i++){bComplex[i] = new Complex(b.num[i], 0);}// 进行FFTComplex[] aFFT = FFT(aComplex);Complex[] bFFT = FFT(bComplex);// 对应位置相乘aFFT = aFFT.Select((x, i) => x * bFFT[i]).ToArray();// 进行IFFTComplex[] retComplex = FFT(aFFT, true);// 取整sbyte[] retNum = new sbyte[n];double[] nums = retComplex.Select(x => Math.Round(x.Real) / n).ToArray();// 进位for (int i = 0; i < nums.Length; i++){if (nums[i] >= 10){nums[i + 1] += Math.Floor(nums[i] / 10);}retNum[i] = (sbyte)(nums[i] % 10);}// 小数点int retlend = a.lend + b.lend;return new Number(retNum, !(a.isPositive ^ b.isPositive), retlend);
}

1.5 除法

由于我并不需要精度很高,只需要计算到有一位有效数字即可,所以我的实现比较简单。如果需要更多位的有效数字,可以在计算结束后再继续给被除数补充零,使其达到要求的精度。
我使用的方法则是先将两个数字无视小数点视为整数,并将被除数填零到比除数多一位,再用二分法找到最终的商,最后计算小数点位置,实现除法。
只不过用二分法总是需要除以二的,所以这里还需要写一个函数防止自己调用自己死循环。

private static Number FindMid(Number l, Number r)
{Number sum = l + r;sbyte[] retNum = new sbyte[sum.num.Length];retNum[0] = (sbyte)(sum.num[0] / 2);for (int i = 1; i < sum.num.Length; i++){retNum[i] = (sbyte)(sum.num[i] / 2);retNum[i - 1] += (sum.num[i] & 1) == 1 ? (sbyte)5 : (sbyte)0;}return new Number(retNum, true, 0);
}public static Number operator /(Number a, Number b)
{// 处理除数为零if (b.num.Length == 1 && b.num[0] == 0)return new Number(new sbyte[] { }, a.isPositive, 0);// 处理被除数为零if (a.num.Length == 1 && a.num[0] == 0)return Zero;// 无视小数点信息, 直接将两个数当做整数进行运算Number dividend = new Number(a.num, true, 0);Number divisor = new Number(b.num, true, 0);int lend = a.lend - b.lend;// 小于除数, 在小端填零if (dividend < divisor){sbyte[] newDividend = new sbyte[divisor.num.Length + 1];for (int i = newDividend.Length - dividend.num.Length; i < newDividend.Length; i++){newDividend[i] = dividend.num[i - (newDividend.Length - dividend.num.Length)];}dividend = new Number(newDividend, true, 0);lend += dividend.num.Length - a.num.Length;}// 利用二分法进行计算sbyte[] lb = new sbyte[dividend.num.Length - divisor.num.Length];sbyte[] rb = new sbyte[dividend.num.Length - divisor.num.Length + 2];if (lb.Length == 0) lb = new sbyte[] { 0 }; else lb[^1] = 1;rb[^1] = 1;Number l = new Number(lb, true, 0);Number r = new Number(rb, true, 0);sbyte[] ret = null;while (l <= r){Number mid = FindMid(l, r);Number tryNum = mid * divisor;if (tryNum <= dividend){if (tryNum + divisor > dividend) { ret = mid.num; break; }else l = mid + new Number(new sbyte[] { 1 }, true, 0);}else r = mid - new Number(new sbyte[] { 1 }, true, 0);}return new Number(ret, !(a.isPositive ^ b.isPositive), lend);
}

二、完整的实现

using System;
using System.Linq;
using System.Numerics;/// <summary>
/// <para>含有小数的大数, num为空表示无限大</para>
/// <para>一个Number对象只能表示一个数, 不能在内部修改num数组等字段, 只能通过构造函数传入</para>
/// </summary>
public class Number
{// 数字数组,从低位到高位存储(12345 -> [5, 4, 3, 2, 1])public readonly sbyte[] num;public readonly string stringNum;// 表示小数点后有多少位数(12345.6789 -> 5)public readonly int lend;// 表示小数点前有多少位数(12345.6789 -> 4)public readonly int leni;public bool isPositive;public static Number Zero = new Number(new sbyte[1] { 0 }, true, 0);public static Number Inf = new Number(new sbyte[0], true, 0);public static Number One = new Number(new sbyte[1] { 1 }, true, 0);public Number(){num = new sbyte[] { 0 };stringNum = "0";lend = 0;leni = 1;isPositive = true;}/// <param name="reverse">为true表示是正序排列的数字</param>public Number(sbyte[] num, bool isPositive, int lend = 0, bool reverse = false){// 无穷大if (num == null || num.Length == 0){this.num = new sbyte[0];this.lend = lend;leni = 0;this.isPositive = isPositive;return;}// 零if (num.Count(x => x == 0) == num.Length){this.num = new sbyte[1] { 0 };this.lend = 0;leni = 1;this.isPositive = true;}if (reverse) { num = num.Reverse().ToArray(); }int len = 1, start = 0;// 前导零不够位数if (lend < 0){sbyte[] newNum = new sbyte[num.Length - lend];Array.Copy(num, 0, newNum, -lend, num.Length);num = newNum;lend = 0;}// 去除前导0for (int i = 0; i < num.Length; i++){if (lend > i && num[i] != 0) { lend = Math.Max(lend - i, 0); start = i; break; }}// 后导0不够位数if (lend >= num.Length - start){sbyte[] newNum = new sbyte[lend + start + 1];Array.Copy(num, 0, newNum, 0, num.Length);num = newNum;}// 去除后导0for (int i = num.Length - 1; i >= 0; i--){if (num[i] != 0 || i <= lend + start) { len = i + 1; break; }}// 截取有效数字部分this.num = num.Where((x, i) => i >= start).Take(len - start).ToArray();// 计算字符串表示stringNum = string.Join("", this.num.Reverse());if (lend == 0)stringNum = (isPositive ? "" : "-") + stringNum[..(stringNum.Length - lend)];elsestringNum = (isPositive ? "" : "-") + stringNum[..(stringNum.Length - lend)] + "." + stringNum[(stringNum.Length - lend)..];// 计算长度this.lend = lend;leni = len - start - lend;// 标注正负信息this.isPositive = isPositive;}/// <param name="reverse">为true表示是正序排列的数字</param>public Number(string num, bool isPositive, int lend = 0, bool reverse = false){// 无穷大if (num == null || num.Length == 0){this.num = new sbyte[0];this.lend = lend;leni = 0;this.isPositive = isPositive;return;}// 零if (num.All(x => x == '0')){this.num = new sbyte[1] { 0 };this.lend = 0;leni = 1;this.isPositive = true;}if (reverse) { num = num.Reverse().ToString(); }int len = 1, start = 0;// 前导零不够位数if (lend < 0){num = num.PadLeft(num.Length - lend, '0');lend = 0;}// 去除前导0for (int i = 0; i < num.Length; i++){if (lend > i && num[i] != '0') { lend = Math.Max(lend - i, 0); start = i; break; }}// 后导0不够位数if (lend >= num.Length - start) num = num.PadRight(lend + start + 1, '0');// 去除后导0for (int i = num.Length - 1; i >= 0; i--){if (num[i] != '0' || i < lend + start) { len = i + 1; break; }}// 截取有效数字部分this.num = num.Substring(start, len).Select(c => (sbyte)(c - '0')).ToArray();// 计算字符串表示stringNum = string.Join("", this.num.Reverse());stringNum = stringNum[..(stringNum.Length - lend)] + "." + stringNum[(stringNum.Length - lend)..];stringNum = (isPositive ? "" : "-") + (stringNum[0] == '.' ? "0" : "") + stringNum;// 计算长度this.lend = lend;leni = len - start - lend;// 标注正负信息this.isPositive = isPositive;}private static int NextPowerOfTwo(int n){if (n == 0) return 1;n--; // 处理已经是 2 的幂的情况(如 16 → 16)n |= n >> 1;n |= n >> 2;n |= n >> 4;n |= n >> 8;n |= n >> 16;return n + 1;}private static Complex[] FFT(Complex[] a, bool inverse = false){int n = a.Length;if (n == 1){return new Complex[] { a[0] };}// 添0if ((n & (n - 1)) != 0){n = NextPowerOfTwo(n);Complex[] newA = new Complex[n];Array.Copy(a, newA, a.Length);a = newA;}// 分奇偶下标Complex[] pe = a.Where((x, i) => (i & 1) == 0).ToArray();Complex[] po = a.Where((x, i) => (i & 1) == 1).ToArray();// 递归Complex[] qe = FFT(pe, inverse);Complex[] qo = FFT(po, inverse);// 参数double angle = 2 * Math.PI / n * (inverse ? -1 : 1);Complex omegaBase = new Complex(Math.Cos(angle), Math.Sin(angle));Complex omega = Complex.One;// 合并结果Complex[] ret = new Complex[n];for (int i = 0; i < n >> 1; i++){ret[i] = qe[i] + omega * qo[i];ret[i + (n >> 1)] = qe[i] - omega * qo[i];omega *= omegaBase;}return ret;}/// <summary>/// 正数相加, 无论Number.isPositive是否为true, 一律按照正数运算/// 例: /// 12345.6789  lend=5  leni=4///   123.321   lend=3  leni=3/// --------------------------/// 12468.9999  lend=5  leni=4/// </summary>private static (sbyte[], int) Add(Number a, Number b){// 最长整数长度、最长小数长度int maxLeni = Math.Max(a.leni, b.leni);int maxLend = Math.Max(a.lend, b.lend);// 计算最大长度 = 最大整数部分长度 + 最大小数部分长度 + 进位int maxLength = maxLeni + maxLend;if (a.leni == b.leni && a.num[^1] + b.num[^1] >= 10) maxLength++;// 结果sbyte[] retNum = new sbyte[maxLength];// 计算整数部分for (int i = 0; i < maxLeni; i++){retNum[maxLend + i] += (i < a.leni) ? a.num[a.lend + i] : (sbyte)0;retNum[maxLend + i] += (i < b.leni) ? b.num[b.lend + i] : (sbyte)0;}// 计算小数部分for (int i = 0; i < maxLend; i++){retNum[maxLend - i - 1] += (i < a.lend) ? a.num[a.lend - i - 1] : (sbyte)0;retNum[maxLend - i - 1] += (i < b.lend) ? b.num[b.lend - i - 1] : (sbyte)0;}// 进位for (int i = 0; i < maxLength; i++){if (retNum[i] >= 10){retNum[i + 1] += (sbyte)(retNum[i] / 10);retNum[i] %= 10;}}return (retNum, maxLend);}/// <summary>/// 正数相减, 无论Number.isPositive是否为true, 一律按照正数运算/// 例:///  12345.6789  lend=5  leni=4/// -  123.321   lend=3  leni=3/// ---------------------------///  12222.3579  lend=5  leni=4private static (sbyte[], int, bool) Sub(Number a, Number b){// 比较两数绝对值大小, 判断是否够减bool isPos = false;if (a.leni > b.leni) isPos = true;else if (a.leni == b.leni){for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { break; }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { isPos = true; break; }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { isPos = false; break; }// 两数相等if ((i + 1) == a.num.Length && a.num.Length == b.num.Length &&a.num[^(i + 1)] == b.num[^(i + 1)]){isPos = true;break;}}}// 分清楚大数和小数Number bigNum = isPos ? a : b;Number smallNum = isPos ? b : a;// 结果int maxLend = Math.Max(bigNum.lend, smallNum.lend);int maxLength = maxLend + Math.Max(bigNum.leni, smallNum.leni);sbyte[] retNum = new sbyte[maxLength];// 用大数减小数int bs = bigNum.lend - maxLend, ss = smallNum.lend - maxLend;for (int i = 0; i < maxLength; i++){// 减法retNum[i] += bs + i >= 0 ? bigNum.num[bs + i] : (sbyte)0;retNum[i] -= ss + i >= 0 && ss + i < smallNum.num.Length ? smallNum.num[ss + i] : (sbyte)0;// 借位if (retNum[i] < 0) { retNum[i] += 10; retNum[i + 1]--; }}return (retNum, maxLend, isPos);}private static Number FindMid(Number l, Number r){Number sum = l + r;sbyte[] retNum = new sbyte[sum.num.Length];retNum[0] = (sbyte)(sum.num[0] / 2);for (int i = 1; i < sum.num.Length; i++){retNum[i] = (sbyte)(sum.num[i] / 2);retNum[i - 1] += (sum.num[i] & 1) == 1 ? (sbyte)5 : (sbyte)0;}return new Number(retNum, true, 0);}public static bool operator >=(Number a, Number b){if (a.isPositive == true && b.isPositive == false) return true;if (a.isPositive == false && b.isPositive == true) return false;if (a.leni > b.leni) return !(true ^ a.isPositive);else if (a.leni < b.leni) return !(false ^ a.isPositive);for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { return !(false ^ a.isPositive); }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { return !(true ^ a.isPositive); }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { return !(false ^ a.isPositive); }}// 两数相等return !(true ^ a.isPositive);}public static bool operator <=(Number a, Number b){if (a.isPositive == true && b.isPositive == false) return false;if (a.isPositive == false && b.isPositive == true) return true;if (a.leni > b.leni) return !(false ^ a.isPositive);else if (a.leni < b.leni) return!(true ^ a.isPositive);for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { return !(true ^ a.isPositive); }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { return !(false ^ a.isPositive); }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { return !(true ^ a.isPositive); }}// 两数相等return !(true ^ a.isPositive);}public static bool operator >(Number a, Number b){if (a.isPositive == true && b.isPositive == false) return true;if (a.isPositive == false && b.isPositive == true) return false;if (a.leni > b.leni) return !(true ^ a.isPositive);else if (a.leni < b.leni) return!(false ^ a.isPositive);for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { return !(false ^ a.isPositive); }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { return !(true ^ a.isPositive); }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { return !(false ^ a.isPositive); }}// 两数相等return !(false ^ a.isPositive);}public static bool operator <(Number a, Number b){if (a.isPositive == true && b.isPositive == false) return false;if (a.isPositive == false && b.isPositive == true) return true;if (a.leni > b.leni) return !(false ^ a.isPositive);else if (a.leni < b.leni) return!(true ^ a.isPositive);for (int i = 0; i < Math.Max(a.num.Length, b.num.Length); i++){// 被减数超界if ((i + 1) > a.num.Length) { return !(true ^ a.isPositive); }// 超界或更大if ((i + 1) > b.num.Length || a.num[^(i + 1)] > b.num[^(i + 1)]) { return !(false ^ a.isPositive); }else if (a.num[^(i + 1)] < b.num[^(i + 1)]) { return !(true ^ a.isPositive); }}// 两数相等return !(false ^ a.isPositive);}public static bool operator ==(Number a, Number b){if (a.leni != b.leni || a.lend != b.lend) return false;if (a.isPositive != b.isPositive) return false;for (int i = 0; i < a.num.Length; i++){if (a.num[i] != b.num[i]) return false;}return true;}public static bool operator !=(Number a, Number b){if (a.leni != b.leni || a.lend != b.lend) return true;if (a.isPositive != b.isPositive) return true;for (int i = 0; i < a.num.Length; i++){if (a.num[i] != b.num[i]) return true;}return false;}public static Number operator +(Number a, Number b){sbyte[] retNum; int maxLend; bool isPos;// 计算结果if (a.isPositive == b.isPositive) { (retNum, maxLend) = Add(a, b); isPos = a.isPositive; }else { (retNum, maxLend, isPos) = Sub(a, b); isPos = !(a.isPositive ^ isPos); }return new Number(retNum, isPos, maxLend);}public static Number operator -(Number a, Number b){sbyte[] retNum; int maxLend; bool isPos;if (a.isPositive != b.isPositive) { (retNum, maxLend) = Add(a, b); isPos = a.isPositive; }else { (retNum, maxLend, isPos) = Sub(a, b); isPos = !(a.isPositive ^ isPos); }return new Number(retNum, isPos, maxLend);}public static Number operator *(Number a, Number b){int n = NextPowerOfTwo(a.num.Length + b.num.Length);Complex[] aComplex = new Complex[n];for (int i = 0; i < a.num.Length; i++){aComplex[i] = new Complex(a.num[i], 0);}Complex[] bComplex = new Complex[n];for (int i = 0; i < b.num.Length; i++){bComplex[i] = new Complex(b.num[i], 0);}// 进行FFTComplex[] aFFT = FFT(aComplex);Complex[] bFFT = FFT(bComplex);// 对应位置相乘aFFT = aFFT.Select((x, i) => x * bFFT[i]).ToArray();// 进行IFFTComplex[] retComplex = FFT(aFFT, true);// 取整sbyte[] retNum = new sbyte[n];double[] nums = retComplex.Select(x => Math.Round(x.Real) / n).ToArray();// 进位for (int i = 0; i < nums.Length; i++){if (nums[i] >= 10){nums[i + 1] += Math.Floor(nums[i] / 10);}retNum[i] = (sbyte)(nums[i] % 10);}// 小数点int retlend = a.lend + b.lend;return new Number(retNum, !(a.isPositive ^ b.isPositive), retlend);}public static Number operator /(Number a, Number b){// 处理除数为零if (b.num.Length == 1 && b.num[0] == 0)return new Number(new sbyte[] { }, a.isPositive, 0);// 处理被除数为零if (a.num.Length == 1 && a.num[0] == 0)return Zero;// 无视小数点信息, 直接将两个数当做整数进行运算Number dividend = new Number(a.num, true, 0);Number divisor = new Number(b.num, true, 0);int lend = a.lend - b.lend;// 小于除数, 在小端填零if (dividend < divisor){sbyte[] newDividend = new sbyte[divisor.num.Length + 1];for (int i = newDividend.Length - dividend.num.Length; i < newDividend.Length; i++){newDividend[i] = dividend.num[i - (newDividend.Length - dividend.num.Length)];}dividend = new Number(newDividend, true, 0);lend += dividend.num.Length - a.num.Length;}// 利用二分法进行计算sbyte[] lb = new sbyte[dividend.num.Length - divisor.num.Length];sbyte[] rb = new sbyte[dividend.num.Length - divisor.num.Length + 2];if (lb.Length == 0) lb = new sbyte[] { 0 }; else lb[^1] = 1;rb[^1] = 1;Number l = new Number(lb, true, 0);Number r = new Number(rb, true, 0);sbyte[] ret = null;while (l <= r){Number mid = FindMid(l, r);Number tryNum = mid * divisor;if (tryNum <= dividend){if (tryNum + divisor > dividend) { ret = mid.num; break; }else l = mid + new Number(new sbyte[] { 1 }, true, 0);}else r = mid - new Number(new sbyte[] { 1 }, true, 0);}return new Number(ret, !(a.isPositive ^ b.isPositive), lend);}public override bool Equals(object obj){// 1. 检查是否为nullif (obj == null)return this == null;// 2. 检查是否为同一类型if (GetType() != obj.GetType())return false;// 3. 比较关键字段return this == (Number)obj;}public override int GetHashCode(){unchecked // 允许整数溢出{int hash = 17;hash = hash * 23 + isPositive.GetHashCode();hash = hash * 23 + lend.GetHashCode();hash = hash * 23 + leni.GetHashCode();// 只计算前4位数字的哈希(平衡性能与唯一性)for (int i = 0; i < Math.Min(4, num.Length); i++){hash = hash * 23 + num[i].GetHashCode();}return hash;}}
}
http://www.lryc.cn/news/619937.html

相关文章:

  • 云电竞盒子对游戏性能有影响吗?
  • 《Python学习之基础语法1:从零开始的编程之旅》
  • 向量相似度计算与Softmax概率分布对比
  • 2025盛夏AI热浪:八大技术浪潮重构数字未来
  • String里常用的方法
  • el-table合并相同名称的列
  • java中在多线程的情况下安全的修改list
  • 基于C#、.net、asp.net的心理健康咨询系统设计与实现/心理辅导系统设计与实现
  • LCP 17. 速算机器人
  • 老生常谈智能指针:《More Effective C++》的条款28
  • Linux 服务:动态主机配置协议(DHCP)实战指南 —— 服务器部署与跨网段配置
  • 4.0 vue3简介
  • DAY 44 预训练模型
  • SQL 核心操作全解析:从基础查询到关联关系实战
  • 18. parseInt 的参数有几个
  • 多语言文本 AI 情感分析 API 数据接口
  • Python解包技巧全解析
  • Docker部署RAGFlow:生产环境开启Kibana与ES安全集成指南
  • Celery在Django中的应用
  • 【web站点安全开发】任务3:网页开发的骨架HTML与美容术CSS
  • Pytest+selenium UI自动化测试实战实例(超详细)
  • 第十三节:后期处理:效果增强
  • OpenBMC适配器模式小白学习指南
  • 服务器安全检测和防御技术
  • LeetCode算法日记 - Day 10: x 的平方根、搜索插入位置
  • 大模型微调【1】之入门
  • 农业物联网:现代农业的智慧革命
  • 后端(服务端)的跳转方式-请求转发和重定向
  • 集成电路学习:什么是CV计算机视觉
  • Nginx学习笔记(七)——Nginx负载均衡