首页 > 解决方案 > 传播更改时如何提高数值稳定性

问题描述

我正在尝试沿数字列表传播更改的值。
变化很小,但列表中的值可能很大。
这会导致一些我想防止的数值不稳定。

例子:

    public class Polyline
    {
        private List<Vector3> points = new List<Vector3>();

        // For every point in points, contains the total polyline length
        // from the first point up to this point.
        private List<double> distances = new List<double>({0.0});

        [...]

        public void Insert(int index, Vector3 point)
        {
            points.Insert(index, point);

            if (points.Count >= 2)
            {
                double change;

                if (index == 0)
                {
                    // Point gets inserted at the start of the polyline
                    distances.Insert(0, 0f);
                    change = VectorMath.PreciseDistance(points[1], point); 
                }
                else if (index == points.Count - 1)
                {
                    // Point gets inserted at the end of the polyline
                    change = 0.0;
                    var length = VectorMath.PreciseDistance(point, points[index - 1]);
                    var prevLength = distances[distances.Count - 1];
                    distances.Add(prevLength + length);
                }
                else
                {
                    // Point gets added somewhere inside the polyline
                    var prev = points[index - 1];
                    var next = points[index + 1];
                    var prevLength = distances[index - 1];

                    // Get the edge lengths of the resulting triangle (prev, point, next)
                    var l0 = VectorMath.PreciseDistance(point, prev);
                    var l1 = VectorMath.PreciseDistance(next, point);
                    var lOld = distances[index] - prevLength;

                    distances.Insert(index, prevLength + l0);

                    change = l0 + l1 - lOld;
                }

                // Propagate the distance change along subsequent distances
                for (var i = index + 1; i < distances.Count; i++)
                {
                    distances[i] += change;
                }
            }
        }
    }

    public static class VectorMath
    {
        // Calculates the distance as precise as possible
        public static double PreciseDistance(Vector3 a, Vector3 b)
        {
            var x = (double) (a.x) - b.x;
            var y = (double) (a.y) - b.y;
            var z = (double) (a.z) - b.z;

            return Math.Sqrt(x * x + y * y + z * z);
        }
    }

在这个例子中,我有一个折线类,它存储它的点,还有一个距离列表。
这些距离表示折线到同一索引处的点的长度。

当折线很长时,插入会导致数值不稳定。
尤其是后面的条目,总长度很大,不精确性变得很大。

问题:
如何更改代码/系统,以便我仍然可以找到给定索引的总长度,而不必担心数值不稳定。
找到该长度应该很快,因此每次需要重新计算它是不可行的。

假设变化值足够精确。
另外我想防止使用双精度或小数,因为性能是一个大问题。

背景:
我的问题实际上是折线类。
如果可能的话,我想使用浮点精度来保持距离,因为框架的其余部分也使用浮点数。

了解不稳定性:
给定随机插入的 1000 个点,总长度约为 5000 个单位。
实际长度与最后一个距离条目中存储的总长度之差约为+-0.2f。

注意:
在原始帖子中,我使用浮点数来表示距离。
正如@derHugo 正确指出的那样,浮点数的精度约为 6-9 位,因此该错误是意料之中的。
但是,将所有内容更改为 double 后(除了 Vector3 -> Unity 类),数值误差仅减少了大约一位数。
因此问题仍然存在。

我添加了Insert的完整源代码,也许我那里有错误......

标签: c#unity3dprecision

解决方案


推荐阅读