This article is currently in the process of being translated into Chinese (~95% done).
Floating points
浮点数就是小数(通常以小数点表示)。为什么不简单地使用一种数据类型来处理数字呢(不论是小数还是整数),这是因为计算机处理整数要比处理小数快很多。因此,把它们分开是合理的 - 如果知道需要处理的只有整数,就选择整数类型。否则,就选择一种浮点数类型,这将在本章中介绍。
使用浮点数与使用整数一样简单,虽然有些与浮点数相关的事项需要特别注意,这些稍后会介绍。现在,先看一下最常用的浮点数类型是怎样定义的:double。
double number;
就象整数一样,定义时就可以赋值:
double number = 42.0;
对float和decimal类型也是一样的,稍后会介绍,不过,这里的写法略有不同:
double doubleVal = 42.0;
float floatVal = 42.0f;
decimal decimalVal = 42.0m;
注意赋值表达式中数字后面的“f”和“m”字母 - 它们告诉编译器,此处是一个float和decimal常量值。若没有它们,C#会把这些数字解释为双精度浮点数(double),不能自动转化为float或是decimal。
float, double还是decimal?
写程序时处理浮点数总会有很多问题与注意事项。比如,C#有最少三种类型可用来处理小数:
- float (System.Single类型的别名)
- double(System.Double类型的别名)
- decimal (System.Decimal类型的别名)
其内部的区别可能有点难以理解,除非对计算机内部的工作原理有较深的了解,因此这里重点就放在日常事务上。
通常,float, double和decimal数据类型的区别在于其精确程度,从而也在于保存这些类型所占用的内存量。float是占用资源最少的 - 占用7个比特位。double精度更高一些,占用16个比特位,而decimal精度是最高的,最多会占用到夸张的29个比特位。
为什么需要这些不同类型的精度呢,答案就在于那些与“数学相关的东西”。把10除以3是理解这种差异的一个经典例子。多数人心算就知道结果是3.33,而且也都知道这是一个不完全精确的结果。真正的结果应该是3.33后面还要跟一长串3 - 有多长,如果是通过C#来计算,就取决于使用的是那种数据类型。请看下例:
float a = 10f / 3;
Console.WriteLine(a);
double b = 10d / 3;
Console.WriteLine(b);
decimal c = 10m / 3;
Console.WriteLine(c);
这里进行了一样的计算,但是使用了不同的数据类型。结果象这样:
a: 3.333333
b: 3.33333333333333
c: 3.3333333333333333333333333333
差异很清晰,不过对多数需求来说,真正需要的精度有多高呢?
选择
首先,考虑需要多少比特位进行存储。float只有7个比特位,因此如果需要的数字比这还大,就应该考虑改用double或decimal。
其次,float和double都只能表示近似值 - 换言之,数字没法精确到最后一位数。这也意味着,一旦使用这些数字开始越来越多的计算,它们可能就不再象原来那么精确了,表示两个本该相等的值会突然间就变得不相等了。
因此,对于精度作为首要考量的情况,应该选择decimal。最好的的例子就是用来表示金融数字(钱) - 肯定不会有人希望记账时是10,结果却不是如此。而另一方面,如果性能更重要,就应该使用float(对于小的数字)或double(对于大的数字)。decimal由于其额外的精度,要比float慢很多 - 有测试结果显示会慢20倍以上!
总结
在性能优先于精度的情况下应该选择float或double对浮点数进行操作。反之,要获得最大程度的精度,且能接受低一些的性能,就应该选择decimal类型 - 尤其是在操作金融类数据的时候。
如果想更深入地了解这些数据类型更多的内部差异,可以参考这篇详细的文章:每个计算机科学家都应该了解的浮点数运算