https://code.google.com/p/dotnet-big-decimal/
这是个BigDecimal类的开源项目,支持Operators +, - and *。
俺给改了改,加上了除法。原来的BigDecimal项目没有整数部分的长度属性,所以没有直接用BigInteger来实现除法,而是自己处理字符串,同时由于.Net4.0的BigInteger类 Parse和ToString方法效率极低,导致这个类效率不高,只能凑合用。
public static BigDecimal operator /(BigDecimal left, BigDecimal right) { var scale = Math.Max(left.scale, right.scale); string decimal1 = left.ToString(); string decimal2 = right.ToString(); BigDecimal value = BigDecimal.Parse(Division(decimal1, decimal2, scale)); return value; } /// <summary> /// 计算除法,精度由CustomScale决定,超过部分直接截去。如果CustomScale小于0,表示精度由前两个参数的最长小数位决定。 /// </summary> private static string Division(string decimal1, string decimal2, int CustomScale) { //算法:把两个参数的小数部分补0对齐,整数部分确保被除数长度大于除数, // 放大被除数的要求精度的倍数,确保整数计算能保留希望的小数部分 // 还原小数点,输出要求的精度,多余部分截断 if (!isNumeric(decimal1)) throw new ArgumentException("Invalid argument"); if (!isNumeric(decimal2)) throw new ArgumentException("Invalid argument"); //判断负号 int s1 = decimal1.IndexOf('-'); if (s1 >= 0) decimal1 = decimal1.Replace("-", ""); //判断负号 int s2 = decimal2.IndexOf('-'); if (s2 >= 0) decimal2 = decimal2.Replace("-", ""); int sign = s1 + s2; //=-2都是负数;=-1一正一负;=0都是正数;>0非法数字 int decimalpartlength1 = 0; int decimalpartlength2 = 0; int integerpartlength1 = 0; int integerpartlength2 = 0; int maxscale = 0; BigInteger bi1; BigInteger bi2; //检查小数部分长度 int pointIdx1 = decimal1.IndexOf('.'); if (pointIdx1 >= 0) { decimalpartlength1 = decimal1.Length - pointIdx1 - 1; //得到小数部分长度 integerpartlength1 = pointIdx1 == 0 ? 1 : pointIdx1; //得到整数部分长度,考虑小数点在第一位的情况 } else { integerpartlength1 = decimal1.Length; //得到整数部分长度 } //检查小数部分长度 int pointIdx2 = decimal1.IndexOf('.'); if (pointIdx2 >= 0) { decimalpartlength2 = decimal2.Length - pointIdx2 - 1; //得到小数部分长度 integerpartlength2 = pointIdx2 == 0 ? 1 : pointIdx2; //得到整数部分长度,考虑小数点在第一位的情况 } else { integerpartlength2 = decimal2.Length; //得到整数部分长度 } decimal1=decimal1.Replace(".", ""); decimal2=decimal2.Replace(".", ""); //对齐小数部分 if (decimalpartlength1 < decimalpartlength2) { decimal1 = decimal1 + new string('0', decimalpartlength2 - decimalpartlength1); } if (decimalpartlength2 < decimalpartlength1) { decimal2 = decimal2 + new string('0', decimalpartlength1 - decimalpartlength2); } bi1 = BigInteger.Parse(decimal1); bi2 = BigInteger.Parse(decimal2); if (bi2.ToString() == "0") throw new DivideByZeroException("DivideByZeroError"); //throw new DivideByZeroException("DivideByZeroError") int rightpos = 0; //计算从右边数小数点的位置,用于还原小数点 int pows = integerpartlength2 - integerpartlength1; if (pows >= 0) { bi1 = bi1 * BigInteger.Pow(10, pows + 1); //放大被除数,确保大于除数 rightpos += pows + 1; } //确定小数位的精度 maxscale = Math.Max(decimalpartlength1, decimalpartlength2); if (CustomScale < 0) { CustomScale = maxscale; //CustomScale<0,表示精度由参数决定 } else { maxscale = Math.Max(maxscale, CustomScale); //得到最大的小数位数 } bi1 = bi1 * BigInteger.Pow(10, maxscale); //放大被除数,确保整数除法之后,能保留小数部分 rightpos += maxscale; BigInteger d = bi1 / bi2; //注意整数除法的特点:会丢掉小数部分 string result = d.ToString(); if (rightpos > result.Length) { result = "0." + new string('0', rightpos - result.Length) + result; //小数点后面的0补上,再还原小数点 } else { result = result.Insert(result.Length - rightpos, "."); //还原小数点 if (result.StartsWith(".")) result = "0" + result; //补上个位的0 } //超出精度截断 if (rightpos > CustomScale) result = result.Substring(0, result.Length - (rightpos - CustomScale)); //还原正负号 if (sign == -1) result = "-" + result; return result; } /// <summary> /// 判断字符串是不是数字:不能有两个小数点、负号只能在最前面、除了小数点和负号,只能是数字。 /// </summary> private static bool isNumeric(string strInput) { char[] ca = strInput.ToCharArray(); int pointcount = 0; for (int i = 0; i < ca.Length; i++) { if ((ca[i] < '0' || ca[i] > '9') && ca[i] != '.' && ca[i] != '-') return false; if ((ca[i] == '-') && (i != 0)) return false; if (ca[i] == '.') pointcount++; } if (pointcount > 1) return false; return true; }
如果需要快速的大数类,可以看看这个http://www.cnblogs.com/skyivben/archive/2008/07/25/1251697.html,
下载链接 https://bitbucket.org/ben.skyiv/biginteger