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