2015-07-19 174 views
-3

我確定這是一個非常愚蠢的問題,但是當我將180度的角度傳遞給c/C++的cos()和sin()函數時,我似乎收到一個不正確的值。我知道,它應該是:的0.0547 正弦和餘弦的0.99 但我得到3.5897934739308216e-009的罪惡和的-1.00000C++ Sin和Cos

我的代碼cos爲:

double radians = DegreesToRadians(angle); 
double cosValue = cos(radians); 
double sinValue = sin(radians); 

DegreesToRadians()是:

double DegreesToRadians(double degrees) 
{ 
    return degrees * PI/180; 
} 

謝謝:)

+1

'我知道它應該是:sin 0.0547,cos 0.99'更像「0和-1」。 – deviantfan

+2

PI的正弦爲0,餘弦爲-1。這聽起來像是你得到的。 –

+1

「0.0547的餘弦和0.99的餘弦」Huh?它應該完全是0和-1。你的代碼正確派生了(最多舍入錯誤)。 –

回答

6

C/C++提供sin(a)cos(a)tan(a)等需要與弧度單位而非一個參數函數。 double DegreesToRadians(d)執行的轉換是關閉,但轉換結果是四捨五入的近似值。此外,機器M_PI已接近,但與數學非理性π的值不同。

OP與180代碼傳遞給DegreesToRadians(d)然後sin()/cos()給出不同比預期由於四捨五入的double()有限精度和用於PI可能弱值的結果。

一個改進是在調用trig函數之前在中執行自變量減少。下面將角度先減小到-45°到45°範圍,然後再調用sin()。這將確保sind(90.0*N) --> -1.0, 0.0, 1.0N的較大值。 。注:sind(360.0*N +/- 30.0)可能不完全等於+/-0.5。需要一些額外的考慮。

#include <math.h> 
#include <stdio.h> 

static double d2r(double d) { 
    return (d/180.0) * ((double) M_PI); 
} 

double sind(double x) { 
    if (!isfinite(x)) { 
    return sin(x); 
    } 
    if (x < 0.0) { 
    return -sind(-x); 
    } 
    int quo; 
    double x90 = remquo(fabs(x), 90.0, &quo); 
    switch (quo % 4) { 
    case 0: 
     // Use * 1.0 to avoid -0.0 
     return sin(d2r(x90)* 1.0); 
    case 1: 
     return cos(d2r(x90)); 
    case 2: 
     return sin(d2r(-x90) * 1.0); 
    case 3: 
     return -cos(d2r(x90)); 
    } 
    return 0.0; 
} 

int main(void) { 
    int i; 
    for (i = -360; i <= 360; i += 15) { 
    printf("sin() of %.1f degrees is % .*e\n", 1.0 * i, DBL_DECIMAL_DIG - 1, 
     sin(d2r(i))); 
    printf("sind() of %.1f degrees is % .*e\n", 1.0 * i, DBL_DECIMAL_DIG - 1, 
     sind(i)); 
    } 
    return 0; 
} 

輸出

sin() of -360.0 degrees is 2.4492935982947064e-16 
sind() of -360.0 degrees is -0.0000000000000000e+00 // Exact 

sin() of -345.0 degrees is 2.5881904510252068e-01 // 76-68 = 8 away 
//       2.5881904510252076e-01 
sind() of -345.0 degrees is 2.5881904510252074e-01 // 76-74 = 2 away 

sin() of -330.0 degrees is 5.0000000000000044e-01 // 44 away 
// 0.5      5.0000000000000000e-01 
sind() of -330.0 degrees is 4.9999999999999994e-01 // 6 away 

sin() of -315.0 degrees is 7.0710678118654768e-01 // 68-52 = 16 away 
// square root 0.5 -->  7.0710678118654752e-01 
sind() of -315.0 degrees is 7.0710678118654746e-01 // 52-46 = 6 away 

sin() of -300.0 degrees is 8.6602540378443860e-01 
sind() of -300.0 degrees is 8.6602540378443871e-01 
sin() of -285.0 degrees is 9.6592582628906842e-01 
sind() of -285.0 degrees is 9.6592582628906831e-01 
sin() of -270.0 degrees is 1.0000000000000000e+00 // Exact 
sind() of -270.0 degrees is 1.0000000000000000e+00 // Exact 
... 
+1

謝謝你的全面答案,非常翔實的 –

+0

@chux我假設「給出的結果與預期不同」意在讀作「給出的結果不同於預期的更多*」 – njuffa

+0

@njuffa好主意,可以這樣說它有點不清楚這個答案顯示瞭如何通過首先使用範圍減少度,然後轉換爲弧度,我們甚至可以做得更好,並將預期的精確值返回180度。 – chux

8

首先,180度的餘弦值應等於-1,所以運算結果y你是對的。

其次,你有時可以不使用sin/cos/tan等功能時,你總能得到結果是最接近正確的人得到確切值。在你的情況下,你從sin得到的值最接近零。

您得到的sin(PI)的值僅在第9個(!)後的浮點數之後才爲零。 3.5897934739308216e-009幾乎等於0.000000004,這幾乎等於零。

+0

OP,請閱讀本文,如果你還沒有:http://floating-point-gui.de/ – SolarBear

+0

謝謝,對不起,我得到了關於轉換的棒的錯誤結束:( –

5

轉換應用到64位時,我有同樣的問題作爲OP。
我的解決方案是使用新的math.h函數__cospi()和__sinpi()。
性能與cos()和sin()相似(甚至快1%)。

// cos(M_PI * -90.0/180.0) returns 0.00000000000000006123233995736766 
//__cospi(  -90.0/180.0) returns 0.0, as it should 
// #define degree2rad 3.14159265359/180 
// #define degree2rad M_PI/ 180.0 
// double rot = -degree2rad * ang; 
// double sn = sin(rot); 
// double cs = cos(rot); 

double rot = -ang/180.0; 
double sn = __sinpi(rot); 
double cs = __cospi(rot); 

從數學。h:

/* __sinpi(x) returns the sine of pi times x; __cospi(x) and __tanpi(x) return 
the cosine and tangent, respectively. These functions can produce a more 
accurate answer than expressions of the form sin(M_PI * x) because they 
avoid any loss of precision that results from rounding the result of the 
multiplication M_PI * x. They may also be significantly more efficient in 
some cases because the argument reduction for these functions is easier 
to compute. Consult the man pages for edge case details.     */ 
相關問題