Math.Sin дает мне странные ценности - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь создать радиальное меню FAB и определить позиции для всех кругов. У меня есть алгоритм, который теоретически работает просто отлично, однако, когда я на самом деле его запускаю, значение Y дает мне что-то странное.Я выложу свой код очень быстро

ВНИМАНИЕ, ЧТО ЭТА ЧАСТЬ НЕ ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО, ЕСЛИ ВАМ НЕ НУЖНО ССЫЛКА НА ЧТО ЗНАЧИТ ЗНАЧЕНИЕ

    public class FABContainer : AbsoluteLayout
    {
        public static int NUMBER_FOR_RING = 1;
        public static double ANGLE_INCREMENT = 360.0 / ((double)NUMBER_FOR_RING);
        public static double CENTER_RADIUS = 100;
        public static double WIDTH_MOD = 0.9;
        public FABContainer()
        {
            this.BackgroundColor = Color.Transparent;
            FAB fab = new FAB();
            List<InternalFAB> internals = new List<InternalFAB>();
            internals.Add(new InternalFAB(this, internals.Count)
            {
            });
            this.Children.Add(fab);
            foreach(InternalFAB f in internals) { this.Children.Add(f); };
        }
    }
    public partial class FAB : SuaveControls.Views.FloatingActionButton
    {
        public FAB()
        {
            this.HeightRequest = FABContainer.CENTER_RADIUS;
            this.WidthRequest = FABContainer.CENTER_RADIUS * FABContainer.WIDTH_MOD;
            Debug.WriteLine($"CREATING NEW CENTER WITH W: {this.WidthRequest} H: {this.HeightRequest}");
                this.Image = "Edit_Icon.png";
            this.BackgroundColor = Color.Transparent;
            this.CornerRadius = (int)this.HeightRequest;
        }
    }
    internal class InternalFAB : SuaveControls.Views.FloatingActionButton
    {
        public static double DIST = 5;
        public EventHandler OnClicked;
        public static double radius = 80;
        public InternalFAB(FABContainer container, int count)
        {
            this.HeightRequest = (radius);
            this.WidthRequest = (radius * FABContainer.WIDTH_MOD * 0.95);
            this.BackgroundColor = Color.Transparent;
            int index = count + 1;
            double AngleDistortion = ((double)index) * FABContainer.ANGLE_INCREMENT;

            double xpos = (DIST + this.WidthRequest) * (Math.Cos((Math.PI / 180.0) * AngleDistortion));
            double ypos = (DIST + this.HeightRequest) * (Math.Sin((Math.PI / 180.0) *AngleDistortion));

            Debug.WriteLine($"CREATING NEW INTERNAL AT: {xpos},{ypos} from distortion {AngleDistortion}");

            this.TranslationX = xpos;
            this.TranslationY = ypos;
        }
    }

Byкстати, это не должно иметь значения, но это использование Xamarin.По сути, та часть, которая на самом деле имеет значение и создает для меня проблему, состоит в следующем:

double AngleDistortion = ((double)index) * FABContainer.ANGLE_INCREMENT;

double xpos = (DIST + this.WidthRequest) * (Math.Cos((Math.PI / 180.0) * AngleDistortion));
double ypos = (DIST + this.HeightRequest) * (Math.Sin((Math.PI / 180.0) *AngleDistortion));

Debug.WriteLine($"CREATING NEW INTERNAL AT: {xpos},{ypos} from distortion {AngleDistortion}");

По любой причине значение Y возвращается как -2.08183080149804E-14 , а не 0что он должен вернуться в «идеальном» случае.Я тщательно просмотрел свой код, чтобы попытаться найти ошибку, но безрезультатно.

Если вам понадобятся дополнительные разъяснения по поводу моего кода, я сразу же сообщу вам об этом.

Ответы [ 2 ]

4 голосов
/ 12 марта 2019

Вы работаете с двойниками, выполняя арифметику с плавающей запятой .То есть все, что вы делаете, является приблизительным.Если вам нужны точные значения, возможно, C # не ваш язык перехода.Mathematica поддерживает такие значения.

0 голосов
/ 12 марта 2019

Умножение на 85 не имеет значения для этой проблемы, поэтому я оставлю это в стороне и просто посмотрю (эффективно) Math.Sin(Math.PI * 2).Результатом этого является -2.44921270764475E-16 на моей машине.

То, что арифметика с плавающей точкой не является точной, играет роль, конечно, но результат не является какой-то произвольной ерундой.Здесь происходит то, что в непосредственной близости от x = 2pi, sin (x) ≈x - 2pi.Однако, Math.Sin(Math.PI * 2) не не оценивает синус точно в 2pi, он не может, 2pi трансцендентен и определенно не может быть представлен как число с плавающей запятой.Ввод в синус уже слегка «выключен» и имеет некоторое значение v=fl(2pi), где fl округляет значение до ближайшего представимого числа с плавающей запятой.Тогда sin(v) ≈ v - 2pi, потому что v около 2pi.

Таким образом, результат Math.Sin(Math.PI * 2) должен приблизительно представлять, как далеко 2 пи, которые мы передали в качестве аргумента, от real 2 пиMath.PI * 2 имеет точное значение 6,28318530717958623199592693708837032318115234375 на моей машине, в соответствии с Wolfram Alpha , то есть -2,4492935982947063544521318645500 ... × 10 ^ -16 от real 2 pi, что составляетдовольно близко к этому -2.44921270764475E-16 значению из ранее.Это не совсем там, но достаточно близко, чтобы подчеркнуть, что это не просто нечто произвольное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...