为什么会有所不同在C#中的浮点精度时圆括号分离时声明分开吗? [英] Why differs floating-point precision in C# when separated by parantheses and when separated by statements?

查看:159
本文介绍了为什么会有所不同在C#中的浮点精度时圆括号分离时声明分开吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道如何浮点精度在正常的情况下工作,但我无意中发现在我的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 for rsult1 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆