浮点加法在.NET中给出了错误的结果?

时间:2013-11-21 17:23:59

标签: c# floating-point-precision

首先,为了清楚起见我不是在谈论浮点后的小数精度,我在这里读了很多答案。我的问题有点不同,我真的很想知道为什么会这样。

所以这就是(这是在C#.NET 4中尝试过的):

如果你可以说浮动的200,000个数字的列表实际上是整数,并且可以说这些数字可以在1.00F到500.00F的任何范围内,如果你在一个循环中求和它们就得到一个数字X (假设没有溢出)。

如果你有一个带有整数(相同数字)的相同列表并且你在循环中求它们实际上得到Y并且这些数字非常不同,差异几乎高达5%。

我们尝试了这个并得到结果44 465 501作为X和43 185 788作为Y结果。正如你所看到的,这几乎就像110 000的差异。并且X并不总是大于Y(如果最小有效十进制值不为0,我认为应该发生这种情况。)

我的想法是,只有当你有实际的十进制数(例如3.3或124.23)时才会发生这种情况,但如果你有整数但输入为浮点数似乎也会发生这种情况。

谁能告诉我这是为什么?我知道浮点数在最小有效十进制值上有错误但我不知道当你实际上将整数作为浮点数时这也存在。

感谢您的回答:)

编辑,这就是测试方法(在LINQPAD中):

using (SqlConnection connection = new SqlConnection(@"CONNECTION"))
{
SqlCommand command = new SqlCommand("select total_time = CAST(total_time as int) from test333", connection);
command.Connection.Open();
var reader = command.ExecuteReader();
float suma = 0;
while (reader.Read())
suma += (int)reader[0];
suma.Dump();
}

价值观是:

float -> 4,323257E+07
int -> 43125788

对不起,差异不是1.3百万,大约是110 000

2 个答案:

答案 0 :(得分:0)

我无法复制你的问题 - 我创建了一个测试循环来解析1到500之间的数字“字符串”列表:

void Main()
{
    var r = new Random();

    int count = 200000;
    var nums = Enumerable.Range(1,count)
                            .Select(i => r.Next(500).ToString())
                            .ToList();

    float sumD = nums.Sum(s => float.Parse(s));
    int sumI = nums.Sum(s => int.Parse(s));

    sumD.Dump();
    sumI.Dump();
}

sumDsumI每次都在10以内(由于下面描述的float精度限制)。您的号码列表不同或某些号码包含小数部分。

可能float的精度限制引起。 float只能存储7位数的精度,因此一旦总数超过7位,您将失去右侧的最低有效数字(例如49,983,710而不是49,983,711)。

那就是说 - 我看不出差异会如你所说的那么戏剧化 - 我的第一个猜测是:

  1. 您的列表不是完全相等
  2. 你列出 有一些小数部分
  3. 您的求和逻辑中存在一个错误,可能会加剧float的精度限制。

答案 1 :(得分:0)

float只有24位尾数,因此它只能表示高达16,777,216的连续整数。换句话说,16777216f + 1f == 16777216

如果你使用double,你将得到53位,在你的总和达到9,007,199,254,740,992之前不会有这个问题。