그래서 고등학교 수학, 그리고 아마도 대학에서 삼각 함수를 사용하는 방법, 그들이하는 일, 그들이 해결하는 문제의 종류를 배웁니다. 그러나 그들은 항상 나에게 블랙 박스로 제시되었습니다. 사인 또는 코사인이 필요한 경우 계산기의 sin 또는 cos 버튼을 누르면 설정이 완료됩니다. 괜찮습니다.
내가 궁금한 것은 삼각 함수가 일반적으로 어떻게 구현되는지입니다.
그래서 고등학교 수학, 그리고 아마도 대학에서 삼각 함수를 사용하는 방법, 그들이하는 일, 그들이 해결하는 문제의 종류를 배웁니다. 그러나 그들은 항상 나에게 블랙 박스로 제시되었습니다. 사인 또는 코사인이 필요한 경우 계산기의 sin 또는 cos 버튼을 누르면 설정이 완료됩니다. 괜찮습니다.
내가 궁금한 것은 삼각 함수가 일반적으로 어떻게 구현되는지입니다.
답변:
먼저, 일종의 범위 축소를 수행해야합니다. 삼각 함수는 주기적이므로 인수를 표준 간격으로 줄여야합니다. 우선 각도를 0도에서 360도 사이로 줄일 수 있습니다. 그러나 몇 가지 신원을 사용하면 더 적은 것으로 얻을 수 있다는 것을 알게됩니다. 0도에서 45도 사이의 각도에 대해 사인과 코사인을 계산하는 경우 모든 각도에 대한 모든 삼각 함수를 계산하는 방법을 부트 스트랩 할 수 있습니다.
인수를 줄이면 대부분의 칩은 CORDIC 알고리즘을 사용하여 사인과 코사인을 계산합니다. 사람들이 컴퓨터가 Taylor 시리즈를 사용한다고 말하는 것을들을 수 있습니다. 합리적으로 들리지만 사실이 아닙니다. CORDIC 알고리즘은 효율적인 하드웨어 구현에 훨씬 더 적합합니다 . ( 소프트웨어 라이브러리는 삼각 함수를 지원하지 않는 하드웨어에서 Taylor 시리즈를 사용할 수 있습니다.) CORDIC 알고리즘을 사용하여 상당히 좋은 답변을 얻었지만 정확도를 높이기 위해 다른 작업을 수행하는 몇 가지 추가 처리가있을 수 있습니다.
위의 몇 가지 개선 사항이 있습니다. 예를 들어, 아주 작은 각도 theta (라디안 단위)의 경우 sin (theta) = theta를 모든 정밀도에 적용하므로 다른 알고리즘을 사용하는 것보다 단순히 theta를 반환하는 것이 더 효율적입니다. 따라서 실제로는 가능한 모든 성능과 정확성을 끌어 내기위한 많은 특수한 경우 논리가 있습니다. 시장 규모가 작은 칩은 최적화 작업이 많지 않을 수 있습니다.
편집 : Jack Ganssle은 임베디드 시스템에 대한 저서 "The Firmware Handbook" 에서 적절한 토론을했습니다 .
참고 : 정확도와 성능 제약이있는 경우 Taylor 시리즈를 사용하여 수치 목적으로 함수를 근사 하면 안됩니다 . (미적분 과정을 위해 저장하십시오.) 그들은 단일 지점에서 함수 의 분석 을 사용 합니다 . 예를 들어 모든 파생물이 해당 지점에 존재한다는 사실. 관심 구간에서 반드시 수렴하는 것은 아닙니다. 종종 그들은 평가 지점 근처에서 "완벽"하기 위해 함수 근사값의 정확도를 분배하는 형편없는 일을합니다. 오류는 일반적으로 벗어나면 위로 확대됩니다. 그리고 비 연속적 미분 (예 : 구형파, 삼각파 및 적분)이있는 함수가있는 경우 Taylor 시리즈는 잘못된 답을 제공합니다.
최대 차수 N의 다항식을 사용하여 구간 x0 <x <x1 동안 주어진 함수 f (x)를 근사화 할 때 가장 좋은 "쉬운"솔루션은 Chebyshev 근사치입니다 . 좋은 토론은 수치 레시피를 참조하십시오. 내가 링크 한 Wolfram 기사의 Tj (x)와 Tk (x)는 cos와 inverse cosine을 사용했으며, 이들은 다항식이며 실제로는 계수를 얻기 위해 반복 공식을 사용합니다. 다시, 수치 레시피를 참조하십시오.
편집하다 : Wikipedia에는 근사 이론 에 대한 반쯤 괜찮은 기사가 있습니다 . 그들이 인용하는 출처 중 하나 (Hart, "Computer Approximations")는 절판 (& 중고 사본은 비싸다)이지만 이와 같은 항목에 대해 자세히 설명합니다. (Jack Ganssle은 자신의 뉴스 레터 The Embedded Muse 39 호에서이를 언급합니다 .)
편집 2 : 다음은 sin (x)에 대한 Taylor 대 Chebyshev에 대한 유형의 오류 메트릭 (아래 참조)입니다. 참고해야 할 몇 가지 중요한 사항 :
오해하지 마세요 : Taylor 시리즈는 사인 / 코사인에 대해 제대로 작동합니다 (-pi / 2에서 + pi / 2 범위에 대해 합리적인 정밀도로; 기술적으로 충분한 용어를 사용하면 모든 실제 입력에 대해 원하는 정밀도에 도달 할 수 있습니다. 그러나 Taylor 시리즈를 사용하여 cos (100)를 계산하려고 시도하고 임의 정밀도 산술을 사용하지 않는 한 수행 할 수 없습니다. 비과학적인 계산기로 무인도에 갇혀서 사인과 코사인을 계산해야했다면 계수가 기억하기 쉽기 때문에 아마도 Taylor 시리즈를 사용할 것입니다. 그러나 자신의 sin () 또는 cos () 함수를 작성해야하는 실제 응용 프로그램은 원하는 정확도에 도달하기 위해 효율적인 구현을 사용하는 것이 가장 좋을만큼 드물며 Taylor 시리즈는 그렇지 않습니다 .
범위 = -pi / 2 ~ + pi / 2, 차수 5 (3 항)
범위 = -pi / 2 ~ + pi / 2, 차수 7 (4 항)
범위 = -pi / 4 ~ + pi / 4, 차수 3 (2 항)
범위 = -pi / 4 ~ + pi / 4, 차수 5 (3 항)
범위 = -pi / 4 ~ + pi / 4, 차수 7 (4 항)
나는 그들이 Taylor Series 또는 CORDIC을 사용하여 계산되었다고 믿습니다 . 삼각 함수 (게임, 그래픽)를 많이 사용하는 일부 응용 프로그램은 시작할 때 삼각 함수 테이블을 구성하므로 값을 반복해서 다시 계산하지 않고 조회 할 수 있습니다.
삼각 함수에 대한 Wikipedia 기사 를 확인하십시오 . 실제로 코드로 구현하는 방법을 배우기에 좋은 곳은 Numerical Recipes입니다. 입니다.
저는 수학자는 아니지만 sin, cos 및 tan이 "어디에서 왔는지"에 대한 이해는 어떤 의미에서 직각 삼각형으로 작업 할 때 관찰된다는 것입니다. 다른 직각 삼각형의 변의 길이를 측정하고 그래프에 점을 플로팅하면 그로부터 sin, cos 및 tan을 얻을 수 있습니다. Harper Shelby가 지적했듯이 함수는 단순히 직각 삼각형의 속성으로 정의됩니다.
이러한 비율이 원의 기하학과 어떤 관련이 있는지 이해함으로써보다 정교한 이해가 이루어지며, 이는 라디안과 그 모든 장점으로 이어집니다. Wikipedia 항목에 모두 있습니다.
@Jason S가 제공 한 답변을 확장하고 싶습니다. @Jason S가 설명한 것과 유사한 도메인 세분화 방법을 사용하고 Maclaurin 시리즈 근사를 사용하여 tan (), sin ()에 대한 평균 (2-3) X 속도 향상 , cos (), atan (), asin () 및 acos () 함수가 -O3 최적화를 통해 gcc 컴파일러에 내장되었습니다. 아래에 설명 된 최고의 Maclaurin 계열 근사 함수는 배정 밀도 정확도를 달성했습니다.
tan (), sin () 및 cos () 함수의 경우 단순화를 위해 0에서 2pi + pi / 80까지 겹치는 도메인은 pi / 80, 3pi / 80에서 "앵커 포인트"를 사용하여 81 개의 동일한 간격으로 나뉩니다. ..., 161pi / 80. 그런 다음이 81 개의 앵커 포인트 중 tan (), sin () 및 cos ()를 평가하고 저장했습니다. 삼각 ID의 도움으로 각 삼각 함수에 대해 단일 Maclaurin 시리즈 함수가 개발되었습니다. ± infinity 사이의 각도는 함수가 먼저 입력 각도를 0 ~ 2pi 도메인으로 변환하기 때문에 삼각 근사 함수에 제출 될 수 있습니다. 이 번역 오버 헤드는 근사 오버 헤드에 포함됩니다.
atan (), asin () 및 acos () 함수에 대해 유사한 메서드가 개발되었습니다. 여기서 -1.0에서 1.1까지의 겹치는 도메인은 -19/20, -17/20, .. ., 19/20, 21/20. 그런 다음이 21 개의 앵커 포인트 중 atan () 만 저장되었습니다. 다시 말하지만, 역 삼각 ID의 도움으로 atan () 함수에 대해 단일 Maclaurin 시리즈 함수가 개발되었습니다. 그런 다음 atan () 함수의 결과를 사용하여 asin () 및 acos ()를 근사했습니다.
모든 역 삼각 근사 함수는 atan () 근사 함수를 기반으로하므로 모든 배정 밀도 인수 입력 값이 허용됩니다. 그러나 asin () 및 acos () 근사 함수에 입력 된 인수는 ± 1 도메인으로 잘립니다. 외부의 값은 의미가 없기 때문입니다.
근사 함수를 테스트하기 위해 10 억 번의 임의 함수 평가가 강제로 평가되었습니다 (즉, -O3 최적화 컴파일러는 일부 계산 된 결과가 사용되지 않기 때문에 평가를 우회 할 수 없습니다.) 10 억 평가의 편향을 제거하기 위해 난수를 처리하고 결과를 처리하면 삼각 함수 또는 역 삼각 함수를 평가하지 않고 실행 비용이 먼저 수행되었습니다. 그런 다음이 편향을 각 테스트에서 빼서 실제 함수 평가 시간의보다 대표적인 근사치를 얻었습니다.
표 2. 표시된 기능을 10 억 번 실행하는 데 소요 된 시간 (초). 추정치는 표 1의 나머지 행에서 표 1의 첫 번째 행에 표시된 10 억 개의 난수를 평가하는 데 드는 시간 비용을 뺀 값입니다.
tan ()에서 보낸 시간 : 18.0515 18.2545
TAN3 ()에서 보낸 시간 : 5.93853 6.02349
TAN4 ()에서 보낸 시간 : 6.72216 6.99134
sin () 및 cos ()에서 보낸 시간 : 19.4052 19.4311
SINCOS3 ()에서 보낸 시간 : 7.85564 7.92844
SINCOS4 ()에서 보낸 시간 : 9.36672 9.57946
atan ()에서 보낸 시간 : 15.7160 15.6599
ATAN1 ()에서 보낸 시간 : 6.47800 6.55230
ATAN2 ()에서 보낸 시간 : 7.26730 7.24885
ATAN3 ()에서 보낸 시간 : 8.15299 8.21284
asin () 및 acos ()에 소요 된 시간 : 36.8833 36.9496
ASINCOS1 ()에서 보낸 시간 : 10.1655 9.78479
ASINCOS2 ()에서 보낸 시간 : 10.6236 10.6000
ASINCOS3 ()에서 보낸 시간 : 12.8430 12.0707
(공간 절약을 위해 표 1은 표시하지 않았습니다.) 표 2는 각 근사 함수에 대해 10 억 번의 평가를 두 번의 개별 실행 결과를 보여줍니다. 첫 번째 열은 첫 번째 실행이고 두 번째 열은 두 번째 실행입니다. 함수 이름의 숫자 '1', '2', '3'또는 '4'는 특정 삼각 또는 역 삼각 근사를 평가하기 위해 Maclaurin 급수 함수에서 사용되는 용어의 수를 나타냅니다. SINCOS # ()는 sin과 cos가 동시에 평가되었음을 의미합니다. 마찬가지로 ASINCOS # ()는 asin과 acos가 동시에 평가되었음을 의미합니다. 두 수량을 동시에 평가하는 데 추가 오버 헤드가 거의 없습니다.
결과에 따르면 용어 수를 늘리면 예상대로 실행 시간이 약간 늘어납니다. 가장 적은 수의 용어조차도 값이 ± 무한대에 가까운 tan () 근사값을 제외하고는 모든 곳에서 약 12-14 자리 정확도를 제공했습니다. tan () 함수에도 문제가있을 것으로 예상 할 수 있습니다.
비슷한 결과가 Unix의 고급 MacBook Pro 노트북과 Linux의 고급 데스크톱 컴퓨터에서 얻어졌습니다.