在 C# 中实现银行家舍入法
在 C# 中实现银行家舍入法(四舍六入五成双)有几种方式。以下是完整的实现方案:
方法一:使用内置的 Math.Round(推荐)
C# 内置的 Math.Round 方法默认就使用银行家舍入法:
using System; public class BankersRoundingExample { public static void Main() { // 测试数据 double[] testNumbers = { 1.235, 1.245, 1.255, 1.265, 1.275, 1.285 }; Console.WriteLine("银行家舍入法示例(保留2位小数):"); foreach (double num in testNumbers) { double rounded = Math.Round(num, 2); Console.WriteLine($"{num:F3} -> {rounded:F2}"); } // 显式指定舍入规则 Console.WriteLine("\n显式指定舍入规则:"); double test1 = 1.235; double test2 = 1.245; Console.WriteLine($"{test1:F3} -> {Math.Round(test1, 2, MidpointRounding.ToEven):F2}"); Console.WriteLine($"{test2:F3} -> {Math.Round(test2, 2, MidpointRounding.ToEven):F2}"); // 对比传统四舍五入 Console.WriteLine("\n对比传统四舍五入:"); Console.WriteLine($"{test1:F3} -> 银行家: {Math.Round(test1, 2, MidpointRounding.ToEven):F2}, " + $"传统: {Math.Round(test1, 2, MidpointRounding.AwayFromZero):F2}"); } }
方法二:自定义实现
如果需要完全控制舍入逻辑,可以自定义实现:
using System; public static class BankersRounding { /// <summary> /// 自定义银行家舍入法实现 /// </summary> /// <param name="value">要舍入的值</param> /// <param name="decimals">小数位数</param> /// <returns>舍入后的值</returns> public static double CustomBankersRound(double value, int decimals) { if (decimals < 0) throw new ArgumentException("小数位数不能为负数", nameof(decimals)); double factor = Math.Pow(10, decimals); double scaledValue = value * factor; // 分离整数和小数部分 double integerPart = Math.Truncate(scaledValue); double fractionalPart = scaledValue - integerPart; // 应用银行家舍入规则 if (Math.Abs(fractionalPart) < 0.5) { // 四舍 return integerPart / factor; } else if (Math.Abs(fractionalPart) > 0.5) { // 六入 return (integerPart + Math.Sign(value)) / factor; } else { // 五成双:检查前一位数字的奇偶性 bool isEven = (integerPart % 2 == 0); return isEven ? integerPart / factor : (integerPart + Math.Sign(value)) / factor; } } /// <summary> /// 更精确的银行家舍入实现(处理边界情况) /// </summary> public static decimal PreciseBankersRound(decimal value, int decimals) { if (decimals < 0) throw new ArgumentException("小数位数不能为负数", nameof(decimals)); decimal factor = (decimal)Math.Pow(10, decimals); decimal scaledValue = value * factor; decimal integerPart = Math.Truncate(scaledValue); decimal fractionalPart = scaledValue - integerPart; // 使用绝对值进行比较,避免符号问题 decimal absFractional = Math.Abs(fractionalPart); if (absFractional < 0.5m) { return integerPart / factor; } else if (absFractional > 0.5m) { return (integerPart + Math.Sign(value)) / factor; } else { // 五成双规则 bool isEven = (Math.Abs(integerPart) % 2 == 0); return isEven ? integerPart / factor : (integerPart + Math.Sign(value)) / factor; } } }
方法三:自定义实现1
public decimal Banker(decimal value, int digital) { string strVal; int pPot; decimal result; if (value < 0) result = Math.Abs(value); else result = value; strVal = result.ToString(); pPot = strVal.IndexOf("."); if (pPot > 0 && pPot + digital + 1 < strVal.Length) { decimal ratio = (decimal)Math.Pow(10, digital); string usedVale = strVal.Substring(0, pPot + digital + 1); int nextNum = int.Parse(strVal.Substring(pPot + digital + 1, 1)); decimal baseVal = decimal.Parse(usedVale); if (nextNum > 5) { result = baseVal + 1 / ratio; } else if (nextNum < 5) { result = baseVal; } else { decimal elapse = 0; if (pPot + digital + 2 < strVal.Length) elapse = Math.Abs(decimal.Parse(strVal) - baseVal); if (elapse > 0) { result = baseVal + 1 / ratio; } else { if (digital > 0 && int.Parse(strVal.Substring(pPot + digital, 1)) % 2 != 0) { result = baseVal + 1 / ratio; } else if (digital == 0 && int.Parse(strVal.Substring(pPot - 1, 1)) % 2 != 0) { result = baseVal + 1 / ratio; } else { result = baseVal; } } } } if (value < 0) result = result * -1; return result; } //延长精度位数后的四舍五入+银行家舍入法 public decimal BankerEx(decimal value, int digital) { decimal result; if (value < 0) result = Math.Abs(value); else result = value; var ratio = (decimal)Math.Pow(10, digital); var scaledValue = RoundOld(result * ratio, digital - 1); var baseVal = Math.Truncate(scaledValue); var elapse = Math.Abs(scaledValue - baseVal); if (elapse > (decimal)0.5) result = (baseVal + 1) / ratio; else if (elapse < (decimal)0.5) result = baseVal / ratio; else result = (baseVal % 2 == 0 ? baseVal : baseVal + 1) / ratio; if (value < 0) result = result * -1; return result; } //传统四舍五入法 public decimal RoundOld(decimal value, int digital) { decimal result; if (value < 0) result = Math.Abs(value); else result = value; var ratio = (decimal)Math.Pow(10, digital); var scaledValue = result * ratio; var baseVal = Math.Truncate(scaledValue); var elapse = Math.Abs(scaledValue - baseVal); if (elapse < (decimal)0.5) result = baseVal / ratio; else result = (baseVal + 1) / ratio; if (value < 0) result = result * -1; return result; }
posted on 2025-11-13 10:52 wangzhiliang 阅读(1) 评论(0) 收藏 举报
浙公网安备 33010602011771号