Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit82311bc

Browse files
committed
Yet more portability hacking for degree-based trig functions.
The true explanation for Peter Eisentraut's report of inexact asind resultsseems to be that (a) he's compiling into x87 instruction set, which useswider-than-double float registers, plus (b) the library function asin() onhis platform returns a result that is wider than double and is not roundedto double width. To fix, we have to force the function's result to berounded comparably to what happened to the scaling constant asin_0_5.Experimentation suggests that storing it into a volatile local variable isthe least ugly way of making that happen. Although only asin() is known toexhibit an observable inexact result, we'd better do this in all the placeswhere we're hoping to get an exact result by scaling.
1 parent77cd477 commit82311bc

File tree

1 file changed

+54
-10
lines changed

1 file changed

+54
-10
lines changed

‎src/backend/utils/adt/float.c

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
18341847
staticvoid
18351848
init_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+
volatilefloat8asin_x=asin(x);
1888+
1889+
return (asin_x /asin_0_5)*30.0;
1890+
}
18741891
else
1875-
return90.0- (acos(x) /acos_0_5)*60.0;
1892+
{
1893+
volatilefloat8acos_x=acos(x);
1894+
1895+
return90.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-
return90.0- (asin(x) /asin_0_5)*30.0;
1919+
{
1920+
volatilefloat8asin_x=asin(x);
1921+
1922+
return90.0- (asin_x /asin_0_5)*30.0;
1923+
}
18991924
else
1900-
return (acos(x) /acos_0_5)*60.0;
1925+
{
1926+
volatilefloat8acos_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
float8arg1=PG_GETARG_FLOAT8(0);
19812010
float8result;
2011+
volatilefloat8atan_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
float8arg1=PG_GETARG_FLOAT8(0);
20092040
float8arg2=PG_GETARG_FLOAT8(1);
20102041
float8result;
2042+
volatilefloat8atan2_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)
20342072
staticdouble
20352073
sind_0_to_30(doublex)
20362074
{
2037-
return (sin(x*RADIANS_PER_DEGREE) /sin_30) /2.0;
2075+
volatilefloat8sin_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)
20462086
staticdouble
20472087
cosd_0_to_60(doublex)
20482088
{
2049-
float8one_minus_cos_x=1.0-cos(x*RADIANS_PER_DEGREE);
2089+
volatilefloat8one_minus_cos_x=1.0-cos(x*RADIANS_PER_DEGREE);
20502090

20512091
return1.0- (one_minus_cos_x /one_minus_cos_60) /2.0;
20522092
}
@@ -2153,6 +2193,7 @@ dcotd(PG_FUNCTION_ARGS)
21532193
{
21542194
float8arg1=PG_GETARG_FLOAT8(0);
21552195
float8result;
2196+
volatilefloat8cot_arg1;
21562197
intsign=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
float8arg1=PG_GETARG_FLOAT8(0);
22722314
float8result;
2315+
volatilefloat8tan_arg1;
22732316
intsign=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

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp