This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
| Other format: | [Raw text] | |
This patch concerned the accuracy of results obtained with MOD(arg1, arg2) and MODULO(arg1, arg2) at large values of the ratio of arg1 to arg2; these were drifting off and exceeding the absolute value of arg2 for relatively small values of the ratio. For example:
real*8 :: x = 10.0e9 do i = 10, 22 x = 10d0 * x print '(a,i2,a,g14.8)', "mod (10**",i,", 1.7_8) = ",mod (x, 1.7_8) end do end
mod (10**10, 1.7_8) = 1.3000026 mod (10**11, 1.7_8) = 1.1000261 mod (10**12, 1.7_8) = 0.80026150 mod (10**13, 1.7_8) = 1.2026138 mod (10**14, 1.7_8) = 0.12609863 mod (10**15, 1.7_8) = 1.2607422 mod (10**16, 1.7_8) = 5.8125000 mod (10**17, 1.7_8) = -50.687500 mod (10**18, 1.7_8) = 364.00000 mod (10**19, 1.7_8) = -.70000000E+20 mod (10**20, 1.7_8) = -.70000000E+21 mod (10**21, 1.7_8) = -.70000000E+22 mod (10**22, 1.7_8) = -.70000000E+23
mod (10**10, 1.7_8) = 1.3000026 mod (10**11, 1.7_8) = 1.1000261 mod (10**12, 1.7_8) = 0.80026123 mod (10**13, 1.7_8) = 1.2026123 mod (10**14, 1.7_8) = 0.12612289 mod (10**15, 1.7_8) = 1.2612289 mod (10**16, 1.7_8) = 0.71228947 mod (10**17, 1.7_8) = 0.32289470 mod (10**18, 1.7_8) = 1.5289470 mod (10**19, 1.7_8) = 1.6894697 mod (10**20, 1.7_8) = 1.5946971 mod (10**21, 1.7_8) = 0.64697063 mod (10**22, 1.7_8) = 0.86970625
The patch is self explanatory, including the calculation of modulo. This latter is a bit contorted in order to avoid any further divisions; this is rewarded by the computation time only being 30% more than that for mod.
We have not included a testcase because anything useful would fail on platforms without the fmod built_in. If none such exist, we would be happy to provide a testcase!
We would like to acknowledge Uros Bizjak for his work in ensuring that the library can provide the goods for any compiler option. Thanks Uros!
2006-10-31 Francois-Xavier Coudert <fxcoudert@gcc.gnu,org> Paul Thomas <pault@gcc.gnu.org>
PR fortran/24518 * trans-intrinsic.c (gfc_conv_intrinsic_mod): Use built_in fmod for both MOD and MODULO, if it is available.
Index: gcc/fortran/f95-lang.c
===================================================================
*** gcc/fortran/f95-lang.c (révision 118179)
--- gcc/fortran/f95-lang.c (copie de travail)
*************** gfc_init_builtin_functions (void)
*** 896,901 ****
--- 896,908 ----
BUILT_IN_COPYSIGN, "copysign", true);
gfc_define_builtin ("__builtin_copysignf", mfunc_float[1],
BUILT_IN_COPYSIGNF, "copysignf", true);
+
+ gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1],
+ BUILT_IN_FMODL, "fmodl", true);
+ gfc_define_builtin ("__builtin_fmod", mfunc_double[1],
+ BUILT_IN_FMOD, "fmod", true);
+ gfc_define_builtin ("__builtin_fmodf", mfunc_float[1],
+ BUILT_IN_FMODF, "fmodf", true);
/* These are used to implement the ** operator. */
gfc_define_builtin ("__builtin_powl", mfunc_longdouble[1],
Index: gcc/fortran/trans-intrinsic.c
===================================================================
*** gcc/fortran/trans-intrinsic.c (révision 118179)
--- gcc/fortran/trans-intrinsic.c (copie de travail)
*************** gfc_conv_intrinsic_mod (gfc_se * se, gfc
*** 976,989 ****
int n, ikind;
arg = gfc_conv_intrinsic_function_args (se, expr);
- arg2 = TREE_VALUE (TREE_CHAIN (arg));
- arg = TREE_VALUE (arg);
- type = TREE_TYPE (arg);
switch (expr->ts.type)
{
case BT_INTEGER:
/* Integer case is easy, we've got a builtin op. */
if (modulo)
se->expr = build2 (FLOOR_MOD_EXPR, type, arg, arg2);
else
--- 976,990 ----
int n, ikind;
arg = gfc_conv_intrinsic_function_args (se, expr);
switch (expr->ts.type)
{
case BT_INTEGER:
/* Integer case is easy, we've got a builtin op. */
+ arg2 = TREE_VALUE (TREE_CHAIN (arg));
+ arg = TREE_VALUE (arg);
+ type = TREE_TYPE (arg);
+
if (modulo)
se->expr = build2 (FLOOR_MOD_EXPR, type, arg, arg2);
else
*************** gfc_conv_intrinsic_mod (gfc_se * se, gfc
*** 991,1001 ****
break;
case BT_REAL:
! /* Real values we have to do the hard way. */
arg = gfc_evaluate_now (arg, &se->pre);
arg2 = gfc_evaluate_now (arg2, &se->pre);
tmp = build2 (RDIV_EXPR, type, arg, arg2);
/* Test if the value is too large to handle sensibly. */
gfc_set_model_kind (expr->ts.kind);
mpfr_init (huge);
--- 992,1060 ----
break;
case BT_REAL:
! n = END_BUILTINS;
! /* Check if we have a builtin fmod. */
! switch (expr->ts.kind)
! {
! case 4:
! n = BUILT_IN_FMODF;
! break;
!
! case 8:
! n = BUILT_IN_FMOD;
! break;
!
! case 10:
! case 16:
! n = BUILT_IN_FMODL;
! break;
!
! default:
! break;
! }
!
! /* Use it if it exists. */
! if (n != END_BUILTINS)
! {
! tmp = built_in_decls[n];
! se->expr = build_function_call_expr (tmp, arg);
! if (modulo == 0)
! return;
! }
!
! arg2 = TREE_VALUE (TREE_CHAIN (arg));
! arg = TREE_VALUE (arg);
! type = TREE_TYPE (arg);
!
arg = gfc_evaluate_now (arg, &se->pre);
arg2 = gfc_evaluate_now (arg2, &se->pre);
+ /* Definition:
+ modulo = arg - floor (arg/arg2) * arg2, so
+ = test ? fmod (arg, arg2) : fmod (arg, arg2) + arg2,
+ where
+ test = (fmod (arg, arg2) != 0) && ((arg < 0) xor (arg2 < 0))
+ thereby avoiding another division and retaining the accuracy
+ of the builtin function. */
+ if (n != END_BUILTINS && modulo)
+ {
+ tree zero = gfc_build_const (type, integer_zero_node);
+ tmp = gfc_evaluate_now (se->expr, &se->pre);
+ test = build2 (LT_EXPR, boolean_type_node, arg, zero);
+ test2 = build2 (LT_EXPR, boolean_type_node, arg2, zero);
+ test2 = build2 (TRUTH_XOR_EXPR, boolean_type_node, test, test2);
+ test = build2 (NE_EXPR, boolean_type_node, tmp, zero);
+ test = build2 (TRUTH_AND_EXPR, boolean_type_node, test, test2);
+ test = gfc_evaluate_now (test, &se->pre);
+ se->expr = build3 (COND_EXPR, type, test,
+ build2 (PLUS_EXPR, type, tmp, arg2), tmp);
+ return;
+ }
+
+ /* If we do not have a built_in fmod, the calculation is going to
+ have to be done longhand. */
tmp = build2 (RDIV_EXPR, type, arg, arg2);
+
/* Test if the value is too large to handle sensibly. */
gfc_set_model_kind (expr->ts.kind);
mpfr_init (huge);
Attachment:
Change.Logs
Description: Binary data
| Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
|---|---|---|
| Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |