加法: 逐位相加,要考虑到进位的情况。
减法:逐位相减,要考虑到借位的情况。
乘法:第一个乘数不动,循环第二个乘数的每一位,每一位先做循环加法,在根据位置对加的结果补0,最后把结果累加起来。
除法:循环从被除数中减去除数,减去多少次结果就是多少,直接写运行很慢,做了一点优化,看操作数之间长度差是否大于1,如果大于1,则本次除数后补差距-1个0,循环可以控制在百次左右。
public class BigDataOperator
{
/// <summary>
/// 加法
/// </summary>
/// <param name="lOperand"></param>
/// <param name="rOperand"></param>
/// <returns></returns>
public static string Add(string lOperand, string rOperand)
{
if (string.IsNullOrEmpty(lOperand) || string.IsNullOrEmpty(rOperand)) throw new ArgumentException("not a number");
bool isNeginative = false;
if (IsNegative(lOperand) && IsNegative(rOperand))
{
isNeginative = true;
lOperand = lOperand.Trim('-');
rOperand = rOperand.Trim('-');
}
if (IsNegative(lOperand) && !IsNegative(rOperand)) return Minus(rOperand, lOperand.Trim('-'));
if (!IsNegative(lOperand) && IsNegative(rOperand)) return Minus(lOperand, rOperand.Trim('-'));
string shortNumStr = lOperand;
string longNumStr = rOperand;
if (lOperand.Length > rOperand.Length)
{
shortNumStr = rOperand;
longNumStr = lOperand;
}
StringBuilder result = new StringBuilder();
//长数加短数 逐位相加
var difference = longNumStr.Length - shortNumStr.Length; //长度差
int carry = 0;//进位
for (int i = longNumStr.Length - 1; i >= 0; i--)
{
var shortIndex = i - difference;
var lNum = longNumStr[i] - (int)'0';
int sNum = 0;
if (shortIndex >= 0)
{
sNum = shortNumStr[shortIndex] - (int)'0';
}
var sum = lNum + sNum + carry;
if (sum > 9)
{
carry = 1;
result.Insert(0, sum - 10);
}
else
{
carry = 0;
result.Insert(0, sum);
}
}
//最后可能结果增长了一位
if (carry != 0) result.Insert(0, 1);
return (isNeginative ? "-" : "") + result.ToString().TrimStart('0');
}
/// <summary>
/// 减法
/// </summary>
/// <param name="lOperand"></param>
/// <param name="rOperand"></param>
/// <returns></returns>
public static string Minus(string lOperand, string rOperand)
{
if (string.IsNullOrEmpty(lOperand) || string.IsNullOrEmpty(rOperand)) throw new ArgumentException("not a number");
bool isNeginative = true;
if (IsNegative(lOperand) && IsNegative(rOperand)) return Minus(rOperand.TrimStart('-'), lOperand.TrimStart('-'));
if (IsNegative(lOperand) && !IsNegative(rOperand)) return Add(lOperand, "-" + rOperand);
if (!IsNegative(lOperand) && IsNegative(rOperand)) return Add(lOperand, rOperand.Trim('-'));
var bigNum = rOperand;
var smallNum = lOperand;
if (IsBigger(lOperand, rOperand))
{
isNeginative = false;
bigNum = lOperand;
smallNum = rOperand;
}
if (lOperand == rOperand) return "0";
StringBuilder result = new StringBuilder();
//逐位相加
var difference = bigNum.Length - smallNum.Length; //长度差
int borrowNum = 0; //借位
for (int i = bigNum.Length - 1; i >= 0; i--)
{
var shortIndex = i - difference;
var lNum = bigNum[i] - (int)'0' - borrowNum;
int sNum = 0;
if (shortIndex >= 0)
{
sNum = smallNum[shortIndex] - (int)'0';
}
if (lNum < sNum)
{
borrowNum = 1;
}
else
{
borrowNum = 0;
}
var diff = lNum + borrowNum * 10 - sNum;
result.Insert(0, diff);
}
return (isNeginative ? "-" : "") + result.ToString().TrimStart('0');
}
/// <summary>
/// 乘法
/// </summary>
/// <param name="lOperand"></param>
/// <param name="rOperand"></param>
/// <returns></returns>
public static string Multiple(string lOperand, string rOperand)
{
if (string.IsNullOrEmpty(lOperand) || string.IsNullOrEmpty(rOperand)) throw new ArgumentException("not a number");
bool isNeginative = true;
if (!IsNegative(lOperand) && !IsNegative(rOperand)) isNeginative = false;
if (IsNegative(lOperand) && IsNegative(rOperand)) isNeginative = false;
lOperand = lOperand.Trim('-');
rOperand = rOperand.Trim('-');
StringBuilder result = new StringBuilder();
//逐位相加
var resultTemp = "0";
for (int i = rOperand.Length - 1; i >= 0; i--)
{
var num = rOperand[i] - (int)'0';
var bitemp = "0";
for (int j = 0; j < num; j++) //重复加
{
bitemp = Add(bitemp, lOperand);
}
for (int k = 0; k < rOperand.Length - 1 - i; k++) //尾部补0
{
bitemp = bitemp + "0";
}
resultTemp = Add(resultTemp, bitemp);
}
return (isNeginative ? "-" : "") + resultTemp.TrimStart('0');
}
/// <summary>
/// 除法(小数舍去)
/// </summary>
/// <param name="lOperand"></param>
/// <param name="rOperand"></param>
/// <returns></returns>
public static string Divided(string lOperand, string rOperand)
{
if (string.IsNullOrEmpty(lOperand) || string.IsNullOrEmpty(rOperand)) throw new ArgumentException("not a number");
bool isNeginative = true;
if (!IsNegative(lOperand) && !IsNegative(rOperand)) isNeginative = false;
if (IsNegative(lOperand) && IsNegative(rOperand)) isNeginative = false;
lOperand = lOperand.Trim('-');
rOperand = rOperand.Trim('-');
if (lOperand == rOperand) return (isNeginative ? "-" : "") + '1';
if (!IsBigger(lOperand, rOperand)) return "0";
string result = "0";
var temp = lOperand;
while (true) //循环减法
{
var dividedNum = rOperand;
var times = "1";
var differ = temp.Length - rOperand.Length;//优化
if (differ > 1)
{
for (int i = 0; i < differ - 1; i++)
{
dividedNum = dividedNum + "0";
times = times + "0";
}
}
temp = Minus(temp, dividedNum);
if (IsNegative(temp))
{
break;
}
result = Add(result, times);
}
return (isNeginative ? "-" : "") + result.TrimStart('0');
}
/// <summary>
/// 判断是否大于
/// </summary>
/// <param name="lOperand"></param>
/// <param name="rOperand"></param>
/// <returns></returns>
public static bool IsBigger(string lOperand, string rOperand)
{
if (string.IsNullOrEmpty(lOperand) || string.IsNullOrEmpty(rOperand)) throw new ArgumentException("not a number");
bool isAllNagative = false;
if (IsNegative(lOperand) && !IsNegative(rOperand)) return false;
if (!IsNegative(lOperand) && IsNegative(rOperand)) return true;
if (IsNegative(lOperand) && IsNegative(rOperand))
{
isAllNagative = true;
}
string shortNumStr = lOperand;
string longNumStr = rOperand;
if (lOperand.Length > rOperand.Length)
{
return isAllNagative ? false : true;
}
if (lOperand.Length < rOperand.Length)
{
return isAllNagative ? true : false;
}
for (int i = 0; i < lOperand.Length; i++)
{
if (lOperand[i] > rOperand[0])
{
return isAllNagative ? false : true;
}
else if (lOperand[i] < rOperand[0])
{
return isAllNagative ? true : false;
}
else
{
continue;
}
}
//equal
return false;
}
/// <summary>
/// 判断是不是负数
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static bool IsNegative(string value)
{
if (string.IsNullOrEmpty(value)) throw new ArgumentException("not a number");
return value.ElementAt(0) == '-';
}
}
测试:
Assert.AreEqual(BigDataOperator.IsNegative("4444444444444444444444444444444444444"), false);
Assert.AreEqual(BigDataOperator.IsNegative("-14444444444444444444444444444444444444"), true);
Assert.AreEqual(BigDataOperator.IsBigger("5555555555555", "5555555555555"), false);
Assert.AreEqual(BigDataOperator.IsBigger("5555555555555", "-5555555555555"), true);
Assert.AreEqual(BigDataOperator.IsBigger("-5555555555555", "5555555555555"), false);
Assert.AreEqual(BigDataOperator.IsBigger("66666666666666", "555555555555"), true);
Assert.AreEqual(BigDataOperator.IsBigger("555555555555", "66666666666666"), false);
//add
Assert.AreEqual(BigDataOperator.Add("555555555555", "66666666666666"), "67222222222221");
Assert.AreEqual(BigDataOperator.Add("555555555555", "-66666666666666"), "-66111111111111");
Assert.AreEqual(BigDataOperator.Add("-555555555555", "66666666666666"), "66111111111111");
Assert.AreEqual(BigDataOperator.Add("-555555555555", "-66666666666666"), "-67222222222221");
//minus
Assert.AreEqual(BigDataOperator.Minus("555555555555", "66666666666666"), "-66111111111111");
Assert.AreEqual(BigDataOperator.Minus("555555555555", "-66666666666666"), "67222222222221");
Assert.AreEqual(BigDataOperator.Minus("-555555555555", "66666666666666"), "-67222222222221");
Assert.AreEqual(BigDataOperator.Minus("-555555555555", "-66666666666666"), "66111111111111");
//multy
Assert.AreEqual(BigDataOperator.Multiple("4236586974332423432", "13216545765875841324"), "55993045637377932557226829234811503968");
Assert.AreEqual(BigDataOperator.Multiple("4236586974332423432", "-13216545765875841324"), "-55993045637377932557226829234811503968");
Assert.AreEqual(BigDataOperator.Multiple("-4236586974332423432", "13216545765875841324"), "-55993045637377932557226829234811503968");
Assert.AreEqual(BigDataOperator.Multiple("-4236586974332423432", "-13216545765875841324"), "55993045637377932557226829234811503968");
//divide
Assert.AreEqual(BigDataOperator.Divided("32464576587684354324325632454325", "666623666466626666"), "48700006046529");
Assert.AreEqual(BigDataOperator.Divided("-32464576587684354324325632454325", "666623666466626666"), "-48700006046529");
Assert.AreEqual(BigDataOperator.Divided("32464576587684354324325632454325", "-666623666466626666"), "-48700006046529");
Assert.AreEqual(BigDataOperator.Divided("-32464576587684354324325632454325", "-666623666466626666"), "48700006046529");