Математична константа значення PI в С


78

Обчислення значення PI є однією зі складної проблеми, і wikipedia розповідає про наближення, зроблені для цього, і каже, що важко точно розрахувати PI.

Як C обчислює PI? Чи обчислює це кожен раз, чи використовує менш точну фіксовану величину?


25
Використання пі, обчислене лише до 39 знаків після коми, дозволить обчислити окружність усього Всесвіту з точністю менше діаметра атома Гідрогену . 16 десяткових знаків (приблизно того, що ви отримуєте за допомогою а double) має бути достатньо для обчислення діаметра Сонячної системи з похибкою менше ширини волосся.
pmg

Я знайшов це в Інтернеті і вважаю його досить цікавим: crypto.stanford.edu/pbc/notes/pi/code.html
Френсіс Куглер

Відповіді:


91

У C Pi визначається в math.h: #define M_PI 3.14159265358979323846


2
І це значення є найбільш точним поданням, доступним для значення подвійної точності.
Капітан Жираф

36
Не зовсім - насправді відповідну реалізацію С може не визначити PIв <math.h>. POSIX визначає M_PI, але знову ж таки, відповідна реалізація C може не визначити його. (POSIX накладає деякі вимоги, що суперечать стандарту C.) Але ви можете визначити це таким чином у власній програмі.
Кіт Томпсон,

2
отже, це фіксоване значення, і неможливо підвищити точність?
user1298016

6
Додаткова інформація: якщо ви використовуєте M_PI і отримуєте помилку, що вона невизначена - це можна вирішити #define _USE_MATH_DEFINES
spin_eight

2
@Danijel M розшифровується як "математика". Ще в ті часи всі "математичні константи" мали префікс M_. Були також такі речі , як M_E, і M_LN10т.д. Вони ніколи не зробили це до стандарту.
Лундін,

29

Найближче, що C робить до "обчислення π" способом, який безпосередньо видно програмам, є acos(-1)подібним. Це майже завжди робиться з поліноміальними / раціональними наближеннями для функції, що обчислюється (або в C, або за допомогою мікрокоду FPU).

Тим НЕ менше, цікаве питання полягає в тому , що обчислення тригонометричних функцій ( sin, cosі tan) вимагає скорочення їх аргументу по модулю 2л. Оскільки 2π не є діадичним раціональним (і навіть не раціональним), його неможливо представити в будь-якому типі з плаваючою комою, і, отже, використання будь-якого наближення значення призведе до катастрофічного накопичення помилок для великих аргументів (наприклад, якщо xє 1e12, і 2*M_PIвідрізняється від 2π на ε, тоді fmod(x,2*M_PI)відрізняється від правильного значення 2π до 1e12 * ε / π, помноженого на правильне значення xмода 2π. Тобто це абсолютно безглуздо.

Правильна реалізація стандартної математичної бібліотеки C просто має гігантське дуже високоточне подання π, закодованого у своєму джерелі, для вирішення проблеми коректного скорочення аргументів (і використовує деякі химерні прийоми, щоб зробити це не зовсім таким гігантським ). Це , як більшість / всі версії C про sin/ cos/ tanфункціях роботи. Однак відомо, що деякі реалізації (наприклад, glibc) використовують реалізації збірки на деяких процесорах (наприклад, x86) і не виконують коректного скорочення аргументів, що призводить до абсолютно безглуздих результатів. (До речі, неправильний asm зазвичай працює приблизно з такою ж швидкістю, як і правильний код C для невеликих аргументів.)


2
Я шукав ISO C, Додаток F, посилання на триггерні функції, але, мабуть, немає жорсткої вимоги, щоб вони були функціями тригера IEEE (що вимагало б, щоб вони були правильними та правильно округленими для всіх входів). Тож це може бути більше питання якості (якості впровадження), ніж питання правильності. Але реалізації, засновані на fdlibm, мають зменшення аргументів, яке працює в цілому домені репрезентабельних значень.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

1
Добре, я розумію, що ви говорите, і дякую за вказівник на fdlibm. Моя думка полягала в тому, що обчислювати синус такого великого xмайже безглуздо і, швидше за все, помилка в коді, що використовує функцію синуса. Якщо xвоно настільки велике, що стає цілим числом, тоді ви можете представити лише близько 6 значень xза період синуса. Звичайно, можна знайти такий, yякий відповідає умові, і це приємно, але я сумніваюся, що існує якийсь корисний додаток для обчислення синусів цілих чисел.
Фріц

1
Більш цікавим, ніж крайній випадок цілого числа, xбув би аналіз того, як швидко зростає ця "помилка епсилону" x. Якщо є суттєва помилка 1000*M_PI, тоді я розумію проблему і від усього серця погоджуюсь з вами.
Фріц,

2
@Fritz: Згідно з грубим аналізом у моїй відповіді, помилка fmod(x,2*M_PI)проти правильного значення, зменшеного аргументом, зростає лінійно за величиною x. Отже, припускаючи, що 1ulp знаходиться xбезпосередньо поза одиничним колом, ви розглядаєте щось на зразок 1000ulp 1000*M_PI. Поблизу нулів sinблизький до лінійного з нахилом 1, тому # ulp в аргументі переводиться безпосередньо до ulp в результаті.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

1
І до речі є цікаві програми sin(2^n)для великих значень n; Однак я не пам’ятаю, що вони зараз.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

22

Просто визначте:

Він повинен дати вам точний номер PI, з яким працюють математичні функції. Отже, якщо вони змінюють значення PI, з яким працюють, по тангенсу, косинусу чи синусу, тоді ваша програма повинна бути завжди оновленою;)


10
Це дозволило б оцінити досить дорогу операцію (acos) кожного разу, коли використовується константа. Навряд чи ефективний та раціональний підхід.
Jaromír Adamec

3
@ JaromírAdamec Насправді, будь-який хороший компілятор повинен оптимізувати цей вираз у константу, будучи чистою функцією зі стандартної бібліотеки, що викликається з постійними аргументами; якщо ви не компілюєте з вимкненими оптимізаціями, тобто.
UnrealEagle

2
@ JaromírAdamec, навпаки, стандарт * C явно дозволяє - або навіть схвалює - компілятор, знаючи складні деталі всіх стандартних функцій бібліотеки!
Антті Хаапала,

1
@ JaromírAdamec Я нічого не кажу про якість окремої реалізації. Я просто зазначаю, що компілятору C, який відповідає специфікації C, як описано в ISO 9899, явно дозволено замінити / вбудувати / замінити всі посилання на стандартну бібліотеку, як описано в тому ж стандарті, припускаючи, що функція з тим самим іменем буде мають поведінку, рівну визначеній у стандарті. Комутатори, що існують у різних компіляторах, існують лише для того, щоб забезпечити правильну компіляцію програм, що не відповідають строго, у цих сучасних реалізаціях.
Антті Хаапала,

1
acosФункція є частиною мови C правильного.
Каз

8

у будь-якому випадку у вас не необмежена точність, тому C визначає константу таким чином:

import math.h, щоб використовувати це


Це означає, що мені вдається отримати більш високу точність для PI, ніж визначена C? Якщо я використовую подвійний x = 1345 * PI; Але це обмежується точністю подвійної змінної, яка використовується в програмі, не ??? Це означає, що нещодавно визначене точне значення марне ??
user1298016

частково так: D ... "подвійний х = 1345 * ПІ", завдяки цій роботі ви втрачаєте певну точність, оскільки ПІ точний, наскільки може. якщо ви хочете отримати більшу точність, вам слід реалізувати ВЛАСНУ структуру та зберегти результат у масиві (як BigInteger у java). ГАРАЗД?
Maziar Aboualizadehbehbahani

1
Насправді M_PIнемає в C. Це частина опції розширення XSI в POSIX.
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

@R .., ти впевнений, що це лише XSI? У документах не мають нормального [XSI] маркера вони мають на XSI-тільки матеріал (дивіться , наприклад , хто ).
Метью Флашен

2
Ах, ви дивилися на SUSv2, який не є POSIX . Це було до злиття специфікацій UNIX / POSIX, на той час вся SUS була XSI. Починаючи з SUSv3, стандарти Unix та POSIX об'єдналися, при цьому опція XSI була частинами Unix, які не вважалися достатньо корисними чи універсальними для забезпечення всіх систем POSIX. Пізніше в SUSv4 (POSIX 2008) низка більш корисних опцій XSI була перенесена до базового стандарту (POSIX), а менш корисні поступово позначаються застарілими, тому з часом, за певної удачі, опція XSI перестане існувати ...
R .. GitHub СТОП ДОПОМОГАЙ ЛЕД

0

Залежно від бібліотеки, якою ви використовуєте стандартні попередньо визначені математичні константи GNU C, тут ... https://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html

Вони у вас уже є, то навіщо їх перевизначати? Можливо, у ваших системних настільних калькуляторах вони є ще більш точними, щоб ви могли, але просто переконайтеся, що не суперечите існуючим визначеним, щоб заощадити на попередженнях компіляції, оскільки вони, як правило, отримують за замовчуванням подібні речі. Насолоджуйтесь!


-2

Я не знаю точно , як Cрозраховує PIбезпосередньо , як я більше знайомий з C++чим C; однак ви можете мати заздалегідь визначений C macroабо constтакий, як:

або ви можете обчислити його за допомогою будь-якої з цих двох формул:

Я не впевнений на 100%, але думаю, що atan()це дешевше acos().


@RyanHaining Це була чиста друкарська помилка з мого боку, дякую вам, що вказали на це. Я зробив відповідні виправлення.
Френсіс Куглер,

1
Це все ще не дійсне C
Райан Хейнінг

@RyanHaining Хм, добре; Я знаю, що ви можете це зробити на С ++. Я не був впевнений, чи дозволив це С. Минуло занадто багато років з того часу, як я працював у C. Чи існує еквівалент без використання; #define CONSTANT numberHere?
Френсіс Куглер

"Всі вирази в ініціалізаторі для об'єкта, який має статичну тривалість або тривалість зберігання потоків, повинні бути постійними виразами або рядковими літералами" ( C2011, 6.7.9 / 4 ). Мені незрозуміло, які характеристики ви сподіваєтесь мати в альтернативі, яка не покладається на макрос, але це одне з головних речей, проти яких ви стикаєтесь.
Джон Боллінгер,

@JohnBollinger Має сенс; моя Cдуже іржава, оскільки минуло близько 20 років, відколи я працюю в ній, і той факт, що я в основному використовую C++. Я спочатку відповідав на це запитання з урахуванням C++перспективи ... Я оновив відповідь, щоб відповісти на це ...
Френсіс Куглер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.