C23 added the sinpi, cospi, etc. functions. Therefore, MPFR in 4.2.0
added the mpfr_ counter parts. I assume that those internally use the
mpfr_sinu, mpfr_cosu, ... functions, which are also user accessible.
In any case, MPFR makes the ...u functions available and explicitly
documents that for u = 360, the mpfr_...u functions permits to use
angles in degree instead of rad.
Fortran 2023 added degree trigonometric functions, which gfortran already
supports. Thus:
The attach patch switches to the mpfr_...u functions for the degree
variant if MPFR 4.2.0, but keeps the fallback for older MPFR versions.
[Currently, GCC requires MPFR 3.1 or newer for build. (MPFR 4.2.0 was
releasedJanuary 2023.) We already did likewise in the past: Making
conditionally use of newer MPFR functions, if available, but have a
fallback until the minimal MPFR version is increased. (The last such
code was removed 2008 as then MPFR >= 3.1.0 was the new minimal
version and all of MPFR is currently used unconditionally.)]
Bootstrapped and regtested on x86_64-gnu-linux with MPFR 4.2.2 (the latest).
OK for mainline?
Tobias
PS: I see gfortran.dg/specifics_1.f90 fails for -O2 and higher, but not
due to this patch → https://gcc.gnu.org/PR120099 (opened on Apr 2025)
Fortran: Use mpfr_sinu etc. with mpfr 4.2.0+ for degree trigonometric functions [PR120225]
As MPFR 4.2.0 added, support for degree trigonometric functions by via the
mpfr_...u functions (for u = 360), it makes sense to use them if available.
If MPFR is older, the current implementation is used as fallback.
PR fortran/120225
gcc/fortran/ChangeLog:
* simplify.cc Include "trigd_fe.inc" only with MPFR < 4.2.0
(rad2deg, rad2deg): Only define if MPFR < 4.2.0.
(gfc_simplify_acosd, gfc_simplify_asind, gfc_simplify_atand,
gfc_simplify_atan2d, gfc_simplify_cosd, gfc_simplify_tand,
gfc_simplify_cotand): Use mpfr_...u functions with MPFR >= 4.2.0.
gcc/fortran/simplify.cc | 41 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 208251b5ec5..79701be839d 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -1183,6 +1183,7 @@ gfc_simplify_asin (gfc_expr *x)
}
+#if MPFR_VERSION < MPFR_VERSION_NUM(4,2,0)
/* Convert radians to degrees, i.e., x * 180 / pi. */
static void
@@ -1196,6 +1197,7 @@ rad2deg (mpfr_t x)
mpfr_div (x, x, tmp, GFC_RND_MODE);
mpfr_clear (tmp);
}
+#endif
/* Simplify ACOSD(X) where the returned value has units of degree. */
@@ -1217,8 +1219,12 @@ gfc_simplify_acosd (gfc_expr *x)
}
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_acosu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_acos (result->value.real, x->value.real, GFC_RND_MODE);
rad2deg (result->value.real);
+#endif
return range_check (result, "ACOSD");
}
@@ -1243,8 +1249,12 @@ gfc_simplify_asind (gfc_expr *x)
}
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_asinu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_asin (result->value.real, x->value.real, GFC_RND_MODE);
rad2deg (result->value.real);
+#endif
return range_check (result, "ASIND");
}
@@ -1261,8 +1271,12 @@ gfc_simplify_atand (gfc_expr *x)
return NULL;
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_atanu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_atan (result->value.real, x->value.real, GFC_RND_MODE);
rad2deg (result->value.real);
+#endif
return range_check (result, "ATAND");
}
@@ -1954,8 +1968,13 @@ gfc_simplify_atan2d (gfc_expr *y, gfc_expr *x)
}
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_atan2u (result->value.real, y->value.real, x->value.real, 360,
+ GFC_RND_MODE);
+#else
mpfr_atan2 (result->value.real, y->value.real, x->value.real, GFC_RND_MODE);
rad2deg (result->value.real);
+#endif
return range_check (result, "ATAN2D");
}
@@ -1990,6 +2009,8 @@ gfc_simplify_cos (gfc_expr *x)
}
+#if MPFR_VERSION < MPFR_VERSION_NUM(4,2,0)
+/* Used by trigd_fe.inc. */
static void
deg2rad (mpfr_t x)
{
@@ -2001,11 +2022,13 @@ deg2rad (mpfr_t x)
mpfr_mul (x, x, d2r, GFC_RND_MODE);
mpfr_clear (d2r);
}
+#endif
+#if MPFR_VERSION < MPFR_VERSION_NUM(4,2,0)
/* Simplification routines for SIND, COSD, TAND. */
#include "trigd_fe.inc"
-
+#endif
/* Simplify COSD(X) where X has the unit of degree. */
@@ -2018,8 +2041,12 @@ gfc_simplify_cosd (gfc_expr *x)
return NULL;
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_cosu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_set (result->value.real, x->value.real, GFC_RND_MODE);
simplify_cosd (result->value.real);
+#endif
return range_check (result, "COSD");
}
@@ -2036,8 +2063,12 @@ gfc_simplify_sind (gfc_expr *x)
return NULL;
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_sinu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_set (result->value.real, x->value.real, GFC_RND_MODE);
simplify_sind (result->value.real);
+#endif
return range_check (result, "SIND");
}
@@ -2054,8 +2085,12 @@ gfc_simplify_tand (gfc_expr *x)
return NULL;
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_tanu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
mpfr_set (result->value.real, x->value.real, GFC_RND_MODE);
simplify_tand (result->value.real);
+#endif
return range_check (result, "TAND");
}
@@ -2078,7 +2113,11 @@ gfc_simplify_cotand (gfc_expr *x)
result = gfc_get_constant_expr (x->ts.type, x->ts.kind, &x->where);
mpfr_set (result->value.real, x->value.real, GFC_RND_MODE);
mpfr_add_ui (result->value.real, result->value.real, 90, GFC_RND_MODE);
+#if MPFR_VERSION >= MPFR_VERSION_NUM(4,2,0)
+ mpfr_tanu (result->value.real, x->value.real, 360, GFC_RND_MODE);
+#else
simplify_tand (result->value.real);
+#endif
mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE);
return range_check (result, "COTAND");