yuanrui / blog

Some notes.
http://yuanrui.github.io
3 stars 0 forks source link

C# float换算精度丢失问题 #30

Open yuanrui opened 4 years ago

yuanrui commented 4 years ago

项目中有一个和其他系统进行经纬度对接的需求,传入的经纬度是float类型,而我们用的decimal进行存储。 最开始的时候使用Convert.ToDecimal进行转换,只取到了小数点的后4位。而float最大可以表示7位小数,转换过程出现了精度丢失的bug.

float input = 106.6509332F;
Console.WriteLine(input);
Console.WriteLine(Convert.ToDecimal(input));

//输出
//106.6509
//106.6509

改进思路,将float类型强制转换为double,再转换成decimal。代码如下

float input = 106.6509332F;
Console.WriteLine(input);
Console.WriteLine(Convert.ToDecimal((double)input));
Console.WriteLine(input.ToString("G9"));

//输出
//106.6509
//106.650932312012
//106.65093

在数值字符串格式时,使用格式G9处理可以保留9位数字,优先保留整数位,小数个数=9-整数位个数。

float input2 = 865569.6509332F;
Console.WriteLine(input2);
Console.WriteLine(input2.ToString("G9"));

//输出
//865569.6
//865569.625

float转decimal出现精度问题,究其原因,float类型使用4字节进行存储,decimal使用16字节进行存储,低字节向高字节之间转换需要进行字节填充,这个填充有可能是不准确的。选用浮点类型进行数值存储时,需要慎重考虑精度丢失问题。

C# 类型/关键字 大致范围 精度 大小 .NET 类型
float ±1.5 x 10−45 至 ±3.4 x 1038 大约 6-9 位数字 4 个字节 System.Single
double ±5.0 × 10−324 到 ±1.7 × 10308 大约 15-17 位数字 8 个字节 System.Double
decimal ±1.0 x 10-28 至 ±7.9228 x 1028 28-29 位 16 个字节 System.Decimal

参考链接:

浮点数值类型

标准数字格式字符串