Ah, yes, you are right. I was thinking wrongly about the result of spacing(0.0).
I have always used epsilon()
, or its explicit value, for these kind of tests, and now I’m using spacing()
more often. There are a few gotchas. The epsilon expression can sometimes be almost a factor of 2 larger than the spacing value. I’ve found a few cases where that matters, and I had to modify the test expression accordingly
As to what spacing() returns, try this code:
program xxx
use, intrinsic :: iso_fortran_env, only: wp=>real64
implicit none
real(wp) :: a
a = 1.0_wp
write(*,*) spacing(nearest(a,-1.0_wp))
write(*,*) spacing(a)
write(*,*) spacing(nearest(a,+1.0_wp))
a = 1.5_wp
write(*,*) spacing(nearest(a,-1.0_wp))
write(*,*) spacing(a)
write(*,*) spacing(nearest(a,+1.0_wp))
end program xxx
On my computer, it gives:
$ gfortran xxx.F90 && a.out
1.1102230246251565E-016
2.2204460492503131E-016
2.2204460492503131E-016
2.2204460492503131E-016
2.2204460492503131E-016
2.2204460492503131E-016
Note that the first three numbers are right at the boundary were the fp exponent changes, while the last three numbers are in the middle of the range where the exponent is all the same. That is why there is exactly a factor of 2 difference in the first two printed values. If I had used multiplication with epsilon()
instead of spacing()
, the output would have been different. Basically spacing()
always returns a value with all zeros in the mantissa except for the leading hidden bit, while multiplication by epsilon()
results in a value that has the same mantissa bits as the multiplicand, but with a shifted exponent.