型別泛型數學 (自 C99 起)
出自 cppreference.com
標頭檔 <tgmath.h> 包含了標頭檔 <math.h> 與 <complex.h>,並定義了數個型別泛型巨集。這些巨集會根據引數的型別,決定要呼叫實數函數或適用的複數函數。
對於每個巨集,若其在無後綴的 <math.h> 函數中對應的實數型別為 double,則該參數被稱為泛型參數(例如 pow 的兩個參數皆為泛型參數,但 scalbn 僅第一個參數為泛型參數)。
當使用 <tgmath.h> 的巨集時,傳遞給泛型參數的引數型別會決定巨集所選取的函數(如下所述)。若引數型別與所選函數的參數型別不相容,則行為未定義(例如,若將複數引數傳遞給僅接受實數的 <tgmath.h> 巨集:float complex fc; ceil(fc); 或 double complex dc; double d; fmax(dc, d); 皆為未定義行為的範例)。
注意:型別泛型巨集在 C99 中是以實作定義的方式實作的,但在 C11 引入關鍵字 _Generic 後,便可透過可攜的方式實作這些巨集。
目錄 |
[編輯] 複數/實數型別泛型巨集
對於所有同時具有實數與複數對應的函數,皆存在一個型別泛型巨集 XXX,它會呼叫以下任一函數:
- 實數函數
- float 變體
XXXf - double 變體
XXX - long double 變體
XXXl
- float 變體
- 複數函數
- float 變體
cXXXf - double 變體
cXXX - long double 變體
cXXXl
- float 變體
上述規則的例外是 fabs 巨集(請參見下方表格)。
呼叫何種函數的判定方式如下:
- 若泛型參數的任一引數為虛數,則行為由各個函數參考頁面單獨指定(特別是
sin、cos、tan、cosh、sinh、tanh、asin、atan、asinh與atanh會呼叫實數函數;sin、tan、sinh、tanh、asin、atan、asinh與atanh的回傳型別為虛數,而cos與cosh的回傳型別為實數)。 - 若泛型參數的任一引數為複數,則呼叫複數函數;否則呼叫實數函數。
- 若泛型參數的任一引數為 long double,則呼叫 long double 變體。否則,若任一參數為 double 或整數,則呼叫 double 變體。否則,呼叫 float 變體。
型別泛型巨集如下:
| 型別泛型 巨集 |
實數函數 變體 |
複數函數 變體 | ||||
|---|---|---|---|---|---|---|
| float | double | long double | float | double | long double | |
| fabs | fabsf | fabs | fabsl | cabsf | cabs | cabsl |
| exp | expf | exp | expl | cexpf | cexp | cexpl |
| log | logf | log | logl | clogf | clog | clogl |
| pow | powf | pow | powl | cpowf | cpow | cpowl |
| sqrt | sqrtf | sqrt | sqrtl | csqrtf | csqrt | csqrtl |
| sin | sinf | sin | sinl | csinf | csin | csinl |
| cos | cosf | cos | cosl | ccosf | ccos | ccosl |
| tan | tanf | tan | tanl | ctanf | ctan | ctanl |
| asin | asinf | asin | asinl | casinf | casin | casinl |
| acos | acosf | acos | acosl | cacosf | cacos | cacosl |
| atan | atanf | atan | atanl | catanf | catan | catanl |
| sinh | sinhf | sinh | sinhl | csinhf | csinh | csinhl |
| cosh | coshf | cosh | coshl | ccoshf | ccosh | ccoshl |
| tanh | tanhf | tanh | tanhl | ctanhf | ctanh | ctanhl |
| asinh | asinhf | asinh | asinhl | casinhf | casinh | casinhl |
| acosh | acoshf | acosh | acoshl | cacoshf | cacosh | cacoshl |
| atanh | atanhf | atanh | atanhl | catanhf | catanh | catanhl |
[編輯] 僅限實數函數
對於所有沒有複數對應的函數(modf 除外),皆存在一個型別泛型巨集 XXX,它會呼叫以下任一實數函數變體:
- float 變體
XXXf - double 變體
XXX - long double 變體
XXXl
呼叫何種函數的判定方式如下:
- 若泛型參數的任一引數為 long double,則呼叫 long double 變體。否則,若泛型參數的任一引數為 double,則呼叫 double 變體。否則,呼叫 float 變體。
[編輯] 僅限複數函數
對於所有沒有實數對應的複數函數,皆存在一個型別泛型巨集 cXXX,它會呼叫以下任一複數函數變體:
呼叫何種函數的判定方式如下:
- 若泛型參數的任一引數為實數、複數或虛數,則會呼叫適當的複數函數。
| 型別泛型 巨集 |
複數函數 變體 | ||
|---|---|---|---|
| float | double | long double | |
| carg | cargf | carg | cargl |
| conj | conjf | conj | conjl |
| creal | crealf | creal | creall |
| cimag | cimagf | cimag | cimagl |
| cproj | cprojf | cproj | cprojl |
[編輯] 範例
執行此程式碼
#include <stdio.h> #include <tgmath.h> int main(void) { int i = 2; printf("sqrt(2) = %f\n", sqrt(i)); // argument type is int, calls sqrt float f = 0.5; printf("sin(0.5f) = %f\n", sin(f)); // argument type is float, calls sinf float complex dc = 1 + 0.5*I; float complex z = sqrt(dc); // argument type is float complex, calls csqrtf printf("sqrt(1 + 0.5i) = %f+%fi\n", creal(z), // argument type is float complex, calls crealf cimag(z)); // argument type is float complex, calls cimagf }
輸出
sqrt(2) = 1.414214 sin(0.5f) = 0.479426 sqrt(1 + 0.5i) = 1.029086+0.242934i
[編輯] 參考
- C23 標準 (ISO/IEC 9899:2024)
- 7.25 型別泛型數學 <tgmath.h> (p: 待定)
- C17 標準 (ISO/IEC 9899:2018)
- 7.25 型別泛型數學 <tgmath.h> (p: 272-273)
- C11 標準 (ISO/IEC 9899:2011)
- 7.25 型別泛型數學 <tgmath.h> (p: 373-375)
- C99 標準 (ISO/IEC 9899:1999)
- 7.22 型別泛型數學 <tgmath.h> (p: 335-337)