@@ -1830,6 +1830,19 @@ dtan(PG_FUNCTION_ARGS)
1830
1830
* Other hazards we are trying to forestall with this kluge include the
1831
1831
* possibility that compilers will rearrange the expressions, or compute
1832
1832
* 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.)
1833
1846
*/
1834
1847
static void
1835
1848
init_degree_constants (void )
@@ -1870,9 +1883,17 @@ asind_q1(double x)
1870
1883
* over the full range.
1871
1884
*/
1872
1885
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
+ }
1874
1891
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
+ }
1876
1897
}
1877
1898
1878
1899
@@ -1895,9 +1916,17 @@ acosd_q1(double x)
1895
1916
* over the full range.
1896
1917
*/
1897
1918
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
+ }
1899
1924
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
+ }
1901
1930
}
1902
1931
1903
1932
@@ -1979,6 +2008,7 @@ datand(PG_FUNCTION_ARGS)
1979
2008
{
1980
2009
float8 arg1 = PG_GETARG_FLOAT8 (0 );
1981
2010
float8 result ;
2011
+ volatile float8 atan_arg1 ;
1982
2012
1983
2013
/* Per the POSIX spec, return NaN if the input is NaN */
1984
2014
if (isnan (arg1 ))
@@ -1992,7 +2022,8 @@ datand(PG_FUNCTION_ARGS)
1992
2022
* even if the input is infinite. Additionally, we take care to ensure
1993
2023
* than when arg1 is 1, the result is exactly 45.
1994
2024
*/
1995
- result = (atan (arg1 ) / atan_1_0 ) * 45.0 ;
2025
+ atan_arg1 = atan (arg1 );
2026
+ result = (atan_arg1 / atan_1_0 ) * 45.0 ;
1996
2027
1997
2028
CHECKFLOATVAL (result , false, true);
1998
2029
PG_RETURN_FLOAT8 (result );
@@ -2008,6 +2039,7 @@ datan2d(PG_FUNCTION_ARGS)
2008
2039
float8 arg1 = PG_GETARG_FLOAT8 (0 );
2009
2040
float8 arg2 = PG_GETARG_FLOAT8 (1 );
2010
2041
float8 result ;
2042
+ volatile float8 atan2_arg1_arg2 ;
2011
2043
2012
2044
/* Per the POSIX spec, return NaN if either input is NaN */
2013
2045
if (isnan (arg1 ) || isnan (arg2 ))
@@ -2018,8 +2050,14 @@ datan2d(PG_FUNCTION_ARGS)
2018
2050
/*
2019
2051
* atan2d maps all inputs to values in the range [-180, 180], so the
2020
2052
* 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.
2021
2058
*/
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 ;
2023
2061
2024
2062
CHECKFLOATVAL (result , false, true);
2025
2063
PG_RETURN_FLOAT8 (result );
@@ -2034,7 +2072,9 @@ datan2d(PG_FUNCTION_ARGS)
2034
2072
static double
2035
2073
sind_0_to_30 (double x )
2036
2074
{
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 ;
2038
2078
}
2039
2079
2040
2080
@@ -2046,7 +2086,7 @@ sind_0_to_30(double x)
2046
2086
static double
2047
2087
cosd_0_to_60 (double x )
2048
2088
{
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 );
2050
2090
2051
2091
return 1.0 - (one_minus_cos_x / one_minus_cos_60 ) / 2.0 ;
2052
2092
}
@@ -2153,6 +2193,7 @@ dcotd(PG_FUNCTION_ARGS)
2153
2193
{
2154
2194
float8 arg1 = PG_GETARG_FLOAT8 (0 );
2155
2195
float8 result ;
2196
+ volatile float8 cot_arg1 ;
2156
2197
int sign = 1 ;
2157
2198
2158
2199
/*
@@ -2193,7 +2234,8 @@ dcotd(PG_FUNCTION_ARGS)
2193
2234
sign = - sign ;
2194
2235
}
2195
2236
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 );
2197
2239
2198
2240
/*
2199
2241
* On some machines we get cotd(270) = minus zero, but this isn't always
@@ -2270,6 +2312,7 @@ dtand(PG_FUNCTION_ARGS)
2270
2312
{
2271
2313
float8 arg1 = PG_GETARG_FLOAT8 (0 );
2272
2314
float8 result ;
2315
+ volatile float8 tan_arg1 ;
2273
2316
int sign = 1 ;
2274
2317
2275
2318
/*
@@ -2310,7 +2353,8 @@ dtand(PG_FUNCTION_ARGS)
2310
2353
sign = - sign ;
2311
2354
}
2312
2355
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 );
2314
2358
2315
2359
/*
2316
2360
* On some machines we get tand(180) = minus zero, but this isn't always
0 commit comments