证明存在三个浮点数,使得 Associative 属性 of Addition 为 false
Proving three float numbers exist, such that Associative Property of Addition is false
我正在寻找三个浮点值,这样,
(A + B) + C != A + (B + C)
浮点值在 0.002 和 10 之间,显然这个问题有很多解决方案。我使用以下算法在 C# 中测试从 0.001 到 10.000 的所有值;我12分钟前开始测试了,现在还是运行.
for (float i = 0.002f; i < 10f; i = i + 0.001f)
{
for (float j = 0.002f; j < 10f; j = j + 0.001f)
{
for (float k = 0.002f; k < 10f; k = k + 0.001f)
{
float FirstAnswer = (i + j) + k;
float SecondAnswer = (j + k) + i;
if (FirstAnswer != SecondAnswer)
{
Console.Write("(" + i.ToString() + " + " + j.ToString() + ") + " + k.ToString() + " = " + FirstAnswer.ToString() + "\n");
Console.Write("(" + j.ToString() + " + " + k.ToString() + ") + " + i.ToString() + " = " + SecondAnswer.ToString() + "\n\n");
}
}
}
}
如您所见,我确保所有值始终是浮动的。我想浮点数加法的工作方式一定与常规的十进制加法不同,但我看不出其中的联系。是否有更好的算法通过查找给定范围内的所有值来使用浮点值证明加法的关联 属性 为假?
如果您想生成比较的所有变体并检查 场景实际上在不使用 EPSILON 进行结果比较的情况下失败,您可以使用 NUnit 框架和 RangeAttribute:
[Test]
public void TestFloatAddition([Range(0.002f,10f,0.001f] float a,
[Range(0.002f,10f,0.001f] float b,
[Range(0.002f,10f,0.001f] float c)
{
Assert.AreEquals((a + b) + c, a + (b + c));
}
此代码将为每个 a
、b
和 c
生成测试,您可以在一个会话中 运行 它。
调试版本和发布版本之间存在差异。如果我 运行 你的程序的 DEBUG 版本,我没有输出。
如果我 运行 一个 RELEASE 构建,我会得到很多输出。
如果按如下方式更改程序,即使在调试版本中也会得到一些输出。正如您将看到的,我只是分步计算这些值:
for (float i = 0.002f; i < 10f; i = i + 0.001f)
{
for (float j = 0.002f; j < 10f; j = j + 0.001f)
{
for (float k = 0.002f; k < 10f; k = k + 0.001f)
{
float FirstAnswer = (i + j);
FirstAnswer += k;
float SecondAnswer = (j + k);
SecondAnswer += i;
if (FirstAnswer != SecondAnswer)
{
Console.Write("(" + i.ToString() + " + " + j.ToString() + ") + " + k.ToString() + " = " + FirstAnswer.ToString() + "\n");
Console.Write("(" + j.ToString() + " + " + k.ToString() + ") + " + i.ToString() + " = " + SecondAnswer.ToString() + "\n\n");
}
}
}
}
我正在寻找三个浮点值,这样, (A + B) + C != A + (B + C)
浮点值在 0.002 和 10 之间,显然这个问题有很多解决方案。我使用以下算法在 C# 中测试从 0.001 到 10.000 的所有值;我12分钟前开始测试了,现在还是运行.
for (float i = 0.002f; i < 10f; i = i + 0.001f)
{
for (float j = 0.002f; j < 10f; j = j + 0.001f)
{
for (float k = 0.002f; k < 10f; k = k + 0.001f)
{
float FirstAnswer = (i + j) + k;
float SecondAnswer = (j + k) + i;
if (FirstAnswer != SecondAnswer)
{
Console.Write("(" + i.ToString() + " + " + j.ToString() + ") + " + k.ToString() + " = " + FirstAnswer.ToString() + "\n");
Console.Write("(" + j.ToString() + " + " + k.ToString() + ") + " + i.ToString() + " = " + SecondAnswer.ToString() + "\n\n");
}
}
}
}
如您所见,我确保所有值始终是浮动的。我想浮点数加法的工作方式一定与常规的十进制加法不同,但我看不出其中的联系。是否有更好的算法通过查找给定范围内的所有值来使用浮点值证明加法的关联 属性 为假?
如果您想生成比较的所有变体并检查 场景实际上在不使用 EPSILON 进行结果比较的情况下失败,您可以使用 NUnit 框架和 RangeAttribute:
[Test]
public void TestFloatAddition([Range(0.002f,10f,0.001f] float a,
[Range(0.002f,10f,0.001f] float b,
[Range(0.002f,10f,0.001f] float c)
{
Assert.AreEquals((a + b) + c, a + (b + c));
}
此代码将为每个 a
、b
和 c
生成测试,您可以在一个会话中 运行 它。
调试版本和发布版本之间存在差异。如果我 运行 你的程序的 DEBUG 版本,我没有输出。
如果我 运行 一个 RELEASE 构建,我会得到很多输出。
如果按如下方式更改程序,即使在调试版本中也会得到一些输出。正如您将看到的,我只是分步计算这些值:
for (float i = 0.002f; i < 10f; i = i + 0.001f)
{
for (float j = 0.002f; j < 10f; j = j + 0.001f)
{
for (float k = 0.002f; k < 10f; k = k + 0.001f)
{
float FirstAnswer = (i + j);
FirstAnswer += k;
float SecondAnswer = (j + k);
SecondAnswer += i;
if (FirstAnswer != SecondAnswer)
{
Console.Write("(" + i.ToString() + " + " + j.ToString() + ") + " + k.ToString() + " = " + FirstAnswer.ToString() + "\n");
Console.Write("(" + j.ToString() + " + " + k.ToString() + ") + " + i.ToString() + " = " + SecondAnswer.ToString() + "\n\n");
}
}
}
}