Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
3 / 3 / 0
Регистрация: 12.07.2022
Сообщений: 213

Слишком не точно вычисляются библиотечные косинус и тангенс для переменных типа float

15.04.2025, 01:59. Показов 5116. Ответов 21
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Если юзать использовать 4-байтовый float, для значений, близких к π/2 (90 град.) - ошибка уже в 4-м или даже 3-м знаке. У float гарантированная точность 6-7 значащих цифр, что никак не вяжется с ошибкой в 3 знаке.

Пример: cos(1.57) даёт: 0.000796274, правильное: 0.000796327.

Я знаю сколько подводных камней в вычислениях с плавающей точкой, все эти приколюхи с представлением, машинным эпсилоном и т. д., знаю что ошибка может накапливаться когда идёт несколько связанных вычислений. Но для простейших функций не ожидал такой погрешности. Тригонометрия вроде уже давно на уровне железа поддерживается. Почему тогда такая ошибка?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
15.04.2025, 01:59
Ответы с готовыми решениями:

Решение ребуса "Синус + Синус + Косинус = Тангенс"
Написать на С++ программу, решающую ребус: СИНУС + СИНУС + КОСИНУС = ТАНГЕНС Пример: ВАГОН...

Синус, косинус,тангенс
Извините, мне нужно код на С++ есть ещё фото внизу

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

21
3757 / 2636 / 580
Регистрация: 11.09.2009
Сообщений: 9,404
15.04.2025, 02:34
Цитата Сообщение от Geek Geekson Посмотреть сообщение
для простейших функций не ожидал такой погрешности. ... Почему тогда такая ошибка?
Потому что косинус - не простейшая функция, а вычисление ряда. Ошибка накапливается.
Если не хотите использовать Double или Long Double, попробуйте поискать библиотеку математических функций, в которой реализованы алгоритмы расчётов с повышенной точностью.
0
Заблокирован
15.04.2025, 02:35
Вот така [цензура] малята.
0
Странный типчик
 Аватар для Anonim4ik
44 / 8 / 2
Регистрация: 29.01.2020
Сообщений: 51
15.04.2025, 03:04
Погрешность ~0.00658%, вроде не очень много, но самому тоже интересно стало
0
49 / 39 / 11
Регистрация: 24.07.2022
Сообщений: 115
15.04.2025, 04:05
А каким компилятором вы пользуетесь? у меня что-то не получается такой результат получить
Миниатюры
Слишком не точно вычисляются библиотечные косинус и тангенс для переменных типа float  
0
Нарушитель
10225 / 5655 / 1257
Регистрация: 12.03.2015
Сообщений: 26,176
15.04.2025, 08:15
Цитата Сообщение от Geek Geekson Посмотреть сообщение
У float гарантированная точность 6-7 значащих цифр, что никак не вяжется с ошибкой в 3 знаке.
Пример: cos(1.57) даёт: 0.000796274, правильное: 0.000796327.
Я чот не понял, а чо тебе не нравится? 7 цифорр и есть, я проверил на куркулятере.



Если float не нравится, юзай double. Или тебя заставляют под дулами автоматов?
0
Модератор
Эксперт С++
 Аватар для zss
13765 / 10960 / 6489
Регистрация: 18.12.2011
Сообщений: 29,233
15.04.2025, 08:21
Цитата Сообщение от dmiteri Посмотреть сообщение
у меня что-то не получается такой результат получить
У Вас 1.57 константа типа double.
А ТС имел ввиду:
C++
1
cout << cos(1.57f);
или
C++
1
cout << cosf(1.57);
кстати
cos(M_PI_2) дает 6.12323e-017
а cosf(M_PI_2) дает -4.37114e-008
0
Заблокирован
15.04.2025, 08:35
Цитата Сообщение от Geek Geekson Посмотреть сообщение
У float гарантированная точность 6-7 значащих цифр, что никак не вяжется с ошибкой в 3 знаке.
Пример: cos(1.57) даёт: 0.000796274, правильное: 0.000796327.
Ошибка в седьмом знаке после точки. Третий знак это ноль.
0
631 / 526 / 104
Регистрация: 05.08.2022
Сообщений: 2,810
15.04.2025, 09:22
Цитата Сообщение от Geek Geekson Посмотреть сообщение
Но для простейших функций не ожидал такой погрешности
Я думаю дело вот в чем.
Ошибка в 7-м знаке после запятой. Не в "значащем 7-м", а именно в 7-м после запятой.
Видимо разработчики (не важно программной или аппаратной реализации) решили, что раз 7 знаков умещается во float - то и точноста расчетов надо взять "до 7 знака после запятой". В общем-то логично. (ну или даже до 6-го знака, т.к. гарантированно 6 знаков).
Задать "относительную" точность - не совсем понятно как в вычислениях ряда. Поэтому точность просто фиксированная.
0
Заблокирован
15.04.2025, 11:54
Цитата Сообщение от zss Посмотреть сообщение
кстати
cos(M_PI_2) дает 6.12323e-017
а cosf(M_PI_2) дает -4.37114e-008
Это считай два нуля.
0
2615 / 1627 / 265
Регистрация: 19.02.2010
Сообщений: 4,316
15.04.2025, 12:16
Лучший ответ Сообщение было отмечено Geek Geekson как решение

Решение

Цитата Сообщение от Geek Geekson Посмотреть сообщение
Тригонометрия вроде уже давно на уровне железа поддерживается. Почему тогда такая ошибка?
Потому, что нужно читать доку по железу - доки по языку программирования недостаточно.
Берём интеловский талмуд Intel® 64 and IA-32 Architectures Software Developer’s Manual - Volume 2 - Instruction Set Reference.
Там для процессорной команды fcos чёрным по белому написано:
for accurate results it is safe to apply FCOS only to arguments reduced accurately in software, to a value smaller in absolute value than 3π/8.
3π/8=1.1781 - а ты суёшь 1.57.
Для синуса -
for accurate results it is safe to apply FSIN only to arguments reduced accurately in software, to a value smaller in absolute value than 3π/4.
Для тангенса -
for accurate results it is safe to apply FPTAN only to arguments reduced accurately in software, to a value smaller in absolute value than 3π/8.
Т.е. НИГДЕ нет гарантий точного вычисления на всей области значений double-аргумента трансцендентной команды. Проц сам делает/сделает редукцию "лишних" периодов у вычисляемой функции - но недостаточно. Надо процу помогать головой и руками - и в доке это напрямую сказано.
И всё равно трансцендентные процессорные команды будут вычислять приближённый результат. Слово accurate везде в цитатах выше - это не слово exact.
2
3 / 3 / 0
Регистрация: 12.07.2022
Сообщений: 213
15.04.2025, 17:23  [ТС]
VTsaregorodtsev, спасибо. Открыл его и поискал там описание для double-варианта - и не нашёл вообще. Получается, в железе поддерживаются только 4-байтовые? И все операции с double считаются программно (через ряды например)? И тогда вопрос открыт насчёт точности для double. Но с карманным калькулятором, по крайней мере, там совпадает в 10 значащих цифрах.

Вообще у меня проц AMD, но они, как понял, тоже этому стандарту следуют?

Добавлено через 14 минут
Цитата Сообщение от Bans Посмотреть сообщение
Ошибка в седьмом знаке после точки. Третий знак это ноль.
Тут имел в виду что ошибка в 3-4 значащей цифре, конечно. А не 3-м знаке после запятой. Нули слева значащими цифрами не являются.
0
Нарушитель
10225 / 5655 / 1257
Регистрация: 12.03.2015
Сообщений: 26,176
15.04.2025, 18:02
Цитата Сообщение от Geek Geekson Посмотреть сообщение
А не 3-м знаке после запятой. Нули слева значащими цифрами не являются.
Ты какие здесь нули имеешь в виду? Слева или справа от запятой?

0
2615 / 1627 / 265
Регистрация: 19.02.2010
Сообщений: 4,316
15.04.2025, 18:04
Цитата Сообщение от Geek Geekson Посмотреть сообщение
Открыл его и поискал там описание для double-варианта - и не нашёл вообще. Получается, в железе поддерживаются только 4-байтовые?
Продолжай курить мануалы по железу х86/х87, как для х32 - так и для х64.

Команды вычисления тригонометрии в х87 берут аргументом значение регистра st(0) на вершине fpu-стека. А этот и все остальные регистры там - 80битные (лонг дабл).
Т.е. у сишной функции cos() аргумент типа дабл всё равно будет загружен в fpu-регистр с расширением на бОльшую точность. У cosf() аргумент типа флоат - аналогично.
Возвращаемые значения - тоже все в лонг дабл, а флоатом/даблом они становятся только в момент выгрузки из регистра в ячейку памяти. Т.е. если запишешь что-то навроде z=cosf(x)*sinf(y) - то умножение произойдёт над лонг дабл-результатами функций, и к типу переменной z будет приведено только в момент записи значения в память.

Вышесказанное - если компилируем под х32, ибо под х64 соглашение о вызовах (calling convention) требует передачи плавучих аргументов функций не в fpu-регистрах, а в xmm-регистрах (для SSE/AVX-наборов команд), и возврата значений тоже через xmm-регистр. Поэтому вычисления тригонометрии в х64 могут реализовываться не через старую аппаратную х87-команду типа fsin/fcos/... (это требует пересылки полученного в xmm-регистре аргумента в память, загрузки его в fpu-регистр, и обратной пересылки результата тоже через память) - а библиотечным кодом непосредственно над значением в xmm-регистре.
И у плавучих типов данных в xmm-регистрах бывают только флоат и дабл - лонг дабла там нет.
Исходя из предыдущего предложения - один и тот же сишный/плюсовый код может при его компиляциях для х32+х87 и для х64+xmm давать затем разные результаты вычислений, ибо во втором случае нет возможности пользования более точным (лонг дабл) представлением данных на всех аппаратных/промежуточных вычислениях плавучей математики.

Цитата Сообщение от Geek Geekson Посмотреть сообщение
Вообще у меня проц AMD, но они, как понял, тоже этому стандарту следуют?
Доки от/для АМД тоже в открытом доступе - бери и сравнивай
Просто в коллекции талмудов от АМД справочник по набору команд идёт не вторым томом (как у Интела) - а третьим, четвёртым и пятым.
Но сразу скажу, что там не так подробно, как у Интела.
2
3 / 3 / 0
Регистрация: 12.07.2022
Сообщений: 213
15.04.2025, 18:40  [ТС]
Цитата Сообщение от Verevkin Посмотреть сообщение
Ты какие здесь нули имеешь в виду? Слева или справа от запятой?
Все нули слева. Посмотри что такое значащие цифры.
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38157 / 21093 / 4305
Регистрация: 12.02.2012
Сообщений: 34,675
Записей в блоге: 14
15.04.2025, 19:20
Цитата Сообщение от Geek Geekson Посмотреть сообщение
Пример: cos(1.57) даёт: 0.000796274, правильное: 0.000796327
Вот более правильное значение: cos(1.57)= 0.00079632671073332548540853364535418588 0175394345 (это к слову). Так что оба твоих значения неправильные. Кстати, откуда ты взял свое "правильное" значение?

И дело не регистрах процессора. Дело в алгоритме вычисления, в котором используются полиномы Чебышёва. Эта схема дает определенную погрешность. И что?
0
3 / 3 / 0
Регистрация: 12.07.2022
Сообщений: 213
15.04.2025, 21:16  [ТС]
Цитата Сообщение от Catstail Посмотреть сообщение
Так что оба твоих значения неправильные
Это почему? 0.000796327 - правильное в пределах 6 значащих цифр, обеспечиваемых точностью float. Последняя "7" - результат округления "67".

Цитата Сообщение от Catstail Посмотреть сообщение
Кстати, откуда ты взял свое "правильное" значение?
Взял результат для double + проверил на калькуляторе. Для 6 значащих цифр этого по идее достаточно.
0
5514 / 2867 / 571
Регистрация: 07.11.2019
Сообщений: 4,750
16.04.2025, 06:08
Geek Geekson, возможно вычисление sin(x-π/2) (или, даже, x-π/2) вместо cos(x) для значений x близких к π/2 будет точнее...
0
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38157 / 21093 / 4305
Регистрация: 12.02.2012
Сообщений: 34,675
Записей в блоге: 14
16.04.2025, 08:33
Цитата Сообщение от Geek Geekson Посмотреть сообщение
проверил на калькуляторе.
-
0
3 / 3 / 0
Регистрация: 12.07.2022
Сообщений: 213
16.04.2025, 13:20  [ТС]
Catstail, за неимением вагона времени. По крайней мере значение с разных калькуляторов и с типа double совпадает в пределах отображаемых цифр, это уже о чём-то говорит. И да, критикуя - предлагай.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
16.04.2025, 13:20
Помогаю со студенческими работами здесь

опять ошибка.на этот раз cannot convert `float (*)(float)' to `float' in argument passing
#include&lt;stdio.h&gt; #include&lt;stdlib.h&gt; #include&lt;math.h&gt; float f1(float x)/*vira*enie 1*/ ...

Чем отличаются float преобразования (float)var от float(var)
Здравствуйте! Подскажите, чем отличается (float)var от float(var)

Ошибка преобразования: значение типа "float *" нельзя присвоить сущности типа "float"
Помогите исправить.Значение типа &quot;float *&quot; нельзя присвоить сущности типа float void Mode2() {...

"Значение типа float* нельзя использовать для инициализации сущности типа float"
#include &lt;math.h&gt; #include&lt;iostream&gt; #include &lt;iomanip&gt; #include&lt;conio.h&gt; using namespace std;...

Преобразование строкового типа в переменную типа float
Как в программе С++ Builder6 преобразовать строковый тип числа взятого из компонента...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru