首页 / C# 入门教程 / 整型与浮点型

C# 入门教程

整型与浮点型

本教程共 100 篇 · 第 10 篇 · 更新于 2026-07-31 · 约 9 分钟阅读

C#C# 入门教程整型浮点型decimal数据类型

10. 整型与浮点型

本节目标:分清各类整数类型和小数类型的范围与精度,记住”金额必须用 decimal”这条铁律。

数字是最常用的数据,但 C# 里”数字”分好几类。选错类型,轻则浪费内存,重则算错钱。这一章把整型和浮点型一次讲清。

整型(integral types)

整型(integral types)只装没有小数部分的数字。按”能装多大”分成几种:

类型关键字大致范围占用
字节byte0 ~ 2551 字节
短整型short±3 万左右2 字节
整型int±21 亿左右4 字节
长整型long极大(约 ±9×10¹⁸)8 字节

日常开发,int 是默认选择。人数、个数、序号用 int 足够。long 留给可能超 21 亿的场景,比如文件大小、时间戳毫秒。

namespace CSharpDemo;

int peopleCount = 100;
long fileSize = 9_000_000_000L;   // 长整型字面量加 L 后缀
byte age = 18;
Tip

数字中间的下划线 _ 是 C# 的数字分隔符,纯为提高可读性,编译时忽略。9_000_000_0009000000000 完全等价。

为什么 C# 要提供这么多档位?本质是在”省内存”和”够用”之间取舍。一个 byte 只占 1 字节,能装 0~255,适合表示颜色分量、单字节标志;而 int 占 4 字节却什么计数都够。对普通业务代码,内存不是瓶颈,int 最省心;只有在处理海量数据或二进制协议时,才值得为每字节精打细算。所以原则很明确:默认 int,超大用 long,只有在”必须用更小类型”的硬性场景才上 byte/short

浮点型:带小数的数

需要小数时,用浮点型(floating-point types)。C# 有三个:floatdoubledecimal。它们的区别在精度用途

类型关键字精度后缀用途
单精度float约 7 位有效数字f对精度不敏感的科学计算
双精度double约 15–16 位d(可省)通用小数、图形、物理
精确小数decimal28–29 位有效十进制m金额、财务计算

这里”精度”指的是”能精确表示多少位有效数字”。float 约 7 位,意思是超过 7 位的数字它就开始存不准;double 约 1516 位,足够绝大多数科学测量;decimal 高达 2829 位十进制数字,专门为了把钱算得分毫不差。

为什么不只是用 double

double 看似万能,但它用二进制近似表示小数,某些十进制小数存不准:

namespace CSharpDemo;

double a = 0.1;
double b = 0.2;
Console.WriteLine(a + b);   // 输出 0.30000000000000004

0.1 + 0.2double 里不等于 0.3,而是多了个微小误差。对物理模拟无所谓,对”算账单”却是灾难——差一分钱财务都不答应。

为什么会这样?因为计算机底层用二进制存数,就像十进制没法精确写出 1/3(只能写 0.3333…),二进制也没法精确写出 0.1,只能存一个极接近的近似值。一次近似看不出,累加成千上万次后误差就被放大,账目就对不上了。decimal 改用十进制存储,正好绕开这个坑——它就是把你写的十进制小数原样保留。

金额必须用 decimal

decimal 用十进制表示,专门为金融设计,能精确存 0.1 这类数:

namespace CSharpDemo;

decimal price = 9.99m;          // m 后缀不可省
decimal quantity = 3;
decimal total = price * quantity;
Console.WriteLine(total);      // 29.97,精确

记住本教程的约定示例:decimal price = 9.99m。那个 m 告诉编译器”这是 decimal 不是 double”,漏写会报错或悄悄变成 double。

Note

decimal 不是”无限精确”,只是它在十进制下表现正确,适合钱。float/double 适合测量值(温度、长度),不适合计数和金额。

Warning

这条是铁律,值得反复强调:凡是钱,全程 decimal,别让 double 混进来。 哪怕只是一处 double 参与计算,误差就会潜伏进结果,可能几天后才在月结对账时爆发,极难排查。常量也带 mconst decimal Tax = 0.13m;

一个踩坑现场

double d1 = 1.0 / 3.0;     // 0.3333333333333333...
decimal m1 = 1.0m / 3.0m;  // 0.3333333333333333333333333333
Console.WriteLine(d1 == 0.333333333333333m);  // False,精度不同

比较两个小数是否相等也别直接用 ==,尤其 double,因为误差可能让”本该相等”的值不相等。金额比较常用”是否相差极小”或干脆用 decimal

类型推断时的默认

var 时,小数字面量默认被推断成 double,整数推断成 int

var x = 3.14;     // double
var y = 3.14m;    // decimal(因 m 后缀)
var z = 100;      // int

所以写金额务必带上 m,否则 var 给你的是 double,又掉回精度坑。

整数溢出会怎样

int 有上限(约 21 亿)。若累加超过上限,默认情况下值会”绕回”成负数,而不是报错:

int max = int.MaxValue;
Console.WriteLine(max + 1);   // 变成负数(溢出回绕)

这种”静默错误”很危险。如果你在做计数、编号这类不能出错的场景,可用 checked 块让溢出直接抛异常(详见第 12 章)。或者用更大的 long 兜底。

Note

默认不检查溢出是为性能考虑——每次算术都查一遍会拖慢运行。但安全敏感处请用 checked 显式开启,把隐患变明显。

Tip

如果你担心某个累加逻辑会越界,最简单稳妥的办法是”从一开始就选够大的类型”。比如数量可能很大的场景直接用 long,比事后加 checked 更省心。

该用 float 还是 double

绝大多数情况用 double:它精度更高,且是 var 推断小数字面量的默认。只有在两种特殊场景才用 float

  1. 和强制要求 float 的旧库/图形 API 对接。
  2. 海量数值且内存极敏感(如百万级浮点数组),float 省一半内存。

日常业务代码,别为了”省内存”盲目用 float,精度损失往往更贵。

整数相除想留小数怎么办

这是新手高频坑:两个 int 相除,C# 会做整数除法,直接丢弃小数部分。

int a = 5;
int b = 2;
Console.WriteLine(a / b);   // 输出 2,小数被丢

double result = (double)a / b;   // 2.5,先把一边转成 double
Console.WriteLine(result);

要保留小数,至少让参与运算的一边是小数类型。1.0 / 3(double)a / b 都行。记住一句话:要小数,先有小数字面量。

Warning

整数除法”静默丢小数”不会报错,结果看着还挺正常,所以特别容易埋坑。凡是做除法且希望有小数,先确认操作数里有小数类型,否则算出来的”平均值""比率”可能整型截断,逻辑全错。

常见疑问解答

问:byte、short 这么小,平时用得到吗? 偶尔。处理二进制协议、文件格式、网络包时,常按字节精确布局,这时 byte 是刚需。日常业务计数几乎都用 int,不必刻意用小类型”省内存”。

问:double 和 decimal 能混着算吗? 可以,但会发生隐式转换,且方向是 double 转 decimal 需显式。最佳实践是全链路统一:金额一律 decimal,测量值用 double,别让两者在表达式里相遇,免得精度规则打架。

问:整数相除想保留小数怎么办? 至少让一边是小数类型:1.0 / 3(double)a / b。若两边都是 int,C# 做整数除法直接丢小数。这是新手高频坑,记住”要小数,先有小数字面量”。

问:decimal 那么精确,是不是所有小数都用它? 不必。decimal 占用 16 字节、运算比 double 慢,且不适合科学/图形这类超大范围或需极小绝对误差的场景。它的定位就是”财务精确”。测量值、坐标、物理量仍用 double,各司其职。

要点速记

  • int 是默认整数;大数用 long;小范围用 byte/short
  • double 通用小数;float 仅特殊场景。
  • 金额必须用 decimal 且带 m 后缀。
  • double 有二进制误差,别拿它算钱或比相等。
  • 两个整数相除会丢小数,要小数先有小数字面量。

动手练一练

  1. decimal 表示三件商品单价 9.99m19.5m3.0m,计算总价并打印,体会金额用 decimal 的必要。
  2. double a = 0.1 + 0.2;,打印结果,再写 decimal b = 0.1m + 0.2m;,对比两者差异并解释。
  3. long 存一个超过 21 亿的数字(如 9_000_000_000L),确认 int 装不下而 long 可以。

浮点比较的工程做法

既然 double 有误差,工程上比较两个小数”是否相等”不用 ==,而是看”差的绝对值是否极小”:

double a = 0.1 + 0.2;
double b = 0.3;
bool equal = Math.Abs(a - b) < 1e-9;   // 差小于十亿分之一算相等
Console.WriteLine(equal);

Math.Abs 取绝对值,1e-9 是科学计数法表示的极小量。这叫”容差比较”,是数值计算的基本功。当然,最省心的还是用 decimal 处理金额,从根上避开误差。

选类型的速查清单

记不住细节时,用这张表快速决策:

  • 计数、编号、年龄、数量 → int,超大用 long
  • 温度、长度、物理测量、图形坐标 → double
  • 单价、金额、税率、余额 → decimal(带 m)。
  • 二进制协议、单字节标志 → byte
Tip

一个实战原则:金额字段从数据库到界面全程 decimal,别在中间转成 double 算完再转回。转换一次就可能引入误差,且难以排查。

小结与下一步

整数用 int(大数用 long);小数通用 double,但钱一律 decimalm。精度不是小事,选对类型,账目才不会差那一分。整数相除别忘丢小数,溢出要用 checked 或更大类型兜底。

下一章看字符与布尔:charbool 这两个看似简单却很重要的小类型。