为什么会有所不同在C#中的浮点精度时圆括号分离时声明分开吗? [英] Why differs floating-point precision in C# when separated by parantheses and when separated by statements?
问题描述
我知道如何浮点精度在正常的情况下工作,但我无意中发现在我的C#代码一个奇怪的局面。
I am aware of how floating point precision works in the regular cases, but I stumbled on an odd situation in my C# code.
为什么不RESULT1和结果2完全相同的浮点值,这里
Why aren't result1 and result2 the exact same floating point value here?
const float A; // Arbitrary value
const float B; // Arbitrary value
float result1 = (A*B)*dt;
float result2 = (A*B);
result2 *= dt;
从的此页面我想通浮动算法是左关联的,这意味着价值进行评估,并在左到右的方式计算。
From this page I figured float arithmetic was left-associative and that this means values are evaluated and calculated in a left-to-right manner.
完整的源代码涉及到XNA的四元数。我不认为这是我的相关常量是什么,什么VectorHelper.AddPitchRollYaw()一样。如果我计算以同样的方式三角洲俯仰/卷/偏航角,但作为代码如下它没有通过测试通过就好了:
The full source code involves XNA's Quaternions. I don't think it's relevant what my constants are and what the VectorHelper.AddPitchRollYaw() does. The test passes just fine if I calculate the delta pitch/roll/yaw angles in the same manner, but as the code is below it does not pass:
X
Expected: 0.275153548f
But was: 0.275153786f
[TestFixture]
internal class QuaternionPrecisionTest
{
[Test]
public void Test()
{
JoystickInput input;
input.Pitch = 0.312312432f;
input.Roll = 0.512312432f;
input.Yaw = 0.912312432f;
const float dt = 0.017001f;
float pitchRate = input.Pitch * PhysicsConstants.MaxPitchRate;
float rollRate = input.Roll * PhysicsConstants.MaxRollRate;
float yawRate = input.Yaw * PhysicsConstants.MaxYawRate;
Quaternion orient1 = Quaternion.Identity;
Quaternion orient2 = Quaternion.Identity;
for (int i = 0; i < 10000; i++)
{
float deltaPitch =
(input.Pitch * PhysicsConstants.MaxPitchRate) * dt;
float deltaRoll =
(input.Roll * PhysicsConstants.MaxRollRate) * dt;
float deltaYaw =
(input.Yaw * PhysicsConstants.MaxYawRate) * dt;
// Add deltas of pitch, roll and yaw to the rotation matrix
orient1 = VectorHelper.AddPitchRollYaw(
orient1, deltaPitch, deltaRoll, deltaYaw);
deltaPitch = pitchRate * dt;
deltaRoll = rollRate * dt;
deltaYaw = yawRate * dt;
orient2 = VectorHelper.AddPitchRollYaw(
orient2, deltaPitch, deltaRoll, deltaYaw);
}
Assert.AreEqual(orient1.X, orient2.X, "X");
Assert.AreEqual(orient1.Y, orient2.Y, "Y");
Assert.AreEqual(orient1.Z, orient2.Z, "Z");
Assert.AreEqual(orient1.W, orient2.W, "W");
}
}
当然,误差小,仅在提出自己大量的迭代,但它给我带来一些伟大的headackes。
Granted, the error is small and only presents itself after a large number of iterations, but it has caused me some great headackes.
推荐答案
我找不到一个参考支持这一了,但我认为这是由于以下几点:
I couldn't find a reference to back this up but I think it is due to the following:
- 浮点运算在硬件提供的精确计算,这意味着他们可以用比
浮动
的更高的精度进行。 - 分配到中间
RESULT2
变量力量四舍五入回到浮动的精度,但对于单个表达式rsult1
完全计算的本地精密被舍去了。
- float operations are calculated in the precision available in the hardware, that means they can be done with a greater precision than that of
float
. - the assignment to the intermediate
result2
variable forces rounding back to float precision, but the single expression forrsult1
is computed entirely in native precision before being rounded down.
在一个侧面说明,测试float或double与 ==
总是危险的。微软单元测试提供了上午 Assert.AreEqual(浮点预期,实际浮动,浮动三角洲)
在这里,你会用适当的增量解决这个问题(基于float.Epsilon)
On a side note, testing float or double with ==
is always dangerous. The Microsoft Unit testing provides for am Assert.AreEqual(float expected, float actual,float delta)
where you would solve this problem with a suitable delta (based on float.Epsilon).
这篇关于为什么会有所不同在C#中的浮点精度时圆括号分离时声明分开吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!