Math.Cos & Math.Sin в C # - PullRequest
       8

Math.Cos & Math.Sin в C #

8 голосов
/ 21 мая 2011

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

С примером ввода 90 градусов я преобразовываю значение в радианы с помощью следующего кода:

public double DegreeToRadian(float angle)
{
  return Math.PI * angle / 180.0;
}

Это дает мне 1,5707963267949 радиан. Тогда, когда я использую

Math.Cos(radians)

, я получаю ответ: 6.12303176911189E-17

Что за хреньпродолжается?Косинус 90 градусов должен быть 0, так почему я получаю такое отклонение ... и что более важно, как я могу остановить это?

Ответы [ 7 ]

14 голосов
/ 21 мая 2011

Позвольте мне ответить на ваш вопрос другим: Как вы думаете, как далеко 6.12303176911189E-17 от 0?То, что вы называете deviance , на самом деле связано со способом внутреннего хранения чисел с плавающей запятой.Я бы порекомендовал вам прочитать следующую статью .В .NET они хранятся с использованием стандарта IEEE 754 .

6 голосов
/ 21 мая 2011

См. Ответы выше. Помните, что 6.12303176911189E-17 - это 0,00000000000000006 (я мог даже пропустить ноль там!), Так что это очень и очень небольшое отклонение.

2 голосов
/ 21 мая 2011

Читайте по арифметике с плавающей запятой .Это никогда и никогда не может быть точным.Никогда не сравнивайте точно ни с чем, но проверьте, отличаются ли числа на (маленький) эпсилон.

1 голос
/ 05 января 2019

вы должны использовать округление

var radians = Math.PI * degres / 180.0;
var cos = Math.Round(Math.Cos(radians), 2);
var sin = Math.Round(Math.Sin(radians), 2);

результат будет: грех: 1 cos: 0

1 голос
/ 15 декабря 2017

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

Math.Sin(Math.PI) должен равен 0,
Math.Cos(Math.PI) должен равен -1,
Math.Sin(Math.PI/2) должен равен 1,
Math.Cos(Math.PI/2) должен равен 0 и т. Д.

Можно ожидать, что библиотека с плавающей запятой будет учитывать эти и другие тригонометрические идентификаторы , независимо от незначительных ошибок в своих постоянных значениях (например, Math.PI).

Тот факт, что вы получаете небольшую ошибку от Math.Cos(Math.PI/2), указывает на то, что реализация вычисляет результат, а не извлекает его из таблицы.Лучшая реализация Math.Cos и других трансцендентных функций может быть более точной для конкретных личностей.

Я уверен, что в случае C # такое поведение ожидается, и поэтому Microsoft не может изменить его безвлияет на существующий код.Если получение точного результата для конкретных тригонометрических идентификаторов имеет для вас значение, вы можете обернуть встроенные функции с плавающей запятой в некоторый код, который проверяет известные входные данные.

1 голос
/ 11 декабря 2015

Поскольку результат вычисления действительно близок к 0 (нулю), вы можете просто использовать округление:

Math.Round(result, 4): // 4 decimals, e.g.: 2.1234

Итак, вычисление sin / cos из радиана :

const double Deg = Math.PI / 180;
double sin = Math.Round(Math.Sin(yourRadianValue * Deg), 4);
double cos = Math.Round(Math.Cos(yourRadianValue * Deg), 4); // 0.0000...06 becomes 0

Что если yourRadianValue = 90, возвращает sin = 1 и cos = 0.

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

Как заметил @ b1tw153, было бы замечательно, если бы были возвращены точные значения для кратных PI / 2.И это именно то, что Microsoft сделала в своей библиотеке System.Numerics;если вы изучите исходный код для Matrix3x2.CreateRotation, вы заметите, что они обрабатывают n * PI / 2 случаев вручную: https://github.com/Microsoft/referencesource/blob/master/System.Numerics/System/Numerics/Matrix3x2.cs#L325

...