Как исправить проблемы с точностью

У меня есть несколько классов, которые следуют той же базовой концепции для работы с юнитами.

Вот простой пример использования одного из них в модульном тесте:

    [Test()]
    public void Angle_MathOperatorTest()
    {
        Angle a1 = new Angle(AngleType.Degree, 360);
        Angle a2 = new Angle(AngleType.Radian, Math.PI * 2);

        Angle addedAngle = a1 + a2;
        addedAngle.Degrees.ShouldBeEquivalentTo(720);

        Angle subtractedAngle = a1 - a2;
        subtractedAngle.Radians.ShouldBeEquivalentTo(0);
    }

Я сделал несколько классов, как это продемонстрировал Angle Class, охватывающих другие основные типы юнитов.

Определенным классом, который показал мне, что у меня была проблема точности, было использование класса, который обрабатывает единицы длины: Dimension

Я помог построить базовую библиотеку геометрии, используя этот класс измерений в качестве базового типа единиц измерения. Например, вот класс Point:

public class Point
{

    public Dimension X;

    public Dimension Y;

    public Dimension Z;
}

Линии и другие фигуры имеют такие свойства, как длина, которые представлены измерениями и конечными точками, построенными с использованием этого класса точек.

Проблема становится очевидной, когда я пытаюсь определить, параллельны ли эти линии. Как в этой функции:

    /// <summary>
    /// checks to see whether every line is parallel
    /// </summary>
    /// <param name="passedLines">passed List of Lines</param>
    /// <returns></returns>
    public static bool AreAllParallel(this List<Line> passedLines)
    {

        for (int i = 0; i < passedLines.Count - 1; i++)
        {
            if (!passedLines[i].IsParallelTo(passedLines[i + 1]))
            {
                return false;
            }
        }

        return true;
    }

Он часто возвращает false, потому что проверяет слишком высокую точность. После выполнения Поворотов и Переводов с Точками и линиями, округление суммируется настолько, что эта функция возвращает false, когда я хочу, чтобы она возвращала true.

Так:

Какой набор из следующих вариантов является правильным / лучшим выбором?

  • просто проверяю такие функции, как IsParallelTo для чисел, которые находятся относительно близко (например, в пределах 0,0001 дюйма)

Если (Math.Abs ​​( thing.x - thing2.x) <.0001)

  • совершенствование предыдущей идеи с переменной константой, извлекаемой из файла конфигурации, что позволяет пользователю выбрать желаемое приемлемое отклонение

If(Math.Abs ​​( thing.x - thing2.x)

  • или уменьшение проблемы на корневом уровне в классе измерений:

Я могу использовать ту же стратегию

//inside Dimension Equals
public override bool Equals(object obj)
{
    return (Math.Abs(this.Inches - ((Dimension)(obj)).Inches)) < Constants.AcceptedEqualityDeviationConstant;
}

Это бы действительно выглядело так, но вышесказанное легче понять.

return (Math.Abs ​​(this.GetValue(this.InternalUnitType) - ((Dimension)(obj)).GetValue(this.InternalUnitType)))

Или, наконец, моя последняя идея состоит в том, чтобы заменить все в моих классах единиц на базовую единицу Decimal вместо Double (Размерность, Угол и т. Д.) До десятичного числа и каким-то образом (после изучения этого) выяснить, поможет ли это.


Как и где я должен улучшить последовательность точности в операциях равенства моих классов?

PS Библиотеки с открытым исходным кодом и могут быть найдены (Единицы здесь и Геометрия здесь)

1 ответ

Если e1 направление первой линии и e2 Затем для направления второй линии, чтобы проверить, параллельны ли они в пределах допустимого отклонения θ (радианы), выполните следующее (псевдокод):

bool is_parallel = |Cross(e1,e2)| <= |e1|*|e2|*Cos(θ)

где |v| это величина вектора и Cross() является векторным перекрестным произведением.

Другие вопросы по тегам