在 C# 中,double 和 decimal 都是用来表示带小数的数值类型 ,但它们在内部表示、精度、性能和适用场景 上有本质区别。选择错误的类型可能导致严重精度问题(尤其在金融计算中)。
✅ 一句话总结区别
double:64 位双精度浮点数 ,基于 IEEE 754 标准 ,速度快、范围大,但有舍入误差 → 适合科学计算、图形、物理模拟。decimal:128 位高精度十进制数 ,无二进制舍入误差 ,专为金融和货币计算设计 → 精确但速度慢、范围小。
🔍 详细对比表
| 特性 | double |
decimal |
|---|---|---|
| 关键字 | double |
decimal |
| .NET 类型 | System.Double |
System.Decimal |
| 存储大小 | 64 位(8 字节) | 128 位(16 字节) |
| 精度 | 约 15-17 位有效数字 | 28-29 位有效数字 |
| 数值范围 | ±5.0 × 10⁻³²⁴ 到 ±1.7 × 10³⁰⁸ | ±1.0 × 10⁻²⁸ 到 ±7.9 × 10²⁸ |
| 内部表示 | 二进制浮点(以 2 为底) | 十进制浮点(以 10 为底) |
| 是否精确表示 0.1? | ❌ 不能(有舍入误差) | ✅ 能(精确) |
| 性能 | ⚡ 快(CPU 硬件直接支持) | 🐢 慢(软件模拟) |
| 默认字面量后缀 | 无(如 3.14 是 double) |
需加 m 或 M(如 3.14m) |
💥 关键区别:精度 vs 速度
❌ double 的经典陷阱:0.1 + 0.2 ≠ 0.3
double a = 0.1;
double b = 0.2;
double sum = a + b;
Console.WriteLine(sum == 0.3); // False!
Console.WriteLine(sum); // 0.30000000000000004
原因:
0.1在二进制中是无限循环小数,无法精确表示。
✅ decimal 精确计算:
decimal a = 0.1m;
decimal b = 0.2m;
decimal sum = a + b;
Console.WriteLine(sum == 0.3m); // True!
Console.WriteLine(sum); // 0.3
📌 字面量写法注意
// double(默认)
double d1 = 123.45; // OK
double d2 = 123.45d; // 显式 d 后缀(可选)
// decimal(必须加 m/M)
decimal m1 = 123.45m; // ✅ 正确
decimal m2 = 123.45; // ❌ 编译错误!会先当作 double,再隐式转换(可能丢失精度)
⚠️ 永远不要写
decimal x = 0.1;------ 这会先创建一个不精确的double,再转成decimal,错误已发生!
🧪 适用场景对比
✅ 使用 double 的场景:
- 科学计算(物理、工程)
- 图形渲染、游戏开发(坐标、速度)
- 机器学习、统计分析
- 对性能敏感、允许微小误差的场景
✅ 使用 decimal 的场景:
- 金融、会计、货币计算(必须精确到分)
- 税务计算
- 任何需要十进制精确表示的业务逻辑
- 用户输入的金额、价格等
💡 黄金法则 :
"涉及钱的地方,永远用decimal!"
⚠️ 常见误区
❌ 误区 1:decimal 能表示任意大的数
虽然
decimal精度高,但最大值只有约 7.9 × 10²⁸ ,远小于double的 10³⁰⁸。如果需要超大数,考虑
BigInteger(整数)或自定义类型。
❌ 误区 2:decimal 性能差到不能用
虽然比
double慢(约 10-20 倍),但在现代 CPU 上,一次decimal加法仍只需几十纳秒 。对于金融系统(每秒几百笔交易),完全够用。
❌ 误区 3:可以用 double 存金额,只要四舍五入
即使显示时四舍五入,内部累积误差仍会导致对账不平 !
例如:1000 次 0.1 元累加,
double可能变成 99.99999999999999。
✅ 最佳实践建议
| 场景 | 推荐类型 |
|---|---|
| 金额、价格、利率 | decimal |
| 科学/工程计算 | double |
| 数据库字段 | 金额用 DECIMAL(p,s),科学数据用 FLOAT/DOUBLE |
| API 设计 | 金融接口参数/返回值用 decimal |
| 常量定义 | public const decimal TaxRate = 0.13m; |
🧠 总结
| 问题 | 答案 |
|---|---|
| 哪个更精确? | decimal(十进制无误差) |
| 哪个更快? | double(硬件加速) |
| 存钱用哪个? | 必须用 decimal |
| 0.1 能精确表示吗? | double ❌,decimal ✅ |
| 字面量怎么写? | double: 3.14;decimal: 3.14m |
💡 记住 :
"double为速度而生,decimal为正确而战。"在金融世界里,一分钱都不能错 ------这就是
decimal的存在意义。
问题
double和float有什么区别
double占用64位内存,而float占用32位
什么是NaN
NaN表示非数字,它是double或float可以具有特殊值,0除以0的结果