C# 浮点数与定点数详细解析

C# 浮点数与定点数详细解析

在 C# 中,数值类型主要分为:

  • 整数型 (int, long 等)
  • 浮点型 (float, double)
  • 定点型 (decimal)

浮点数和定点数在内部的表示方式不同,导致它们的 精度、范围、性能、使用场景 都有明显区别。本文将详细剖析两者的原理与对比。


1️⃣ 浮点数(float / double)

1.1 表示方法(IEEE 754)

浮点数采用 二进制科学计数法 存储:

复制代码
值 = (-1)^符号位 × 1.尾数 × 2^(指数 - 偏移量)
  • 符号位:1 位,表示正负
  • 指数位:控制缩放大小
  • 尾数位:存储有效数字
类型 位数 符号位 指数位 尾数位
float 32 1 8 23
double 64 1 11 52

👉 范围极大,但精度有限。某些小数在二进制中无法精确表示。


1.2 小数的二进制表示

浮点数小数用 2 的负次方来组合:

复制代码
0.101₂ = 2⁻¹ + 2⁻³ = 0.5 + 0.125 = 0.625

但像 0.1 这样的十进制分数,在二进制中是无限循环小数:

复制代码
0.1₁₀ = 0.0001100110011...₂

只能近似存储 → 运算会出现误差。


1.3 常见误差示例

csharp 复制代码
Console.WriteLine(0.1 + 0.2 == 0.3);  // False
Console.WriteLine(0.1 + 0.2);         // 0.30000000000000004

原因:二进制截断 → 加法结果不是精确的 0.3。


1.4 特殊值

浮点数里其实还藏着几个特别的数,它们在实际开发里经常会遇到:

  • 正无穷 / 负无穷

    当结果太大,已经超过浮点数能表示的范围时,就会变成无穷大:

    • double.PositiveInfinity → 正无穷
    • double.NegativeInfinity → 负无穷
  • NaN(Not a Number,意思是"不是一个数")

    一些数学上不合法的运算会得到 NaN,比如:

    • 0.0 / 0.0
    • Math.Sqrt(-1)
      特别注意:NaN 和任何值比较(甚至跟自己比)都会是 false。
    csharp 复制代码
    Console.WriteLine(double.NaN == double.NaN); // false
  • +0 和 -0

    浮点数里其实区分正零和负零,不过在大多数运算里,它们没区别:

    • +0 == -0 结果是 true

    • 但在某些场景(比如除法)下会有区别:

      csharp 复制代码
      Console.WriteLine(1.0 / +0); // Infinity
      Console.WriteLine(1.0 / -0); // -Infinity

1.5 浮点数比较正确姿势

  1. 近似比较(epsilon 容差)
csharp 复制代码
bool IsEqual(double a, double b, double eps = 1e-10)
    => Math.Abs(a - b) < eps;
  1. 游戏开发常见做法(Godot / Unity)
csharp 复制代码
Mathf.Approximately(a, b);      // Unity
Mathf.IsEqualApprox(a, b);      // Godot
  1. 避免直接用 ==
    除非数据本身是整数运算得来的,或者特别确定是完全相等。

2️⃣ 定点数(decimal)

2.1 表示方法

  • 总共 128 位存储:

    • 96 位存有效数字
    • 16 位存小数位精度(scale,小数点位置)
  • 十进制方式存储 → 可以精确表示 0.1、0.2、0.3。


2.2 特点

  • 高精度(28-29 位有效数字)
  • 范围比 double 小,但能避免浮点误差
  • 计算速度比浮点数慢(大约 5~20 倍),因为是软件实现而不是硬件指令

2.3 示例

csharp 复制代码
decimal a = 0.1m + 0.2m;
decimal b = 0.3m;
Console.WriteLine(a == b); // True

👉 在货币、金融计算中,应优先使用 decimal。


3️⃣ 性能对比

特性 float/double(浮点数) decimal(定点数)
存储方式 二进制科学计数法 十进制定点数
精度 有误差(约 15~16 位) 高精度(28~29 位)
范围 极大 较小
运算速度 硬件支持,速度极快 慢(软件实现)
适用场景 科学计算、物理模拟 金融、货币

4️⃣ 小结

  • 浮点数 → 范围大、速度快,但存在精度误差
  • decimal → 精度高,适合金融,但性能较差
  • 判断浮点数相等时,应使用 近似比较 而不是 ==
  • 在游戏或物理模拟 → 用 float/double
  • 在账务、价格计算 → 用 decimal
相关推荐
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
神仙别闹2 天前
基于C#+MySQL实现(WinForm)个人聊天室软件
c#
伞伞悦读2 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
孙启超3 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int3 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
CoderYanger3 天前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
伞伞悦读3 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json