Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблемы с Math.Cos, Некорректно находится косинус угла 
:(
    Опции темы
PingWiN0x20
Дата 17.11.2009, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 9.2.2008

Репутация: нет
Всего: нет



Начал изучать C#, забрался в математику и почти сразу нашел такую вот неурядицу....

Код

System.Console.WriteLine("Синус 0 = " + Math.Sin(0 * Math.PI / 180));
System.Console.WriteLine("Синус 90 = " + Math.Sin(90 * Math.PI / 180));
System.Console.WriteLine("Косинус 0 = " + Math.Cos(0 * Math.PI / 180));
System.Console.WriteLine("Косинус 90 = " + Math.Cos(90 * Math.PI / 180));


Выводится:
Код

Синус 0 = 0
Синус 90 = 1
Косинус 0 = 1
Косинус 90 = 6,123031...E-17


Вопрос: что с косинусом 90 градусов??? 
Почему программа выводит не ноль, а число, хоть и очень-очень маленькое, но бОльшее нуля?

Это сообщение отредактировал(а) PingWiN0x20 - 17.11.2009, 15:09
PM MAIL   Вверх
KuMa1104
Дата 17.11.2009, 15:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 541
Регистрация: 16.4.2009
Где: Ростов-на-Дону

Репутация: нет
Всего: 3



Цитата(PingWiN0x20 @  17.11.2009,  15:07 Найти цитируемый пост)
Косинус 90 = 6,123031...E-17
 это проктически ноль.

ИМХО.
Компьютер в отличае от человека считает с приблизительной точьностью, он получил значение которое соответствует этой точности.



--------------------
Галактика – суровая штука. Чтобы в ней выжить, надо знать, где твое полотенце.

Время - штука относительная... а время обеда - ещё более относительная
PM MAIL   Вверх
PingWiN0x20
Дата 17.11.2009, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 9.2.2008

Репутация: нет
Всего: нет



ноль <> приблизительно ноль.

Код

if (Math.Cos(90 * Math.PI / 180) == 0)
       Console.WriteLine("Косинус 90 = 0");


Такой код не выводит ничего. А должен бы.

P.S.: почему тогда синус 90 посчитался нормально... без приблизительной точности?
PM MAIL   Вверх
KuMa1104
Дата 17.11.2009, 15:52 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 541
Регистрация: 16.4.2009
Где: Ростов-на-Дону

Репутация: нет
Всего: 3



Опять таки ИМХО
Думаю попало удачно, в итоге остаток был так мал что отбросился, а у cos он был таков что был мал и соответствовал условию точности, но не достаточно мал чтоб быть отброшенным.


--------------------
Галактика – суровая штука. Чтобы в ней выжить, надо знать, где твое полотенце.

Время - штука относительная... а время обеда - ещё более относительная
PM MAIL   Вверх
diadiavova
Дата 17.11.2009, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



PingWiN0x20, просто округляй результат на величину, которая "проглотит" погрешность(одного разряда будет достаточно).


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
PingWiN0x20
Дата 17.11.2009, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 9.2.2008

Репутация: нет
Всего: нет



Только что проверил в Delphi ... такая же ерунда!

И вот еще что настораживает...
Код

Number = 1 / (Math.Cos(90 * Math.PI / 180))


Если мне память не изменяет, на ноль делить нельзя (косинус 90 вся-таки нулю равен). Но приведенного выше выражения это не касается. В переменной Number будет вполне себе обыкновенное число.
Придется писать свою функцию Cos, которая, встретив значение угла 90.00 вернет ноль, а не 6,123031...E-17.

Спасибо всем за ответы  smile 

Это сообщение отредактировал(а) PingWiN0x20 - 17.11.2009, 17:01
PM MAIL   Вверх
KuMa1104
Дата 17.11.2009, 17:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 541
Регистрация: 16.4.2009
Где: Ростов-на-Дону

Репутация: нет
Всего: 3



Цитата(diadiavova @  17.11.2009,  16:27 Найти цитируемый пост)
PingWiN0x20, просто округляй результат на величину, которая "проглотит" погрешность(одного разряда будет достаточно).


diadiavova забавная дилемма получаеться ввести новую погрешность чтоб устранить старую smile

Добавлено @ 17:08
PingWiN0x20 Здесь то что предложил diadiavova по моему хорошо подойдёт. 
Но можно провести забавную на мой взгляд аналогию....

Код

Ударить преступностью по преступности


Добавлено через 8 минут и 55 секунд
Цитата(PingWiN0x20 @  17.11.2009,  16:56 Найти цитируемый пост)
Придется писать свою функцию Cos, которая, встретив значение угла 90.00 вернет ноль, а не 6,123031...E-17.


Вот что что а это думаю не стоит, лучше чем у тех ребят что их писали врятли получиться.



Это сообщение отредактировал(а) KuMa1104 - 17.11.2009, 17:08


--------------------
Галактика – суровая штука. Чтобы в ней выжить, надо знать, где твое полотенце.

Время - штука относительная... а время обеда - ещё более относительная
PM MAIL   Вверх
PingWiN0x20
Дата 17.11.2009, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 9.2.2008

Репутация: нет
Всего: нет



Оказывается на ноль делить нельзя только челочисленные типы, с плавающей точкой - можно, результатом будет "бесконечность". С ней можно работать дальше.
Тупизм! 

Код

            double c = 0, d = 0;
            c = 10 / d; //выполняется без проблем

            double x = Double.PositiveInfinity;
            Console.WriteLine(10 / x); //выдаст ноль :) 

            int x = 0, y = 0;
            x = 10 / y; //ошибочка - на ноль делить нельзя



Цитата
Вот что что а это думаю не стоит, лучше чем у тех ребят что их писали врятли получиться.


Да нет, я не собираюсь переписывать саму функцию Math.Cos() smile
Просто сделаю как-то так:

Код

        public static double PI_180 = Math.PI / 180;
        public static double Cos(double Exp)
        {
            if (Exp == 90.00)
                return 0.00;
            else
                return Math.Cos(Exp * PI_180);
        }


Это сообщение отредактировал(а) PingWiN0x20 - 17.11.2009, 17:28
PM MAIL   Вверх
diadiavova
Дата 17.11.2009, 17:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(KuMa1104 @  17.11.2009,  17:04 Найти цитируемый пост)
diadiavova забавная дилемма получаеться ввести новую погрешность чтоб устранить старую
Не ввести новую погрешность, а установить предельно-допустимую погрешность на таком уровне, в пределах которого возвращаемый машиной результат будет корректным. 
Когда ты пишешь
Цитата(KuMa1104 @  17.11.2009,  15:25 Найти цитируемый пост)
это проктически ноль.

Ты практически говоришь о том же. Мой ответ от твоего отличается только тем, что он содержит практический совет.

И кстати, в конечном виде значения иррациональных функций можно представить только для некоторых частных аргументов, а всё остальное всё-равно содержит погрешность. Мой совет сводится всего лишь к тому, чтобы учесть это обстоятельство.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
Дрон
Дата 17.11.2009, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Весёлая тема. 

Цитата(PingWiN0x20 @  17.11.2009,  16:56 Найти цитируемый пост)
Придется писать свою функцию Cos, которая, встретив значение угла 90.00 вернет ноль, а не 6,123031...E-17.

Вот это вообще убило  smile 

Попробуй вот такое посчитать:
Код

           Console.WriteLine(0.1 * 3 - 0.3);

Ноль не получится smile
И что, на этот случай тоже собственную функцию умножения писать будешь? А таких случаев бесконечно много, все не перечислишь.

Смысл в том, что во-первых в форме числа с плавающей запятой (Float/Double) нельзя представить любое число -- количество представимых чисел конечно. 
Во-вторых могут быть проблемы с представлением десятичных чисел в двоичном виде. Это примерно как с обыкновенными дробями, сравни:
1/3 * 3 = 10
1/3 = 0.333333333(3)
0.333333333(3) * 3 = 0.999999999(9)
Парадокс, да? smile

PS: О сколько нам открытий чудных готовит просвященья дух (почти по Пушкину).

Добавлено @ 17:46
Да, забыл. Вывод из всего это простой. Результаты вычислений с плавающей запятой нельзя сравнивать как a == b -- ничего не получится (как я уже писал 0.1 * 3 не равно 0.3). Надо вычитать одно из другого и сравнивать абсолютную разницу с заранее выбранным маленьким числом, которое ты принимаешь как допустимую погрешность, т.е. например так: Math.Abs(a - b) < 0.000000001

Это сообщение отредактировал(а) Дрон - 17.11.2009, 17:48


--------------------
Да. Именно так.
PM   Вверх
Ram1reS
Дата 17.11.2009, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 141
Регистрация: 25.4.2008
Где: Москва

Репутация: 3
Всего: 5



Console.WriteLine(0.1d * 3 - 0.3); // 0
--------------------
 
PM MAIL ICQ   Вверх
diadiavova
Дата 17.11.2009, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доктор Зло(диагност, настоящий, с лицензией и полномочиями)
****


Профиль
Группа: Модератор
Сообщений: 5821
Регистрация: 14.8.2008
Где: В Коньфпольте

Репутация: 31
Всего: 142



Цитата(Дрон @  17.11.2009,  17:40 Найти цитируемый пост)
Надо вычитать одно из другого и сравнивать абсолютную разницу с неким маленьким числом, которое ты принимаешь как допустимую погрешность, т.е. например так: Math.Abs(a - b) < 0.000000001

 smile Это, пожалуй лучше всего. Эта маленькая величина - предельно-допустимая погрешность на данном этапе вычислений.


--------------------
Хочешь получить мудрый совет - читай подписи участников форумов.
Злой доктор Щасзаболит smile
PM   Вверх
PingWiN0x20
Дата 17.11.2009, 17:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 9.2.2008

Репутация: нет
Всего: нет



Цитата(Ram1reS @ 17.11.2009,  17:48)
Console.WriteLine(0.1d * 3 - 0.3); // 0

неа, не ноль .... 5,5511151...Е-17



Дрон, спасибо! Теперь до меня дошло что о чем   smile 

Это сообщение отредактировал(а) PingWiN0x20 - 17.11.2009, 18:01
PM MAIL   Вверх
Дрон
Дата 17.11.2009, 18:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 24
Всего: 92



Цитата(Ram1reS @  17.11.2009,  17:48 Найти цитируемый пост)
Console.WriteLine(0.1d * 3 - 0.3); // 0 

d? Ничего не меняет -- это же double, литералы и так double по-умолчанию.
Может всё-таки m? Тогда будет decimal, в нём всё гораздо лучше, таких погрешностей нет, но вот синусы и косинусы в нём не считаются.


--------------------
Да. Именно так.
PM   Вверх
KuMa1104
Дата 17.11.2009, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 541
Регистрация: 16.4.2009
Где: Ростов-на-Дону

Репутация: нет
Всего: 3



Цитата(Дрон @  17.11.2009,  18:07 Найти цитируемый пост)
Console.WriteLine(0.1* 3 - 0.3);


Я так смотрю что у одних ноль а у других нет.
Хотя к теме не относиться но хотелбы поинтересоваться почему так?

Я так понемаю что компьютер просто отбрасывает все лишние знаки, а не округляет получаеться что у одних процессор считает с большей точностью чем у других???

Или причина не в этом?


--------------------
Галактика – суровая штука. Чтобы в ней выжить, надо знать, где твое полотенце.

Время - штука относительная... а время обеда - ещё более относительная
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1086 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.