@@ -1830,6 +1830,19 @@ dtan(PG_FUNCTION_ARGS)
18301830 * Other hazards we are trying to forestall with this kluge include the
18311831 * possibility that compilers will rearrange the expressions, or compute
18321832 * some intermediate results in registers wider than a standard double.
1833+ *
1834+ * In the places where we use these constants, the typical pattern is like
1835+ *volatile float8 sin_x = sin(x * RADIANS_PER_DEGREE);
1836+ *return (sin_x / sin_30);
1837+ * where we hope to get a value of exactly 1.0 from the division when x = 30.
1838+ * The volatile temporary variable is needed on machines with wide float
1839+ * registers, to ensure that the result of sin(x) is rounded to double width
1840+ * the same as the value of sin_30 has been. Experimentation with gcc shows
1841+ * that marking the temp variable volatile is necessary to make the store and
1842+ * reload actually happen; hopefully the same trick works for other compilers.
1843+ * (gcc's documentation suggests using the -ffloat-store compiler switch to
1844+ * ensure this, but that is compiler-specific and it also pessimizes code in
1845+ * many places where we don't care about this.)
18331846 */
18341847static void
18351848init_degree_constants (void )
@@ -1870,9 +1883,17 @@ asind_q1(double x)
18701883 * over the full range.
18711884 */
18721885if (x <=0.5 )
1873- return (asin (x ) /asin_0_5 )* 30.0 ;
1886+ {
1887+ volatile float8 asin_x = asin (x );
1888+
1889+ return (asin_x /asin_0_5 )* 30.0 ;
1890+ }
18741891else
1875- return 90.0 - (acos (x ) /acos_0_5 )* 60.0 ;
1892+ {
1893+ volatile float8 acos_x = acos (x );
1894+
1895+ return 90.0 - (acos_x /acos_0_5 )* 60.0 ;
1896+ }
18761897}
18771898
18781899
@@ -1895,9 +1916,17 @@ acosd_q1(double x)
18951916 * over the full range.
18961917 */
18971918if (x <=0.5 )
1898- return 90.0 - (asin (x ) /asin_0_5 )* 30.0 ;
1919+ {
1920+ volatile float8 asin_x = asin (x );
1921+
1922+ return 90.0 - (asin_x /asin_0_5 )* 30.0 ;
1923+ }
18991924else
1900- return (acos (x ) /acos_0_5 )* 60.0 ;
1925+ {
1926+ volatile float8 acos_x = acos (x );
1927+
1928+ return (acos_x /acos_0_5 )* 60.0 ;
1929+ }
19011930}
19021931
19031932
@@ -1979,6 +2008,7 @@ datand(PG_FUNCTION_ARGS)
19792008{
19802009float8 arg1 = PG_GETARG_FLOAT8 (0 );
19812010float8 result ;
2011+ volatile float8 atan_arg1 ;
19822012
19832013/* Per the POSIX spec, return NaN if the input is NaN */
19842014if (isnan (arg1 ))
@@ -1992,7 +2022,8 @@ datand(PG_FUNCTION_ARGS)
19922022 * even if the input is infinite. Additionally, we take care to ensure
19932023 * than when arg1 is 1, the result is exactly 45.
19942024 */
1995- result = (atan (arg1 ) /atan_1_0 )* 45.0 ;
2025+ atan_arg1 = atan (arg1 );
2026+ result = (atan_arg1 /atan_1_0 )* 45.0 ;
19962027
19972028CHECKFLOATVAL (result , false, true);
19982029PG_RETURN_FLOAT8 (result );
@@ -2008,6 +2039,7 @@ datan2d(PG_FUNCTION_ARGS)
20082039float8 arg1 = PG_GETARG_FLOAT8 (0 );
20092040float8 arg2 = PG_GETARG_FLOAT8 (1 );
20102041float8 result ;
2042+ volatile float8 atan2_arg1_arg2 ;
20112043
20122044/* Per the POSIX spec, return NaN if either input is NaN */
20132045if (isnan (arg1 )|| isnan (arg2 ))
@@ -2018,8 +2050,14 @@ datan2d(PG_FUNCTION_ARGS)
20182050/*
20192051 * atan2d maps all inputs to values in the range [-180, 180], so the
20202052 * result should always be finite, even if the inputs are infinite.
2053+ *
2054+ * Note: this coding assumes that atan(1.0) is a suitable scaling constant
2055+ * to get an exact result from atan2(). This might well fail on us at
2056+ * some point, requiring us to decide exactly what inputs we think we're
2057+ * going to guarantee an exact result for.
20212058 */
2022- result = (atan2 (arg1 ,arg2 ) /atan_1_0 )* 45.0 ;
2059+ atan2_arg1_arg2 = atan2 (arg1 ,arg2 );
2060+ result = (atan2_arg1_arg2 /atan_1_0 )* 45.0 ;
20232061
20242062CHECKFLOATVAL (result , false, true);
20252063PG_RETURN_FLOAT8 (result );
@@ -2034,7 +2072,9 @@ datan2d(PG_FUNCTION_ARGS)
20342072static double
20352073sind_0_to_30 (double x )
20362074{
2037- return (sin (x * RADIANS_PER_DEGREE ) /sin_30 ) /2.0 ;
2075+ volatile float8 sin_x = sin (x * RADIANS_PER_DEGREE );
2076+
2077+ return (sin_x /sin_30 ) /2.0 ;
20382078}
20392079
20402080
@@ -2046,7 +2086,7 @@ sind_0_to_30(double x)
20462086static double
20472087cosd_0_to_60 (double x )
20482088{
2049- float8 one_minus_cos_x = 1.0 - cos (x * RADIANS_PER_DEGREE );
2089+ volatile float8 one_minus_cos_x = 1.0 - cos (x * RADIANS_PER_DEGREE );
20502090
20512091return 1.0 - (one_minus_cos_x /one_minus_cos_60 ) /2.0 ;
20522092}
@@ -2153,6 +2193,7 @@ dcotd(PG_FUNCTION_ARGS)
21532193{
21542194float8 arg1 = PG_GETARG_FLOAT8 (0 );
21552195float8 result ;
2196+ volatile float8 cot_arg1 ;
21562197int sign = 1 ;
21572198
21582199/*
@@ -2193,7 +2234,8 @@ dcotd(PG_FUNCTION_ARGS)
21932234sign = - sign ;
21942235}
21952236
2196- result = sign * ((cosd_q1 (arg1 ) /sind_q1 (arg1 )) /cot_45 );
2237+ cot_arg1 = cosd_q1 (arg1 ) /sind_q1 (arg1 );
2238+ result = sign * (cot_arg1 /cot_45 );
21972239
21982240/*
21992241 * On some machines we get cotd(270) = minus zero, but this isn't always
@@ -2270,6 +2312,7 @@ dtand(PG_FUNCTION_ARGS)
22702312{
22712313float8 arg1 = PG_GETARG_FLOAT8 (0 );
22722314float8 result ;
2315+ volatile float8 tan_arg1 ;
22732316int sign = 1 ;
22742317
22752318/*
@@ -2310,7 +2353,8 @@ dtand(PG_FUNCTION_ARGS)
23102353sign = - sign ;
23112354}
23122355
2313- result = sign * ((sind_q1 (arg1 ) /cosd_q1 (arg1 )) /tan_45 );
2356+ tan_arg1 = sind_q1 (arg1 ) /cosd_q1 (arg1 );
2357+ result = sign * (tan_arg1 /tan_45 );
23142358
23152359/*
23162360 * On some machines we get tand(180) = minus zero, but this isn't always