一些经验丰富的人可以解释我今天发现的这个奇怪的错误吗? 当我用C#脚本加载表数据时,我得到的金额很奇怪。
事实证明,问题是类似功能的输出不同:
string amount_in_string = "1234567,15";
double amount_in_double = double.Parse(amount_in_string);
float amount_in_float = float.Parse(amount_in_string);
//amount_in_double = 1234567.15;
//amount_in_float = 1234567.13;
当float和double是相似的类型(浮点)时,为什么会得到不同的结果。像这样少量的精度可以有所作为吗?
答案 0 :(得分:6)
将“ 1234567.15”转换为double
时,结果是double
中可以表示的最接近的值,即1234567.1499999999068677425384521484375。尽管您在问题中报告该值为1234567.15,但实际值为1234567.1499999999068677425384521484375。当数值显示的位数有限时,将显示“ 1234567.15”。
将“ 1234567.15”转换为float
时,结果是float
中可表示的壁橱值,即1234567.125。尽管您报告该值为1234567.13,但实际值为1234567.125。当数值显示的位数有限时,可能会显示“ 1234567.13”。
观察到1234567超过1,048,576,即2 20 。 float
使用的32位浮点格式使用24位作为有效数字(数字的小数部分)。如果有效数的高位表示2 20 ,则低位表示2 20-23 = 2 -3 =⅛。这就是为什么您看到“ 1234567.15”转换为四舍五入到最接近的八分之一的值的原因。
答案 1 :(得分:2)
浮点数从不精确,它们是数字的表示形式。常用的例子是
1/3 + 1/3 = 2/3
...因此,浮点数.33333 + .33333
中的答案不是精确的2/3,而是.66666
。
长话短说,您无法转换为精确二进制数的更精确分数始终会有一个舍入数字。越精确,发生舍入误差的可能性就越大。
请记住,如果您执行多个不同的分数运算,您甚至可能会遇到多个不同的舍入错误,这些错误会使数字意外正确,甚至更进一步。
答案 2 :(得分:-1)
您可以看到结果的小提琴(这里也有文化问题)
https://dotnetfiddle.net/Lnv1q7
string amount_in_string = "1234567,15"; // NOTE THE COMMA in original
string amount_in_string = "1234567.15"; //my correct culture
double amount_in_double = double.Parse(amount_in_string);
float amount_in_float = float.Parse(amount_in_string);
Console.WriteLine(amount_in_string);
Console.WriteLine(amount_in_double);
Console.WriteLine(amount_in_float);
结果(分析错误的语言!)
1234567,15
123456715
1.234567E+08
结果(解析正确的文化!)
1234567.15
1234567.15
1234567
另一种用float
证明精度下降的
float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);
结果
float: 0.3333333
double: 0.333333333333333
decimal: 0.3333333333333333333333333333
浮点数仅应在某些精度损失不是非常有价值的情况下使用。这是因为浮点数是32位,十进制是128位 浮点数主要用在像素坐标中,精度的损失并不重要,因为消费者可以通过任何方式将位置转换为更精确的坐标。
除非您不关心(某些)精度的损失,否则应积极避免.NET浮动中的。除非您正在编写游戏,否则现在可能永远不会这样
这是银行业务问题的根源,当交易损失一分钱/分的百分之一/美分时,每笔交易看似看不见,但却导致大量“丢失”钱。
使用十进制