https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109008

--- Comment #12 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
(In reply to Richard Biener from comment #11)

I think before we code something on the compiler side, it might be better
to play just with C testcases.

Quite naive

#include <math.h>

__attribute__((noipa)) void
extend_range (double result, int (*test) (double), double *result_min, double
*result_max)
{
  *result_min = result;
  *result_max = result;
  for (double eps = __DBL_DENORM_MIN__; __builtin_isfinite (eps); eps = eps *
2.0)
    if (!test (result - eps))
      {
        *result_min = result - eps;
        break;
      }
  for (double eps = __DBL_DENORM_MIN__; __builtin_isfinite (eps); eps = eps *
2.0)
    if (!test (result + eps))
      {
        *result_max = result + eps;
        break;
      }
}

__attribute__((noipa)) double
fn1 (double eps)
{
  double d = 1. + eps;
  if (d == 1.)
    return eps;
  return 0.0;
}

int
test1 (double eps)
{
  return fn1 (eps) == eps;
}

__attribute__((noipa)) double
fn2 (double eps)
{
  double d = 1. + eps;
  if (d == 0x1.0000001p0)
    return eps;
  return 0.0;
}

int
test2 (double eps)
{
  return fn2 (eps) == eps;
}

__attribute__((noipa)) double
fn3 (double eps)
{
  double d = 1. + eps;
  if (d == 2.)
    return eps;
  return 0.0;
}

int
test3 (double eps)
{
  return fn3 (eps) == eps;
}

int
main ()
{
  double min, max;
  extend_range (1. - 1., test1, &min, &max);
  __builtin_printf ("%.32a [%.32a, %.32a]\n", 1.0 - 1., min, max);
  extend_range (0x1.0000001p0 - 1., test2, &min, &max);
  __builtin_printf ("%.32a [%.32a, %.32a]\n", 0x1.0000001p0 - 1., min, max);
  extend_range (2. - 1., test3, &min, &max);
  __builtin_printf ("%.32a [%.32a, %.32a]\n", 2. - 1., min, max);
  return 0;
}

prints
0x0.00000000000000000000000000000000p+0
[-0x1.00000000000000000000000000000000p-53,
0x1.00000000000000000000000000000000p-52]
0x1.00000000000000000000000000000000p-28
[0x1.fffffe00000000000000000000000000p-29,
0x1.00000100000000000000000000000000p-28]
0x1.00000000000000000000000000000000p+0
[0x1.ffffffffffffe0000000000000000000p-1,
0x1.00000000000020000000000000000000p+0]
so yes, clearly even the x + 1. == 2. reverse is affected, but while maximum of
other_op and lhs range's ulp might be a good starting point, it would be good
to iteratively adjust it.  The above just searches for a power of two epsilon
in both directions (first one that changes the range, so conservatively
larger), wonder if for the search instead of iterations we couldn't do a binary
search between the largest and smallest exponents,
and/or whether after finding a pair of power of two epsilons where one extends
the lhs range and the other one still doesn't do up to mantissa precision
further iterations to find the exact epsilon value; though perhaps stop after
some constant number of them and consider that good enough (similarly, if the
min - eps (or max + eps) for two different values yield the same value).
All this still sounds quite brute force as opposed to trying to be clever and
do the math right.

Reply via email to