CodeGym /课程 /C# SELF /精度问题和特殊值

精度问题和特殊值

C# SELF
第 6 级, 课程 3
可用

1. 入门

你可能觉得,既然电脑“聪明”,那0.1 + 0.2应该就是0.3。但其实没那么简单。咱们来看个简单例子。

double x = 0.1;
double y = 0.2;
double sum = x + y;
Console.WriteLine(sum); // 程序会输出啥?
浮点数相加:我们以为是0.3,实际呢?

现在你试试和0.3比较一下:

Console.WriteLine(sum == 0.3); // 这会是true还是false?

如果你看到False,别惊讶!

原因在于内存里的数字表示方式

电脑用二进制来处理数字。但不是所有十进制小数都能用有限的二进制小数表示,就像1/3没法用有限的十进制小数写出来(0.333...)。比如0.1在二进制里就是无限小数,存的时候只能“凑合”着四舍五入。

说人话就是,double有时候“假装”能精确存你的数,其实只是存了个很接近的近似值。

2. 用double做运算会遇到哪些“神奇”现象?

咱们来看几个实际例子。

例子1. 经典的“魔法”0.1 + 0.2

double a = 0.1;
double b = 0.2;
double sum = a + b;
Console.WriteLine(sum);            // 0.30000000000000004
Console.WriteLine(sum == 0.3);     // False

电脑输出的不是0.3,而是0.30000000000000004。差别很小,但比如你做金融相关的,这就很要命了。

例子2. 循环累加

double result = 0;
for (int i = 0; i < 10; i++)
{
    result += 0.1;
}
Console.WriteLine(result); // 0.9999999999999999

你想要1.0,结果却小了一点。还是因为double内部的四舍五入。

为啥这些在实际开发中很重要

很多人觉得:“差一点点有啥关系嘛!”咱们举个支付领域的例子。

假如你的网银要把100笔0.1欧元的交易加起来。如果你的程序每次都“丢”掉一百万分之一欧元,放到银行的规模上,你就真的“丢钱”了。这时候财务就会来找你问:“我们的钱去哪了?!”

3. 怎么正确比较浮点数

因为double经常存不了你想要的那个精确值,直接用==比较可能会“坑”你。一般的做法是比较两个数的差的绝对值和一个很小的数(epsilon)。

带容差的比较例子

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.000001;

if (Math.Abs(a - b) < epsilon)
{
    Console.WriteLine("差不多等于!"); // 这样比较更靠谱
}

这里的意思是:“如果两个数的差小于一百万分之一,就当它们相等”。

4. double的特殊值:Infinity, NaN, -Infinity

double类型不仅能存数字,还能存一些特殊值。这些值出现在数学老师绝对不让你干的操作里。

正无穷(Infinity)

如果你让1除以0会咋样?

double result = 1.0 / 0.0;
Console.WriteLine(result); // Infinity

在C#(还有很多别的语言)里,double类型除以0不会报错!结果会变成特殊值“正无穷”。

负无穷(-Infinity)

如果你让负数除以0,就会得到负无穷:

double result = -1.0 / 0.0;
Console.WriteLine(result); // -Infinity

“不是数字”(NaN — Not a Number)

如果你做了很奇怪的操作,比如试图开负数的平方根:

double result = Math.Sqrt(-1);
Console.WriteLine(result); // NaN

或者让0.0 / 0.0:

double result = 0.0 / 0.0;
Console.WriteLine(result); // NaN

NaN就是“现实生活里根本不是数字的东西”。

怎么判断是不是特殊值

C#里有专门的函数来判断这些特殊值:

Console.WriteLine(double.IsInfinity(result));    // 如果是无穷就true
Console.WriteLine(double.IsNaN(result));         // 如果是NaN就true

表格:double遇到奇葩操作会咋样

操作 结果 double里存的内容
1.0 / 0.0
Infinity +∞
-1.0 / 0.0
-Infinity -∞
0.0 / 0.0
NaN 不是数字
Math.Sqrt(-1)
NaN 不是数字
2
任务
C# SELF, 第 6 级, 课程 3
已锁定
使用 epsilon 进行比较
使用 epsilon 进行比较
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION