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

            Bug ID: 124819
           Summary: libgfortran: REAL(4) transformational BESSEL_JN loses
                    accuracy against scalar path on x86_64-linux-gnu
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libfortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: albert at tugraz dot at
  Target Milestone: ---

The runtime transformational REAL(4) BESSEL_JN implementation appears to lose
too much accuracy relative to the scalar BESSEL_JN path on my x86_64-linux-gnu
system.

I can reproduce a failure of gcc/testsuite/gfortran.dg/bessel_6.f90 with
current trunk from 2026-04-08. The failing comparison is between:

- transformational path: BESSEL_JN(0, mymax, x)
- scalar path: [(BESSEL_JN(i, x), i = 0, mymax)]

The first mismatch on my system is:

  mymax = 37
  x = 475.779999
  i = 30
  rec(i) = 3.96264251E-04
  lib(i) = 3.96265590E-04
  relative error = 3.37849360E-06
  tolerance = 1.78813934E-06

A small instrumented version of bessel_6.f90 that prints the first failing
point is:

implicit none
real,parameter :: values(*) = [0.0, 0.5, 1.0, 0.9,
1.8,2.0,3.0,4.0,4.25,8.0,34.53, 475.78]
real,parameter :: myeps(size(values)) = epsilon(0.0) * [2, 7, 5, 6, 9, 12, 12,
7, 7, 8, 98, 15]
integer,parameter :: mymax(size(values)) = [100, 17, 23, 21, 27, 28, 32, 35,
31, 41, 47, 37]
integer, parameter :: Nmax = 100
real :: rec(0:Nmax), lib(0:Nmax)
integer :: i

do i = 1, ubound(values,dim=1)
  call compare(mymax(i), values(i), myeps(i))
end do

contains

subroutine compare(mymax, x, myeps)
  integer :: i, mymax
  real :: x, myeps

  rec(0:mymax) = BESSEL_JN(0, mymax, x)
  lib(0:mymax) = [(BESSEL_JN(i, x), i = 0, mymax)]

  do i = 0, mymax
    if (rec(i) == lib(i)) cycle
    if (abs((rec(i) - lib(i)) / rec(i)) > myeps) then
      print *, 'FAIL', mymax, x, i, rec(i), lib(i),
abs((rec(i)-lib(i))/rec(i)), myeps
      stop 1
    end if
  end do
end
end

Built and run with:

$ gcc-build/gcc/gfortran -B gcc-build/gcc /tmp/bessel_6_debug.f90 \
    -L gcc-build/x86_64-pc-linux-gnu/libgfortran/.libs \
   
-Wl,-rpath,/home/ert/code/gcc-dev/gcc-build/x86_64-pc-linux-gnu/libgfortran/.libs
\
    -o /tmp/bessel_6_debug
$ /tmp/bessel_6_debug
 STOP 1
  FAIL          37   475.779999              30   3.96264251E-04  
3.96265590E-04   3.37849360E-06   1.78813934E-06

The scalar side lowers to repeated jnf calls, while the transformational
REAL(4) side goes through libgfortran/generated/bessel_r4.c:bessel_jn_r4 and
uses a REAL(4) backward recurrence seeded from jnf(n2, x) and jnf(n2-1, x).
That recurrence seems to accumulate enough rounding error on this system to
miss the test tolerance.

This looks related to the historical sensitivity of bessel_6.f90 to target/libm
behavior, but the failing path here is specifically the libgfortran REAL(4)
recurrence implementation.

System configuration:
- GCC source: upstream/master at cfa0910d9c0fa307b3156f247c50044524b3d5b2
(2026-04-08)
- Local compiler under test: gcc version 16.0.1 20260403 (experimental)
- Configure line: ../gcc/configure --enable-languages=fortran
--disable-multilib --disable-bootstrap CFLAGS='-Og -g' CXXFLAGS='-Og -g'
- OS distro: CachyOS Linux
- Kernel: Linux mailuefterl 6.19.10-1-cachyos x86_64
- CPU: AMD Ryzen 9 5950X 16-Core Processor
- libc/libm: GNU libc 2.43, using /usr/lib/libm.so.6

I have not yet determined whether using wider intermediates in bessel_jn_r4 is
sufficient on all systems, but that seems like the first implementation change
to try.

Reply via email to