diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml new file mode 100644 index 2946122..434fb88 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -993,9 +993,9 @@ Finally, shows the available trigonometric functions. All trigonometric functions take arguments and return values of type double - precision. Trigonometric functions arguments are expressed - in radians. Inverse functions return values are expressed in - radians. See unit transformation functions + precision. Each of the trigonometric functions comes in + two varieties, one which works in radians and one which works in + degrees. See unit transformation functions radians() and degrees() above. @@ -1003,10 +1003,11 @@ Trigonometric Functions - + - Function + Function (radians) + Function (degrees) Description @@ -1018,6 +1019,11 @@ acosacos(x) + + + acosd + acosd(x) + inverse cosine @@ -1028,6 +1034,12 @@ asin(x) + + + asind + + asind(x) + inverse sine @@ -1038,6 +1050,12 @@ atan(x) + + + atand + + atand(x) + inverse tangent @@ -1049,6 +1067,13 @@ atan2(y, x) + + + atan2d + + atan2d(y, + x) + inverse tangent of y/x @@ -1060,6 +1085,12 @@ cos(x) + + + cosd + + cosd(x) + cosine @@ -1070,6 +1101,12 @@ cot(x) + + + cotd + + cotd(x) + cotangent @@ -1080,6 +1117,12 @@ sin(x) + + + sind + + sind(x) + sine @@ -1090,6 +1133,12 @@ tan(x) + + + tand + + tand(x) + tangent diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c new file mode 100644 index 4e927d8..d2318f7 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -1535,7 +1535,7 @@ dacos(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1556,7 +1556,7 @@ dasin(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1577,7 +1577,7 @@ datan(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1599,7 +1599,7 @@ datan2(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1) || isinf(arg2), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1620,7 +1620,7 @@ dcos(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1642,7 +1642,7 @@ dcot(PG_FUNCTION_ARGS) errmsg("input is out of range"))); result = 1.0 / result; - CHECKFLOATVAL(result, true /* cotan(pi/2) == inf */ , true); + CHECKFLOATVAL(result, true /* cot(0) == Inf */ , true); PG_RETURN_FLOAT8(result); } @@ -1663,7 +1663,7 @@ dsin(PG_FUNCTION_ARGS) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("input is out of range"))); - CHECKFLOATVAL(result, isinf(arg1), true); + CHECKFLOATVAL(result, false, true); PG_RETURN_FLOAT8(result); } @@ -1688,6 +1688,368 @@ dtan(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } + +/* + * asind_q1 - returns the inverse sine of x in degrees, where x is + * assumed to be in the range [0, 1] and the result is + * an angle in the first quadrant (0 to 90 degrees). + * + * In this quadrant there are 3 special case inputs (0, 0.5 and 1) for which + * this function will return exact values (0, 30 and 90 respectively). + */ +static double +asind_q1(double x) +{ + /* + * Stitch together inverse sine and cosine functions for the ranges + * [0, 0.5] and [0.5, 1]. Each expression below is guaranteed to return + * exactly 30 for x=0.5, so the result is a continuous monotonic function + * over the full range. + */ + if (x <= 0.5) + return (asin(x) / asin(0.5)) * 30; + else + return 90 - (acos(x) / acos(0.5)) * 60; +} + + +/* + * acosd_q1 - returns the inverse cosine of x in degrees, where x + * is assumed to be in the range [0, 1] and the result + * is an angle in the first quadrant (0 to 90 degrees). + * + * In this quadrant there are 3 special case inputs (0, 0.5 and 1) for which + * this function will return exact values (0, 60 and 90 respectively). + */ +static double +acosd_q1(double x) +{ + /* + * Stitch together inverse sine and cosine functions for the ranges + * [0, 0.5] and [0.5, 1]. Each expression below is guaranteed to return + * exactly 60 for x=0.5, so the result is a continuous monotonic function + * over the full range. + */ + if (x <= 0.5) + return 90 - (asin(x) / asin(0.5)) * 30; + else + return (acos(x) / acos(0.5)) * 60; +} + + +/* + * dacosd - returns the arccos of arg1 (degrees) + */ +Datum +dacosd(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + float8 result; + + if (isinf(arg1) || arg1 < -1 || arg1 > 1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("input is out of range"))); + + if (isnan(arg1)) + result = arg1; + else if (arg1 >= 0) + result = acosd_q1(arg1); + else + result = 90 + asind_q1(-arg1); + + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * dasind - returns the arcsin of arg1 (degrees) + */ +Datum +dasind(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + float8 result; + + if (isinf(arg1) || arg1 < -1 || arg1 > 1) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("input is out of range"))); + + if (isnan(arg1)) + result = arg1; + else if (arg1 >= 0) + result = asind_q1(arg1); + else + result = -asind_q1(-arg1); + + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * datand - returns the arctan of arg1 (degrees) + */ +Datum +datand(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + float8 result; + + errno = 0; + result = atan(arg1); + if (errno != 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("input is out of range"))); + + result = (result / atan(1.0)) * 45; + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * atan2d - returns the arctan2 of arg1 (degrees) + */ +Datum +datan2d(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + float8 arg2 = PG_GETARG_FLOAT8(1); + float8 result; + + errno = 0; + result = atan2(arg1, arg2); + if (errno != 0) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("input is out of range"))); + + result = (result / atan(1.0)) * 45; + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * sind_0_to_30 - returns the sine of an angle that lies between 0 and + * 30 degrees. This will return exactly 0 when x is 0, + * and exactly 0.5 when x is 30 degrees. + */ +static double +sind_0_to_30(double x) +{ + return ( sin(x * (M_PI/180)) / sin(30 * (M_PI/180)) ) / 2; +} + + +/* + * cosd_0_to_60 - returns the cosine of an angle that lies between 0 + * and 60 degrees. This will return exactly 1 when x + * is 0 and exactly 0.5 when x is 60 degrees. + */ +static double +cosd_0_to_60(double x) +{ + return ( 2 - (1 - cos(x * (M_PI/180))) / (1 - cos(60 * (M_PI/180))) ) / 2; +} + + +/* + * sind_q1 - returns the sine of an angle in the first quadrant + * (0 to 90 degrees). + */ +static double +sind_q1(double x) +{ + /* + * Stitch together the sine and cosine functions for the ranges [0, 30] + * and [30, 90]. These guarantee to return exact answers at their + * endpoints, so the overall result is a continuous monotonic function + * that gives exact results when x = 0, 30 and 90 degrees. + */ + return x <= 30 ? sind_0_to_30(x) : cosd_0_to_60(90-x); +} + + +/* + * cosd_q1 - returns the cosine of an angle in the first quadrant + * (0 to 90 degrees). + */ +static double +cosd_q1(double x) +{ + /* + * Stitch together the sine and cosine functions for the ranges [0, 60] + * and [60, 90]. These guarantee to return exact answers at their + * endpoints, so the overall result is a continuous monotonic function + * that gives exact results when x = 0, 60 and 90 degrees. + */ + return x <= 60 ? cosd_0_to_60(x) : sind_0_to_30(90-x); +} + + +/* + * dcosd - returns the cosine of arg1 (degrees) + */ +Datum +dcosd(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + int sign = 1; + float8 result; + + /* Reduce the range of the input to [0,90] degrees */ + arg1 = fmod(arg1, 360.0); + if (isnan(arg1)) + PG_RETURN_FLOAT8(arg1); + + if (arg1 < 0) + /* cosd(-x) = cosd(x) */ + arg1 = -arg1; + + if (arg1 > 180) + /* cosd(360-x) = cosd(x) */ + arg1 = 360 - arg1; + + if (arg1 > 90) + { + /* cosd(180-x) = -cosd(x) */ + arg1 = 180 - arg1; + sign = -sign; + } + + result = sign * cosd_q1(arg1); + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * dcotd - returns the cotangent of arg1 (degrees) + */ +Datum +dcotd(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + int sign = 1; + float8 result; + + /* Reduce the range of the input to [0,90] degrees */ + arg1 = fmod(arg1, 360.0); + if (isnan(arg1)) + PG_RETURN_FLOAT8(arg1); + + if (arg1 < 0) + { + /* cotd(-x) = -cotd(x) */ + arg1 = -arg1; + sign = -sign; + } + + if (arg1 > 180) + { + /* cotd(360-x) = -cotd(x) */ + arg1 = 360 - arg1; + sign = -sign; + } + + if (arg1 > 90) + { + /* cotd(180-x) = -cotd(x) */ + arg1 = 180 - arg1; + sign = -sign; + } + + result = sign * cosd_q1(arg1) / sind_q1(arg1); + CHECKFLOATVAL(result, true /* cotd(0) == Inf */ , true); + PG_RETURN_FLOAT8(result); +} + + +/* + * dsind - returns the sine of arg1 (degrees) + */ +Datum +dsind(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + int sign = 1; + float8 result; + + /* Reduce the range of the input to [0,90] degrees */ + arg1 = fmod(arg1, 360.0); + if (isnan(arg1)) + PG_RETURN_FLOAT8(arg1); + + if (arg1 < 0) + { + /* sind(-x) = -sind(x) */ + arg1 = -arg1; + sign = -sign; + } + + if (arg1 > 180) + { + /* sind(360-x) = -sind(x) */ + arg1 = 360 - arg1; + sign = -sign; + } + + if (arg1 > 90) + /* sind(180-x) = sind(x) */ + arg1 = 180 - arg1; + + result = sign * sind_q1(arg1); + CHECKFLOATVAL(result, false, true); + PG_RETURN_FLOAT8(result); +} + + +/* + * dtand - returns the tangent of arg1 (degrees) + */ +Datum +dtand(PG_FUNCTION_ARGS) +{ + float8 arg1 = PG_GETARG_FLOAT8(0); + int sign = 1; + float8 result; + + /* Reduce the range of the input to [0,90] degrees */ + arg1 = fmod(arg1, 360.0); + if (isnan(arg1)) + PG_RETURN_FLOAT8(arg1); + + if (arg1 < 0) + { + /* tand(-x) = -tand(x) */ + arg1 = -arg1; + sign = -sign; + } + + if (arg1 > 180) + { + /* tand(360-x) = -tand(x) */ + arg1 = 360 - arg1; + sign = -sign; + } + + if (arg1 > 90) + { + /* tand(180-x) = -tand(x) */ + arg1 = 180 - arg1; + sign = -sign; + } + + result = sign * sind_q1(arg1) / cosd_q1(arg1); + CHECKFLOATVAL(result, true /* tand(90) == Inf */ , true); + PG_RETURN_FLOAT8(result); +} + /* * degrees - returns degrees converted from radians diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h new file mode 100644 index f688454..18a9e1d --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -1892,6 +1892,24 @@ DATA(insert OID = 1606 ( tan PGNSP P DESCR("tangent"); DATA(insert OID = 1607 ( cot PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dcot _null_ _null_ _null_ )); DESCR("cotangent"); + +DATA(insert OID = 3300 ( asind PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dasind _null_ _null_ _null_ )); +DESCR("arcsine, degrees"); +DATA(insert OID = 3308 ( acosd PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dacosd _null_ _null_ _null_ )); +DESCR("arccosine, degrees"); +DATA(insert OID = 3309 ( atand PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ datand _null_ _null_ _null_ )); +DESCR("arctangent, degrees"); +DATA(insert OID = 3315 ( atan2d PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 701 "701 701" _null_ _null_ _null_ _null_ _null_ datan2d _null_ _null_ _null_ )); +DESCR("arctangent, two arguments, degrees"); +DATA(insert OID = 3316 ( sind PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dsind _null_ _null_ _null_ )); +DESCR("sine, degrees"); +DATA(insert OID = 3317 ( cosd PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dcosd _null_ _null_ _null_ )); +DESCR("cosine, degrees"); +DATA(insert OID = 3318 ( tand PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dtand _null_ _null_ _null_ )); +DESCR("tangent, degrees"); +DATA(insert OID = 3319 ( cotd PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ dcotd _null_ _null_ _null_ )); +DESCR("cotangent, degrees"); + DATA(insert OID = 1608 ( degrees PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ degrees _null_ _null_ _null_ )); DESCR("radians to degrees"); DATA(insert OID = 1609 ( radians PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 701 "701" _null_ _null_ _null_ _null_ _null_ radians _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h new file mode 100644 index fc1679e..62751ec --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -407,6 +407,14 @@ extern Datum dcos(PG_FUNCTION_ARGS); extern Datum dcot(PG_FUNCTION_ARGS); extern Datum dsin(PG_FUNCTION_ARGS); extern Datum dtan(PG_FUNCTION_ARGS); +extern Datum dacosd(PG_FUNCTION_ARGS); +extern Datum dasind(PG_FUNCTION_ARGS); +extern Datum datand(PG_FUNCTION_ARGS); +extern Datum datan2d(PG_FUNCTION_ARGS); +extern Datum dcosd(PG_FUNCTION_ARGS); +extern Datum dcotd(PG_FUNCTION_ARGS); +extern Datum dsind(PG_FUNCTION_ARGS); +extern Datum dtand(PG_FUNCTION_ARGS); extern Datum degrees(PG_FUNCTION_ARGS); extern Datum dpi(PG_FUNCTION_ARGS); extern Datum radians(PG_FUNCTION_ARGS); diff --git a/src/test/regress/expected/float8.out b/src/test/regress/expected/float8.out new file mode 100644 index 6221538..a6261d2 --- a/src/test/regress/expected/float8.out +++ b/src/test/regress/expected/float8.out @@ -444,3 +444,330 @@ SELECT '' AS five, * FROM FLOAT8_TBL; | -1.2345678901234e-200 (5 rows) +-- Test the trigonometric functions. +-- Use a lower precision to eliminate variations between platforms. +SET extra_float_digits TO -5; +-- sine and cosine +SELECT x, + sin(radians(x)) AS sin_radians, sind(x), + cos(radians(x)) AS cos_radians, cosd(x) +FROM generate_series(-360, 360, 10) AS t(x) +WHERE x = 0 OR x % 90 != 0; -- skip tests that are very platform-dependent + x | sin_radians | sind | cos_radians | cosd +------+---------------+---------------+---------------+--------------- + -350 | 0.1736481777 | 0.1736481777 | 0.984807753 | 0.984807753 + -340 | 0.3420201433 | 0.3420201433 | 0.9396926208 | 0.9396926208 + -330 | 0.5 | 0.5 | 0.8660254038 | 0.8660254038 + -320 | 0.6427876097 | 0.6427876097 | 0.7660444431 | 0.7660444431 + -310 | 0.7660444431 | 0.7660444431 | 0.6427876097 | 0.6427876097 + -300 | 0.8660254038 | 0.8660254038 | 0.5 | 0.5 + -290 | 0.9396926208 | 0.9396926208 | 0.3420201433 | 0.3420201433 + -280 | 0.984807753 | 0.984807753 | 0.1736481777 | 0.1736481777 + -260 | 0.984807753 | 0.984807753 | -0.1736481777 | -0.1736481777 + -250 | 0.9396926208 | 0.9396926208 | -0.3420201433 | -0.3420201433 + -240 | 0.8660254038 | 0.8660254038 | -0.5 | -0.5 + -230 | 0.7660444431 | 0.7660444431 | -0.6427876097 | -0.6427876097 + -220 | 0.6427876097 | 0.6427876097 | -0.7660444431 | -0.7660444431 + -210 | 0.5 | 0.5 | -0.8660254038 | -0.8660254038 + -200 | 0.3420201433 | 0.3420201433 | -0.9396926208 | -0.9396926208 + -190 | 0.1736481777 | 0.1736481777 | -0.984807753 | -0.984807753 + -170 | -0.1736481777 | -0.1736481777 | -0.984807753 | -0.984807753 + -160 | -0.3420201433 | -0.3420201433 | -0.9396926208 | -0.9396926208 + -150 | -0.5 | -0.5 | -0.8660254038 | -0.8660254038 + -140 | -0.6427876097 | -0.6427876097 | -0.7660444431 | -0.7660444431 + -130 | -0.7660444431 | -0.7660444431 | -0.6427876097 | -0.6427876097 + -120 | -0.8660254038 | -0.8660254038 | -0.5 | -0.5 + -110 | -0.9396926208 | -0.9396926208 | -0.3420201433 | -0.3420201433 + -100 | -0.984807753 | -0.984807753 | -0.1736481777 | -0.1736481777 + -80 | -0.984807753 | -0.984807753 | 0.1736481777 | 0.1736481777 + -70 | -0.9396926208 | -0.9396926208 | 0.3420201433 | 0.3420201433 + -60 | -0.8660254038 | -0.8660254038 | 0.5 | 0.5 + -50 | -0.7660444431 | -0.7660444431 | 0.6427876097 | 0.6427876097 + -40 | -0.6427876097 | -0.6427876097 | 0.7660444431 | 0.7660444431 + -30 | -0.5 | -0.5 | 0.8660254038 | 0.8660254038 + -20 | -0.3420201433 | -0.3420201433 | 0.9396926208 | 0.9396926208 + -10 | -0.1736481777 | -0.1736481777 | 0.984807753 | 0.984807753 + 0 | 0 | 0 | 1 | 1 + 10 | 0.1736481777 | 0.1736481777 | 0.984807753 | 0.984807753 + 20 | 0.3420201433 | 0.3420201433 | 0.9396926208 | 0.9396926208 + 30 | 0.5 | 0.5 | 0.8660254038 | 0.8660254038 + 40 | 0.6427876097 | 0.6427876097 | 0.7660444431 | 0.7660444431 + 50 | 0.7660444431 | 0.7660444431 | 0.6427876097 | 0.6427876097 + 60 | 0.8660254038 | 0.8660254038 | 0.5 | 0.5 + 70 | 0.9396926208 | 0.9396926208 | 0.3420201433 | 0.3420201433 + 80 | 0.984807753 | 0.984807753 | 0.1736481777 | 0.1736481777 + 100 | 0.984807753 | 0.984807753 | -0.1736481777 | -0.1736481777 + 110 | 0.9396926208 | 0.9396926208 | -0.3420201433 | -0.3420201433 + 120 | 0.8660254038 | 0.8660254038 | -0.5 | -0.5 + 130 | 0.7660444431 | 0.7660444431 | -0.6427876097 | -0.6427876097 + 140 | 0.6427876097 | 0.6427876097 | -0.7660444431 | -0.7660444431 + 150 | 0.5 | 0.5 | -0.8660254038 | -0.8660254038 + 160 | 0.3420201433 | 0.3420201433 | -0.9396926208 | -0.9396926208 + 170 | 0.1736481777 | 0.1736481777 | -0.984807753 | -0.984807753 + 190 | -0.1736481777 | -0.1736481777 | -0.984807753 | -0.984807753 + 200 | -0.3420201433 | -0.3420201433 | -0.9396926208 | -0.9396926208 + 210 | -0.5 | -0.5 | -0.8660254038 | -0.8660254038 + 220 | -0.6427876097 | -0.6427876097 | -0.7660444431 | -0.7660444431 + 230 | -0.7660444431 | -0.7660444431 | -0.6427876097 | -0.6427876097 + 240 | -0.8660254038 | -0.8660254038 | -0.5 | -0.5 + 250 | -0.9396926208 | -0.9396926208 | -0.3420201433 | -0.3420201433 + 260 | -0.984807753 | -0.984807753 | -0.1736481777 | -0.1736481777 + 280 | -0.984807753 | -0.984807753 | 0.1736481777 | 0.1736481777 + 290 | -0.9396926208 | -0.9396926208 | 0.3420201433 | 0.3420201433 + 300 | -0.8660254038 | -0.8660254038 | 0.5 | 0.5 + 310 | -0.7660444431 | -0.7660444431 | 0.6427876097 | 0.6427876097 + 320 | -0.6427876097 | -0.6427876097 | 0.7660444431 | 0.7660444431 + 330 | -0.5 | -0.5 | 0.8660254038 | 0.8660254038 + 340 | -0.3420201433 | -0.3420201433 | 0.9396926208 | 0.9396926208 + 350 | -0.1736481777 | -0.1736481777 | 0.984807753 | 0.984807753 +(65 rows) + +-- test exactness +SELECT x, + CASE WHEN sind(x) IN (-1,-0.5,0,0.5,1) THEN sind(x) END AS sind, + CASE WHEN cosd(x) IN (-1,-0.5,0,0.5,1) THEN cosd(x) END AS cosd +FROM generate_series(0, 360, 30) AS t(x); + x | sind | cosd +-----+------+------ + 0 | 0 | 1 + 30 | 0.5 | + 60 | | 0.5 + 90 | 1 | 0 + 120 | | -0.5 + 150 | 0.5 | + 180 | 0 | -1 + 210 | -0.5 | + 240 | | -0.5 + 270 | -1 | 0 + 300 | | 0.5 + 330 | -0.5 | + 360 | 0 | 1 +(13 rows) + +-- tangent and cotangent +SELECT x, + tan(radians(x)) AS tan_radians, tand(x), + cot(radians(x)) AS cot_radians, cotd(x) +FROM generate_series(-360, 360, 10) AS t(x) +WHERE x = 0 OR x % 90 != 0; -- skip tests that are very platform-dependent + x | tan_radians | tand | cot_radians | cotd +------+---------------+---------------+---------------+--------------- + -350 | 0.1763269807 | 0.1763269807 | 5.67128182 | 5.67128182 + -340 | 0.3639702343 | 0.3639702343 | 2.747477419 | 2.747477419 + -330 | 0.5773502692 | 0.5773502692 | 1.732050808 | 1.732050808 + -320 | 0.8390996312 | 0.8390996312 | 1.191753593 | 1.191753593 + -310 | 1.191753593 | 1.191753593 | 0.8390996312 | 0.8390996312 + -300 | 1.732050808 | 1.732050808 | 0.5773502692 | 0.5773502692 + -290 | 2.747477419 | 2.747477419 | 0.3639702343 | 0.3639702343 + -280 | 5.67128182 | 5.67128182 | 0.1763269807 | 0.1763269807 + -260 | -5.67128182 | -5.67128182 | -0.1763269807 | -0.1763269807 + -250 | -2.747477419 | -2.747477419 | -0.3639702343 | -0.3639702343 + -240 | -1.732050808 | -1.732050808 | -0.5773502692 | -0.5773502692 + -230 | -1.191753593 | -1.191753593 | -0.8390996312 | -0.8390996312 + -220 | -0.8390996312 | -0.8390996312 | -1.191753593 | -1.191753593 + -210 | -0.5773502692 | -0.5773502692 | -1.732050808 | -1.732050808 + -200 | -0.3639702343 | -0.3639702343 | -2.747477419 | -2.747477419 + -190 | -0.1763269807 | -0.1763269807 | -5.67128182 | -5.67128182 + -170 | 0.1763269807 | 0.1763269807 | 5.67128182 | 5.67128182 + -160 | 0.3639702343 | 0.3639702343 | 2.747477419 | 2.747477419 + -150 | 0.5773502692 | 0.5773502692 | 1.732050808 | 1.732050808 + -140 | 0.8390996312 | 0.8390996312 | 1.191753593 | 1.191753593 + -130 | 1.191753593 | 1.191753593 | 0.8390996312 | 0.8390996312 + -120 | 1.732050808 | 1.732050808 | 0.5773502692 | 0.5773502692 + -110 | 2.747477419 | 2.747477419 | 0.3639702343 | 0.3639702343 + -100 | 5.67128182 | 5.67128182 | 0.1763269807 | 0.1763269807 + -80 | -5.67128182 | -5.67128182 | -0.1763269807 | -0.1763269807 + -70 | -2.747477419 | -2.747477419 | -0.3639702343 | -0.3639702343 + -60 | -1.732050808 | -1.732050808 | -0.5773502692 | -0.5773502692 + -50 | -1.191753593 | -1.191753593 | -0.8390996312 | -0.8390996312 + -40 | -0.8390996312 | -0.8390996312 | -1.191753593 | -1.191753593 + -30 | -0.5773502692 | -0.5773502692 | -1.732050808 | -1.732050808 + -20 | -0.3639702343 | -0.3639702343 | -2.747477419 | -2.747477419 + -10 | -0.1763269807 | -0.1763269807 | -5.67128182 | -5.67128182 + 0 | 0 | 0 | Infinity | Infinity + 10 | 0.1763269807 | 0.1763269807 | 5.67128182 | 5.67128182 + 20 | 0.3639702343 | 0.3639702343 | 2.747477419 | 2.747477419 + 30 | 0.5773502692 | 0.5773502692 | 1.732050808 | 1.732050808 + 40 | 0.8390996312 | 0.8390996312 | 1.191753593 | 1.191753593 + 50 | 1.191753593 | 1.191753593 | 0.8390996312 | 0.8390996312 + 60 | 1.732050808 | 1.732050808 | 0.5773502692 | 0.5773502692 + 70 | 2.747477419 | 2.747477419 | 0.3639702343 | 0.3639702343 + 80 | 5.67128182 | 5.67128182 | 0.1763269807 | 0.1763269807 + 100 | -5.67128182 | -5.67128182 | -0.1763269807 | -0.1763269807 + 110 | -2.747477419 | -2.747477419 | -0.3639702343 | -0.3639702343 + 120 | -1.732050808 | -1.732050808 | -0.5773502692 | -0.5773502692 + 130 | -1.191753593 | -1.191753593 | -0.8390996312 | -0.8390996312 + 140 | -0.8390996312 | -0.8390996312 | -1.191753593 | -1.191753593 + 150 | -0.5773502692 | -0.5773502692 | -1.732050808 | -1.732050808 + 160 | -0.3639702343 | -0.3639702343 | -2.747477419 | -2.747477419 + 170 | -0.1763269807 | -0.1763269807 | -5.67128182 | -5.67128182 + 190 | 0.1763269807 | 0.1763269807 | 5.67128182 | 5.67128182 + 200 | 0.3639702343 | 0.3639702343 | 2.747477419 | 2.747477419 + 210 | 0.5773502692 | 0.5773502692 | 1.732050808 | 1.732050808 + 220 | 0.8390996312 | 0.8390996312 | 1.191753593 | 1.191753593 + 230 | 1.191753593 | 1.191753593 | 0.8390996312 | 0.8390996312 + 240 | 1.732050808 | 1.732050808 | 0.5773502692 | 0.5773502692 + 250 | 2.747477419 | 2.747477419 | 0.3639702343 | 0.3639702343 + 260 | 5.67128182 | 5.67128182 | 0.1763269807 | 0.1763269807 + 280 | -5.67128182 | -5.67128182 | -0.1763269807 | -0.1763269807 + 290 | -2.747477419 | -2.747477419 | -0.3639702343 | -0.3639702343 + 300 | -1.732050808 | -1.732050808 | -0.5773502692 | -0.5773502692 + 310 | -1.191753593 | -1.191753593 | -0.8390996312 | -0.8390996312 + 320 | -0.8390996312 | -0.8390996312 | -1.191753593 | -1.191753593 + 330 | -0.5773502692 | -0.5773502692 | -1.732050808 | -1.732050808 + 340 | -0.3639702343 | -0.3639702343 | -2.747477419 | -2.747477419 + 350 | -0.1763269807 | -0.1763269807 | -5.67128182 | -5.67128182 +(65 rows) + +-- test exactness +SELECT x, + CASE WHEN tand(x) IN (-1,0,1) THEN tand(x) END AS tand, + CASE WHEN cotd(x) IN (-1,0,1) THEN cotd(x) END AS cotd +FROM generate_series(0, 360, 45) AS t(x); + x | tand | cotd +-----+------+------ + 0 | 0 | + 45 | 1 | 1 + 90 | | 0 + 135 | -1 | -1 + 180 | -0 | + 225 | 1 | 1 + 270 | | -0 + 315 | -1 | -1 + 360 | 0 | +(9 rows) + +-- arcsine and arccosine +SELECT x, + degrees(asin(x)) AS degrees_asin, asind(x), + degrees(acos(x)) AS degrees_acos, acosd(x) +FROM generate_series(-1.0, 1.0, 0.1) AS t(x); + x | degrees_asin | asind | degrees_acos | acosd +------+--------------+--------------+--------------+------------- + -1.0 | -90 | -90 | 180 | 180 + -0.9 | -64.15806724 | -64.15806724 | 154.1580672 | 154.1580672 + -0.8 | -53.13010235 | -53.13010235 | 143.1301024 | 143.1301024 + -0.7 | -44.427004 | -44.427004 | 134.427004 | 134.427004 + -0.6 | -36.86989765 | -36.86989765 | 126.8698976 | 126.8698976 + -0.5 | -30 | -30 | 120 | 120 + -0.4 | -23.57817848 | -23.57817848 | 113.5781785 | 113.5781785 + -0.3 | -17.45760312 | -17.45760312 | 107.4576031 | 107.4576031 + -0.2 | -11.53695903 | -11.53695903 | 101.536959 | 101.536959 + -0.1 | -5.739170477 | -5.739170477 | 95.73917048 | 95.73917048 + 0.0 | 0 | 0 | 90 | 90 + 0.1 | 5.739170477 | 5.739170477 | 84.26082952 | 84.26082952 + 0.2 | 11.53695903 | 11.53695903 | 78.46304097 | 78.46304097 + 0.3 | 17.45760312 | 17.45760312 | 72.54239688 | 72.54239688 + 0.4 | 23.57817848 | 23.57817848 | 66.42182152 | 66.42182152 + 0.5 | 30 | 30 | 60 | 60 + 0.6 | 36.86989765 | 36.86989765 | 53.13010235 | 53.13010235 + 0.7 | 44.427004 | 44.427004 | 45.572996 | 45.572996 + 0.8 | 53.13010235 | 53.13010235 | 36.86989765 | 36.86989765 + 0.9 | 64.15806724 | 64.15806724 | 25.84193276 | 25.84193276 + 1.0 | 90 | 90 | 0 | 0 +(21 rows) + +-- arctangent +SELECT x, degrees(atan(x)) AS degrees_atan, atand(x) +FROM (SELECT '-Infinity'::float8 + UNION ALL + SELECT generate_series(-10, -2) + UNION ALL + SELECT generate_series(-1.0, 1.0, 0.1) + UNION ALL + SELECT generate_series(2, 10) + UNION ALL + SELECT 'Infinity'::float8 + UNION ALL + SELECT 'NaN'::float8) AS t(x); + x | degrees_atan | atand +-----------+--------------+-------------- + -Infinity | -90 | -90 + -10 | -84.28940686 | -84.28940686 + -9 | -83.65980825 | -83.65980825 + -8 | -82.87498365 | -82.87498365 + -7 | -81.86989765 | -81.86989765 + -6 | -80.53767779 | -80.53767779 + -5 | -78.69006753 | -78.69006753 + -4 | -75.96375653 | -75.96375653 + -3 | -71.56505118 | -71.56505118 + -2 | -63.43494882 | -63.43494882 + -1 | -45 | -45 + -0.9 | -41.9872125 | -41.9872125 + -0.8 | -38.65980825 | -38.65980825 + -0.7 | -34.9920202 | -34.9920202 + -0.6 | -30.96375653 | -30.96375653 + -0.5 | -26.56505118 | -26.56505118 + -0.4 | -21.80140949 | -21.80140949 + -0.3 | -16.69924423 | -16.69924423 + -0.2 | -11.30993247 | -11.30993247 + -0.1 | -5.710593137 | -5.710593137 + 0 | 0 | 0 + 0.1 | 5.710593137 | 5.710593137 + 0.2 | 11.30993247 | 11.30993247 + 0.3 | 16.69924423 | 16.69924423 + 0.4 | 21.80140949 | 21.80140949 + 0.5 | 26.56505118 | 26.56505118 + 0.6 | 30.96375653 | 30.96375653 + 0.7 | 34.9920202 | 34.9920202 + 0.8 | 38.65980825 | 38.65980825 + 0.9 | 41.9872125 | 41.9872125 + 1 | 45 | 45 + 2 | 63.43494882 | 63.43494882 + 3 | 71.56505118 | 71.56505118 + 4 | 75.96375653 | 75.96375653 + 5 | 78.69006753 | 78.69006753 + 6 | 80.53767779 | 80.53767779 + 7 | 81.86989765 | 81.86989765 + 8 | 82.87498365 | 82.87498365 + 9 | 83.65980825 | 83.65980825 + 10 | 84.28940686 | 84.28940686 + Infinity | 90 | 90 + NaN | NaN | NaN +(42 rows) + +-- 4 quadrant arctangent +SELECT x, y, degrees(atan2(y, x)) AS degrees_atan2, atan2d(y, x) +FROM (SELECT 10*cosd(a), 10*sind(a) + FROM generate_series(0, 360, 10) AS t(a)) AS t(x,y); + x | y | degrees_atan2 | atan2d +--------------+--------------+---------------+-------- + 10 | 0 | 0 | 0 + 9.84807753 | 1.736481777 | 10 | 10 + 9.396926208 | 3.420201433 | 20 | 20 + 8.660254038 | 5 | 30 | 30 + 7.660444431 | 6.427876097 | 40 | 40 + 6.427876097 | 7.660444431 | 50 | 50 + 5 | 8.660254038 | 60 | 60 + 3.420201433 | 9.396926208 | 70 | 70 + 1.736481777 | 9.84807753 | 80 | 80 + 0 | 10 | 90 | 90 + -1.736481777 | 9.84807753 | 100 | 100 + -3.420201433 | 9.396926208 | 110 | 110 + -5 | 8.660254038 | 120 | 120 + -6.427876097 | 7.660444431 | 130 | 130 + -7.660444431 | 6.427876097 | 140 | 140 + -8.660254038 | 5 | 150 | 150 + -9.396926208 | 3.420201433 | 160 | 160 + -9.84807753 | 1.736481777 | 170 | 170 + -10 | 0 | 180 | 180 + -9.84807753 | -1.736481777 | -170 | -170 + -9.396926208 | -3.420201433 | -160 | -160 + -8.660254038 | -5 | -150 | -150 + -7.660444431 | -6.427876097 | -140 | -140 + -6.427876097 | -7.660444431 | -130 | -130 + -5 | -8.660254038 | -120 | -120 + -3.420201433 | -9.396926208 | -110 | -110 + -1.736481777 | -9.84807753 | -100 | -100 + 0 | -10 | -90 | -90 + 1.736481777 | -9.84807753 | -80 | -80 + 3.420201433 | -9.396926208 | -70 | -70 + 5 | -8.660254038 | -60 | -60 + 6.427876097 | -7.660444431 | -50 | -50 + 7.660444431 | -6.427876097 | -40 | -40 + 8.660254038 | -5 | -30 | -30 + 9.396926208 | -3.420201433 | -20 | -20 + 9.84807753 | -1.736481777 | -10 | -10 + 10 | 0 | 0 | 0 +(37 rows) + diff --git a/src/test/regress/sql/float8.sql b/src/test/regress/sql/float8.sql new file mode 100644 index 92a574a..49363d0 --- a/src/test/regress/sql/float8.sql +++ b/src/test/regress/sql/float8.sql @@ -167,3 +167,58 @@ INSERT INTO FLOAT8_TBL(f1) VALUES ('-1.2 INSERT INTO FLOAT8_TBL(f1) VALUES ('-1.2345678901234e-200'); SELECT '' AS five, * FROM FLOAT8_TBL; + +-- Test the trigonometric functions. +-- Use a lower precision to eliminate variations between platforms. +SET extra_float_digits TO -5; + +-- sine and cosine +SELECT x, + sin(radians(x)) AS sin_radians, sind(x), + cos(radians(x)) AS cos_radians, cosd(x) +FROM generate_series(-360, 360, 10) AS t(x) +WHERE x = 0 OR x % 90 != 0; -- skip tests that are very platform-dependent + +-- test exactness +SELECT x, + CASE WHEN sind(x) IN (-1,-0.5,0,0.5,1) THEN sind(x) END AS sind, + CASE WHEN cosd(x) IN (-1,-0.5,0,0.5,1) THEN cosd(x) END AS cosd +FROM generate_series(0, 360, 30) AS t(x); + +-- tangent and cotangent +SELECT x, + tan(radians(x)) AS tan_radians, tand(x), + cot(radians(x)) AS cot_radians, cotd(x) +FROM generate_series(-360, 360, 10) AS t(x) +WHERE x = 0 OR x % 90 != 0; -- skip tests that are very platform-dependent + +-- test exactness +SELECT x, + CASE WHEN tand(x) IN (-1,0,1) THEN tand(x) END AS tand, + CASE WHEN cotd(x) IN (-1,0,1) THEN cotd(x) END AS cotd +FROM generate_series(0, 360, 45) AS t(x); + +-- arcsine and arccosine +SELECT x, + degrees(asin(x)) AS degrees_asin, asind(x), + degrees(acos(x)) AS degrees_acos, acosd(x) +FROM generate_series(-1.0, 1.0, 0.1) AS t(x); + +-- arctangent +SELECT x, degrees(atan(x)) AS degrees_atan, atand(x) +FROM (SELECT '-Infinity'::float8 + UNION ALL + SELECT generate_series(-10, -2) + UNION ALL + SELECT generate_series(-1.0, 1.0, 0.1) + UNION ALL + SELECT generate_series(2, 10) + UNION ALL + SELECT 'Infinity'::float8 + UNION ALL + SELECT 'NaN'::float8) AS t(x); + +-- 4 quadrant arctangent +SELECT x, y, degrees(atan2(y, x)) AS degrees_atan2, atan2d(y, x) +FROM (SELECT 10*cosd(a), 10*sind(a) + FROM generate_series(0, 360, 10) AS t(a)) AS t(x,y);