@@ -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 */
18721885 if (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+ }
18741891 else
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 */
18971918 if (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+ }
18991924 else
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{
19802009 float8 arg1 = PG_GETARG_FLOAT8 (0 );
19812010 float8 result ;
2011+ volatile float8 atan_arg1 ;
19822012
19832013 /* Per the POSIX spec, return NaN if the input is NaN */
19842014 if (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
19972028 CHECKFLOATVAL (result , false, true);
19982029 PG_RETURN_FLOAT8 (result );
@@ -2008,6 +2039,7 @@ datan2d(PG_FUNCTION_ARGS)
20082039 float8 arg1 = PG_GETARG_FLOAT8 (0 );
20092040 float8 arg2 = PG_GETARG_FLOAT8 (1 );
20102041 float8 result ;
2042+ volatile float8 atan2_arg1_arg2 ;
20112043
20122044 /* Per the POSIX spec, return NaN if either input is NaN */
20132045 if (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
20242062 CHECKFLOATVAL (result , false, true);
20252063 PG_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
20512091 return 1.0 - (one_minus_cos_x / one_minus_cos_60 ) / 2.0 ;
20522092}
@@ -2153,6 +2193,7 @@ dcotd(PG_FUNCTION_ARGS)
21532193{
21542194 float8 arg1 = PG_GETARG_FLOAT8 (0 );
21552195 float8 result ;
2196+ volatile float8 cot_arg1 ;
21562197 int sign = 1 ;
21572198
21582199 /*
@@ -2193,7 +2234,8 @@ dcotd(PG_FUNCTION_ARGS)
21932234 sign = - 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{
22712313 float8 arg1 = PG_GETARG_FLOAT8 (0 );
22722314 float8 result ;
2315+ volatile float8 tan_arg1 ;
22732316 int sign = 1 ;
22742317
22752318 /*
@@ -2310,7 +2353,8 @@ dtand(PG_FUNCTION_ARGS)
23102353 sign = - 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
0 commit comments