C#中的Decimal vs Double:精度之战(以及你的神经)
你是否曾经编写过工资计算器,或者,比如说,球的飞行模拟器,然后突然得到0.30000000000000004而不是预期的0.3?如果是的话——欢迎加入这个俱乐部。"decimal vs double! - Which one should I use and when?" 这个问题是Stack Overflow上最热门的问题之一,这并非没有原因。看起来这只是在两种浮点数类型之间做一个简单的选择。但实际上,这是在财务灾难和科学精度(或者反过来)之间做出选择。
在这篇文章中,我们将一劳永逸地剖析这场永恒的争论。您将了解到C#中的decimal类型与double类型有何不同,在何处应用哪种类型,以及最重要的是——如何在2025年避免犯错。我们开始吧!
快速了解核心:引擎盖下隐藏着什么?
在我们开始抛出论点之前,让我们先看看规范。每种类型都有自己的架构,而这正是决定它在何处为王、在何处被排斥的关键。
Double(即System.Double)
- 大小:64位(8字节)。
- 精度:大约15-17位有效数字。
- 范围:非常大(从±5.0 × 10−324 到 ±1.7 × 10308)。
- 表示方式:符合IEEE 754标准的浮点数(二进制)。
- 性能:高。处理器针对double运算进行了优化。
Decimal(即System.Decimal)
- 大小:128位(16字节)。
- 精度:28-29位有效数字。
- 范围:较小(从±1.0 × 10−28 到 ±7.9 × 1028)。
- 表示方式:十进制(本质上是一个带有小数点偏移的整数)。
- 性能:较低。CPU没有硬件支持,所有计算都是软件实现的。
需要记住的主要区别是:double是二进制小数,而decimal是十进制小数。正是因为这个原因,才产生了著名的“舍入误差”。
为什么double会“搞砸”金钱,却非常适合科学计算?
想象一下,您试图用二进制系统表示数字0.1。这将是一个无限循环小数:0.0001100110011...。计算机会将其截断,从而产生一个微小但关键的误差。对于科学计算(天气模拟、物理、图形学),这种误差会累积,但在可接受的范围内。对于金融来说,这意味着从百万用户那里“偷走”了一分钱。
而Decimal将数字存储为整数(例如,1/10 = 0.1存储为整数1以及小数点需要向左移动一位的信息)。因此,decimal的精度对于十进制小数来说是完美的。
何时在C#中使用decimal?(剧透:用于金钱)
能拯救您项目的黄金法则是:在财务、货币和会计计算中使用decimal。如果您的变量中存储的是卢布、美元、贷款利率或增值税——您的选择是明确的。
以下是一个例子,说明为什么double对钱包来说是邪恶的:
using System;
public class MoneyExample{ public static void Main() { // 使用double的错误示例 double price = 10.99; double tax = 0.07; double totalDouble = price + (price * tax); Console.WriteLine($"Double total: {totalDouble}"); // 可能输出 11.759300000000001
// 使用decimal的正确示例 decimal priceDec = 10.99m; decimal taxDec = 0.07m; decimal totalDec = priceDec + (priceDec * taxDec); Console.WriteLine($"Decimal total: {totalDec}"); // 精确结果:11.7593 }}看到这个“多余的