为何无法复现.NET浮点数精度问题?求有效演示示例
浮点数存储货币的精度问题:未复现问题的原因及有效示例
为什么你的两个示例没出现精度问题?
示例1分析
你用double累加0.2共101次(初始0.2+100次0.2)得到20.2,看起来精确是因为:
0.2的二进制是无限循环小数,但double的64位精度足够让累加后的误差极小,Console.WriteLine默认只输出少量小数位,会把误差掩盖掉。如果强制输出更多小数位,就能看到偏差。
示例2分析
这个例子本身就不是用来演示精度问题的——两次执行完全相同的0.1f + 0.2f操作,得到的浮点数结果是完全一致的,所以f == g必然为true,它没法体现浮点数的精度损失。
.NET下的有效演示示例
示例1:经典的0.1+0.2≠0.3
static void Main(string[] args) { double a = 0.1; double b = 0.2; double sum = a + b; Console.WriteLine($"0.1 + 0.2 = {sum}"); // 输出0.30000000000000004 Console.WriteLine($"sum == 0.3 ? {sum == 0.3}"); // 输出False // 用float演示更明显 float fa = 0.1f; float fb = 0.2f; float fsum = fa + fb; Console.WriteLine($"0.1f + 0.2f = {fsum}"); // 输出0.300000012 Console.WriteLine($"fsum == 0.3f ? {fsum == 0.3f}"); // 输出False }
运行后能直接看到浮点数加法的精度偏差,这是因为0.1和0.2在二进制浮点数中无法精确表示,相加后误差暴露。
示例2:多次累加后的误差累积(模拟货币多次交易)
static void Main(string[] args) { // 模拟每次消费0.1元,共消费100次 double total = 0.0; for (int i = 0; i < 100; i++) { total += 0.1; } Console.WriteLine($"累计消费(double):{total}"); // 输出9.999999999999998 Console.WriteLine($"是否等于10.0?{total == 10.0}"); // 输出False // 用decimal对比(货币推荐类型) decimal decTotal = 0.0m; for (int i = 0; i < 100; i++) { decTotal += 0.1m; } Console.WriteLine($"累计消费(decimal):{decTotal}"); // 输出10.0 Console.WriteLine($"是否等于10.0m?{decTotal == 10.0m}"); // 输出True }
这个例子能直观展示:用double处理小额多次累加时,误差会逐渐累积,最终和预期值偏离;而decimal是专门为精确十进制计算设计的,不会出现这类问题,适合存储货币。
示例3:货币计算中的精度损失放大
static void Main(string[] args) { // 模拟商品单价0.1元,购买3件 double price = 0.1; int quantity = 3; double total = price * quantity; Console.WriteLine($"总价(double):{total}"); // 输出0.30000000000000004 decimal decPrice = 0.1m; decimal decTotal = decPrice * quantity; Console.WriteLine($"总价(decimal):{decTotal}"); // 输出0.3 }
简单的乘法操作也能体现浮点数的精度问题,而decimal能保持精确。
内容的提问来源于stack exchange,提问作者Arctic
相关产品推荐
相关产品推荐

