.NET数字类型总结
.Net中数字类型有很多种,一直都没什么留意各种用法,因为MSDN都有很详细的介绍;最近项目中要进行许多大数字的计算和格式化、校验,下面做一些总结。
- 范围和精度
表示小数类型有float、double、decimal。
类型 | 大致范围 | 精度 | 初始化后缀 |
float | -3.4 × 1038 到 +3.4 × 1038 | 7 | f或F |
double | ±5.0 × 10−324 到 ±1.7 × 10308 | 15到16 | d或D |
decimal | (-7.9 x 1028 - 7.9 x 1028) / (100 - 28) | 28到29 | m或M |
以上是来自msdn的数据
float:http://msdn.microsoft.com/zh-cn/library/vstudio/b1e65aza.aspx
double:http://msdn.microsoft.com/zh-cn/library/vstudio/678hzkk9.aspx
decimal:http://msdn.microsoft.com/zh-cn/library/vstudio/364x0z75.aspx
解释一下“大致范围”。首先,以上数据类型都有2个常数的变量:MaxValue、MinValue,他们的值如下所示。
Console.WriteLine(float.MaxValue); //3.402823E+38 Console.WriteLine(float.MinValue); //-3.402823E+38 Console.WriteLine(double.MaxValue); //1.79769313486232E+308 Console.WriteLine(double.MinValue); //-1.79769313486232E+308 Console.WriteLine(decimal.MaxValue); //79228162514264337593543950335 Console.WriteLine(decimal.MinValue); //-79228162514264337593543950335
float的MaxValue和MinValue正对应表中“大致范围”的2个值。
double的MaxValue和MinValue也是对应表中的“大致范围”的2个值,那前面的±5.0 × 10−324 表示的是double的Epsilon属性。
Epsilon的解释是,表示大于零的最小正 Double 值。其实就是最接近0的数字,如果一个double值大于0且小于Epsilon,这个值会被认为跟0相等。
其实float也有Epsilon属性,值为1.4013E-045;因此个人认为,MSDN文档应该把float的“大致范围” 写成像double那样(±1.4 × 10−45 到 ±3.4 × 1038)。
PS. 这个值跟计算机平台有关系,在 ARM 系统中,值Epsilon常量太小,无法检测到,因此它相当于零,使用时要慎重。
decimal的MaxValue和MinValue看得出,全部都是数字精度一直到29位。大致范围的(-7.9 x 1028 - 7.9 x 1028) / (100 - 28),意思就是它的精度最大(小)值可以到29位。
至于这里“精度”的意思,其实是有效位数(包括整数和小数),超过有效位数的计算或显示均以四舍五入截取,其他以0显示。
float的精度为7位,由以下例子可见,不管整数还是小数加起来只显示7位。
string format = "N10"; //显示成数字,并显示10位小数 float fNumber = 1234.56789f; Console.WriteLine(fNumber.ToString(format)); //输出1,234.5680000000 fNumber = 123456789f; Console.WriteLine(fNumber.ToString(format)); //输出123,456,800.0000000000
double的精度为15到16位,其实就是15位有效数字,16是包含小数点的意思;javascript的number就是等价于double。
decimal的精度为28到29位,是最高精度的数字类型,适合金额、财务等计算。
计算如果涉及小数显示,在选择数字类型时,要注意精度。
- 转换和格式化
另外,如果程序是需要在其他国家语言系统运行的,在数字的格式化方面也要有所注意。
所有基础类型,包括之前的3个小数类型,都是有:Parse的静态方法,可以支持从字符串转换到基础类型(还有TryParse);同是也有ToString格式化显示数字。
但由于国家语言、业务类型的差异,标识小数、千分位、符号表示方式、钱币符号位置等都有所差异。
打个比方,字符串"100,000",在中文、英文的语言规范中,都是代表十万这个数字;但在另一些国家语言(如法国),小数点符号为",","."才是千分号。
那这时程序如果在从字符串转换为数字类型的时候,直接如下这样写的话,结果就会出现差异,甚至出现异常。
string numberStr = "1234,567"; double number = double.Parse(numberStr);
因为double.Parse是直接使用系统的语言格式化规范,因此会出现不可预知的行为。保险期间,最好使用Parse的重载,指定IFormatProvider。
public static double Parse(string s, IFormatProvider provider);
专门有一个为数字格式化的类,实现了IFormatProvider,叫NumberFormatInfo。
在每个语言的CultureInfo实例中,都有NumberFormat属性,它是专属于那个语言的数字格式。
PS:CultureInfo包含了各种文化格式,不单止NumberFormat,还有DateTimeFormat等。格式化需要传入一个代表语言的名字或者代号,名字和代号规范请看
http://msdn.microsoft.com/zh-cn/library/system.globalization.cultureinfo(v=VS.80).aspx 。
NumberFormatInfo,有很多数字格式的属性,都跟格式化显示有关,具体请看
http://msdn.microsoft.com/zh-cn/library/system.globalization.numberformatinfo(v=VS.80).aspx。