Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees. - Mailing list pgsql-hackers

From Tom Lane
Subject Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees.
Date
Msg-id 12552.1461611379@sss.pgh.pa.us
Whole thread Raw
In response to Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees.  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: [COMMITTERS] pgsql: Add trigonometric functions that work in degrees.  (Peter Eisentraut <peter_e@gmx.net>)
List pgsql-hackers
I wrote:
> If that is the answer, then the next question is how we can put more
> roadblocks in the way of compile-time evaluation of asin(0.5).  Dean
> suggested that creative use of "volatile" might do it, and I agree
> that that sounds like a promising thing to pursue.

It occurred to me that we don't actually need "volatile".  What we need
is a variable that the compiler is not allowed to assume is a compile-time
constant, and a plain global variable is sufficient for that.  In the
attached patch, we no longer need an assumption that init_degree_constants
doesn't get inlined; we only need to assume that the compiler can't prove
the variables degree_c_thirty etc to be immutable.  Which it cannot, even
if it does global optimization across the whole PG executable, because it
has to consider that loadable extensions might change them.

I'm going to go ahead and push this, because it seems clearly more robust
than what we have.  But I'd appreciate a report on whether it fixes your
issue.

            regards, tom lane

diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index c7c0b58..a95ebe5 100644
*** a/src/backend/utils/adt/float.c
--- b/src/backend/utils/adt/float.c
*************** static float8 atan_1_0 = 0;
*** 77,91 ****
  static float8 tan_45 = 0;
  static float8 cot_45 = 0;

  /* Local function prototypes */
  static int    float4_cmp_internal(float4 a, float4 b);
  static int    float8_cmp_internal(float8 a, float8 b);
  static double sind_q1(double x);
  static double cosd_q1(double x);
!
! /* This is INTENTIONALLY NOT STATIC.  Don't "fix" it. */
! void init_degree_constants(float8 thirty, float8 forty_five, float8 sixty,
!                       float8 one_half, float8 one);

  #ifndef HAVE_CBRT
  /*
--- 77,100 ----
  static float8 tan_45 = 0;
  static float8 cot_45 = 0;

+ /*
+  * These are intentionally not static; don't "fix" them.  They will never
+  * be referenced by other files, much less changed; but we don't want the
+  * compiler to know that, else it might try to precompute expressions
+  * involving them.  See comments for init_degree_constants().
+  */
+ float8        degree_c_thirty = 30.0;
+ float8        degree_c_forty_five = 45.0;
+ float8        degree_c_sixty = 60.0;
+ float8        degree_c_one_half = 0.5;
+ float8        degree_c_one = 1.0;
+
  /* Local function prototypes */
  static int    float4_cmp_internal(float4 a, float4 b);
  static int    float8_cmp_internal(float8 a, float8 b);
  static double sind_q1(double x);
  static double cosd_q1(double x);
! static void init_degree_constants(void);

  #ifndef HAVE_CBRT
  /*
*************** dtan(PG_FUNCTION_ARGS)
*** 1814,1848 ****
   * compilers out there that will precompute expressions such as sin(constant)
   * using a sin() function different from what will be used at runtime.  If we
   * want exact results, we must ensure that none of the scaling constants used
!  * in the degree-based trig functions are computed that way.
!  *
!  * The whole approach fails if init_degree_constants() gets inlined into the
!  * call sites, since then constant-folding can happen anyway.  Currently it
!  * seems sufficient to declare it non-static to prevent that.  We have no
!  * expectation that other files will call this, but don't tell gcc that.
   *
   * Other hazards we are trying to forestall with this kluge include the
   * possibility that compilers will rearrange the expressions, or compute
   * some intermediate results in registers wider than a standard double.
   */
! void
! init_degree_constants(float8 thirty, float8 forty_five, float8 sixty,
!                       float8 one_half, float8 one)
  {
!     sin_30 = sin(thirty * RADIANS_PER_DEGREE);
!     one_minus_cos_60 = 1.0 - cos(sixty * RADIANS_PER_DEGREE);
!     asin_0_5 = asin(one_half);
!     acos_0_5 = acos(one_half);
!     atan_1_0 = atan(one);
!     tan_45 = sind_q1(forty_five) / cosd_q1(forty_five);
!     cot_45 = cosd_q1(forty_five) / sind_q1(forty_five);
      degree_consts_set = true;
  }

  #define INIT_DEGREE_CONSTANTS() \
  do { \
      if (!degree_consts_set) \
!         init_degree_constants(30.0, 45.0, 60.0, 0.5, 1.0); \
  } while(0)


--- 1823,1853 ----
   * compilers out there that will precompute expressions such as sin(constant)
   * using a sin() function different from what will be used at runtime.  If we
   * want exact results, we must ensure that none of the scaling constants used
!  * in the degree-based trig functions are computed that way.  To do so, we
!  * compute them from the variables degree_c_thirty etc, which are also really
!  * constants, but the compiler cannot assume that.
   *
   * Other hazards we are trying to forestall with this kluge include the
   * possibility that compilers will rearrange the expressions, or compute
   * some intermediate results in registers wider than a standard double.
   */
! static void
! init_degree_constants(void)
  {
!     sin_30 = sin(degree_c_thirty * RADIANS_PER_DEGREE);
!     one_minus_cos_60 = 1.0 - cos(degree_c_sixty * RADIANS_PER_DEGREE);
!     asin_0_5 = asin(degree_c_one_half);
!     acos_0_5 = acos(degree_c_one_half);
!     atan_1_0 = atan(degree_c_one);
!     tan_45 = sind_q1(degree_c_forty_five) / cosd_q1(degree_c_forty_five);
!     cot_45 = cosd_q1(degree_c_forty_five) / sind_q1(degree_c_forty_five);
      degree_consts_set = true;
  }

  #define INIT_DEGREE_CONSTANTS() \
  do { \
      if (!degree_consts_set) \
!         init_degree_constants(); \
  } while(0)



pgsql-hackers by date:

Previous
From: "Guo, Yun"
Date:
Subject: how to measure pglogical replication lag
Next
From: Andrew Dunstan
Date:
Subject: Re: [COMMITTERS] pgsql: Add putenv support for msvcrt from Visual Studio 2013