삼각 함수를 만들 때 my_sind(d)
, my_cosd(d)
, my_tand(d)
, 그 정도의 인수가 아닌 라디안을 사용하고 90의 배수에 정확한 답변을 제공, 나는 결과가 때로는 것을 발견 -0.0
보다는 0.0
.
my_sind( 0.0) --> 0.0
my_sind(-0.0) --> -0.0
my_sind(180.0) --> -0.0
my_sind(360.0) --> 0.0
sin()
그리고 tan()
일반적으로 주어진 기호 제로 입력에 동일한 기호 제로 결과를 반환합니다. 그것은 의미하게 my_sin()
일치해야 sin()
하는 입력에 있습니다.
my_sind( 0.0) alike sin( 0.0) --> 0.0
my_sind(-0.0) alike sin(-0.0) --> -0.0
문제는 : 정수가 무엇인지에 대한 non_zero_n
/ 결과는 지금까지 반환 할 수 있어야 -0.0
위해 my_sind(180*non_zero_n)
, my_cosd(180*n + 180)
, my_tand(180*non_zero_n)
?
코드 작성이 쉬워서 코드 만 f(-0.0)
작성 -0.0
하고 처리 할 수 있습니다. 다른 ( 0이 아닌 )에 대해 다른 f(x)
수익 -0.0
을 내야 할 이유가 있는지 와 그 사인을 보장하는 것이 중요하다는 것을 궁금해합니다 .x
참고 : 이것은 왜 0.0
vs. -0.0
가 발생 하는지에 대한 질문이 아닙니다 . 이것이 cos(machine_pi/4)
돌아 오지 않는 이유 는 아닙니다 0.0
. 0.0
또는 의 생성을 제어하는 방법에 대한 질문도 아닙니다 -0.0
. 나는 그것을 디자인 질문으로 가장 잘 본다.
답변
“최소한의 놀라움”의 설계 원칙은 우리가 이전에 확립 한 기능을 참조하여 제시 함을 시사합니다. 이 경우 IEEE Std 754-2008 (부동 소수점 산술에 대한 IEEE 표준), 섹션 9에서 소개 된 기능 sinpi
과 가장 가까운 기능이 제공됩니다. cospi
이러한 기능은 현재 ISO C 및 ISO C ++ 표준의 일부가 아니지만 CUDA와 같은 다양한 프로그래밍 플랫폼의 수학 라이브러리에 통합되었습니다.
이 함수는 sin (πx) 및 cos (πx)를 계산합니다. 여기서 π와의 곱셈은 함수 내부에서 암시 적으로 발생합니다. tanpi
수학적으로 정의 된 것은 아니지만 수학적 동등성에 기초하여에 따라 기능을 제공한다고 가정 할 수있다 tanpi(x) = sinpi(x) / cospi(x)
.
우리는 지금 정의 할 수 있습니다 sind(x) = sinpi(x/180)
, cosd(x) = cospi(x/180)
, tand(x) = tanpi(x/180)
직관적 인 방식으로. IEEE-754의 섹션 9.1.2에서는 sinpi
및에 대한 특수 인수 처리에 대해 설명 cospi
합니다. 특히:
양의 정수 n에 대해 sinPi (+ n)은 +0이고 sinPi (−n)은 -0입니다. 이는 적절한 반올림 모드에서 sinPi (−x) 및 −sinPi (x)가 모든 x에 대해 동일한 수 (또는 둘 다 NaN)임을 나타냅니다. n + ½을 표현할 수있는 경우 정수 n에 대해 cosPi (n + ½)은 +0입니다.
IEEE 754-2008 표준은 인용 된 요구 사항에 대한 이론적 근거를 제공하지 않지만 관련 섹션 의 초기 초안 은 다음과 같습니다.
함수의 값이 0이면이 0의 부호는 수학 함수의 부호 함수의 연속 확장을 고려하여 가장 잘 결정됩니다.
754 Working Group Mail Archive 의 Perusal은 추가 통찰력을 얻을 수 있지만,이를 조사 할 시간이 없었습니다. 구현 sind()
, cosd()
및 tand()
상술 한 바와 같이, 우리는 예를 들어 케이스의 표에 도달 :
SIND
angle value
-540 -0
-360 -0
-180 -0
0 0
180 0
360 0
540 0
COSD
angle value
-630 0
-450 0
-270 0
-90 0
90 0
270 0
450 0
TAND
angle value
-540 0
-360 -0
-180 0
0 0
180 -0
360 0
540 -0
답변
sin () 및 tan ()은 일반적으로 주어진 부호 0 입력에 대해 동일한 부호 0 결과를 반환합니다.
일반적으로 다음과 같은 이유로 사실 일 수 있습니다.
-
속도 / 정확도 . 충분히 작은 복식의 경우 가장 좋은 대답은
sin(x)
입니다x
. 즉, 약보다 작은 숫자1.49e-8
의 경우 x의 사인에 가장 가까운 double은 실제로 x 자체입니다 ( sin () 의 glibc 소스 코드 참조 ). -
특수한 경우의 취급 .
몇 가지 특별한 산술 연산은 0의 부호에 의해 영향을받습니다. 예를 들어,
"1/(+0) = +inf"
하지만"1/(-0) = -inf"
. 유용성을 유지하려면 부호 비트가 연속성 고려 사항에서 파생 된 규칙에 따라 특정 산술 연산을 통해 전파되어야합니다.sin (z) 및 tan (z)와 같은 초월 초월 함수와 그 역수 및 쌍곡선 유사체의 구현은 IEEE 표준에 의해 지정되지 않았지만 유사한 규칙을 따라야합니다. 의 구현은
의 가치와sin(z)
의 부호를 재현 할 것으로 예상됩니다z
z = ±O
.( 복잡한 초등 함수를위한 브랜치 컷 또는 W. Kahan 의 아무것도없는 사인 비트 에 대한 많은 열망)
음의 부호가있는 0은 아래에서 0에 접근하는 수학적 분석 개념을 단측 한계로 반영합니다 (
1 / sin(x)
제로의 부호는 큰 차이를 만듭니다).
편집하다
두 번째 요점을 고려하면 다음과 같이 작성 my_sind
합니다.
my_sind(-0.0) is -0.0
my_sind(0.0) is 0.0
최신 C 표준 (F.10.1.6 sin
및 F.10.1.7 tan
인수가있는 경우, 서명 제로로 구현), 지정 것으로 ±0
, 그것은 수정되지 않은 반환됩니다 .
편집 2
다른 값들에 대해서는 근사치의 문제라고 생각합니다. 주어진 M_PI
<π :
0 = sin(π) < sin(M_PI) ≈ 1.2246467991473532e-16 ≈ +0.0
0 = sin(-π) > sin(-M_PI) ≈ -1.2246467991473532e-16 ≈ -0.0
0 = sin(2*π) > sin(2*M_PI) ≈ -2.4492935982947064e-16
0 = sin(-2*π) < sin(-2*M_PI) ≈ 2.4492935982947064e-16
따라서 my_sind
180 °의 배수로 정확한 답을 제공 하면 반환 할 수 있습니다 ( +0.0
또는 -0.0
다른 것을 선호하는 명확한 이유는 보이지 않습니다).
경우 my_sind
사용은 일부 근사 (예 : degree * M_PI / 180.0
전환 식), 그것이 중요한 값을 접근하고 어떻게 고려해야합니다.
답변
라이브러리는 +0을 -0과 구별하지 않습니다. IEEE 754는 이러한 차이점에 대해 상당히 걱정하고 있습니다. 나는 수학의 함수를 수학적으로 표현할 수 없을 정도로 어려운 것을 발견했습니다. -PJ Plauger, 표준 C 라이브러리 , 1992, 128 페이지.
공식적으로 trig 함수는 C 표준에 따라 0의 부호를 반환해야합니다.
정의되지 않은 행동에 직면했을 때, 가장 놀랍게도의 원리 는에서 해당 함수의 행동을 복제하는 것을 제안합니다 math.h
. 이것은 math.h
제로의 부호에 의존하는 코드에 정확하게 버그를 도입하는 방법과 같은 냄새로 해당 기능의 동작에서 벗어나면서 정당한 냄새가납니다.