For a program slightly modified from Speed of array intrinsics - #3 by Beliavsky, printing the real kind and setting it to either single or double precision, compiling with ifort -Ofast
on WSL2, I do find it to be twice as fast to compute the min, max, and mean of a large 1D array in single precision than double precision (except for an algorithm that is slow in both cases), and more than twice as fast to compute exponentials in single than double precision for a large array.
wp = 8
n = 100000000
time task
0.1932 x=exp(x)
0.1159 minval(x), maxval(x)
0.0628 min_max(x)
0.0627 min_max_explicit_shape(x)
0.2164 min_max_pairs(x)
0.2168 min_max_local(x)
0.1543 minval(x),maxval(x),sum(x)/n
0.0652 min_max_mean(x)
0.0653 min_max_mean_explicit_shape(x)
real 0m1.876s
user 0m1.800s
sys 0m0.061s
wp = 4
n = 100000000
time task
0.0859 x=exp(x)
0.0588 minval(x), maxval(x)
0.0313 min_max(x)
0.0313 min_max_explicit_shape(x)
0.2289 min_max_pairs(x)
0.2055 min_max_local(x)
0.0774 minval(x),maxval(x),sum(x)/n
0.0316 min_max_mean(x)
0.0315 min_max_mean_explicit_shape(x)
real 0m1.199s
user 0m1.110s
sys 0m0.072s
code
module min_max_mod
implicit none
integer, parameter :: wp = kind(1.0)
contains
pure function min_max(x) result(y)
real(kind=wp), intent(in) :: x(:)
real(kind=wp) :: y(2)
integer :: i,n
n = size(x)
if (n < 1) return
y(1) = x(1)
y(2) = y(1)
do i=2,n
if (x(i) < y(1)) y(1) = x(i)
if (x(i) > y(2)) y(2) = x(i)
end do
end function min_max
!
pure function min_max_explicit_shape(n,x) result(y)
integer , intent(in) :: n
real(kind=wp), intent(in) :: x(n)
real(kind=wp) :: y(2)
integer :: i
if (n < 1) return
y(1) = x(1)
y(2) = y(1)
do i=2,n
if (x(i) < y(1)) y(1) = x(i)
if (x(i) > y(2)) y(2) = x(i)
end do
end function min_max_explicit_shape
!
pure function min_max_pairs(x) result(y)
real(kind=wp), intent(in) :: x(:)
real(kind=wp) :: y(2)
integer :: i,n
logical :: odd
n = size(x)
if (n < 1) return
if (n == 1) then
y(1) = x(1)
y(2) = x(2)
return
end if
odd = mod(n,2) == 1
if (x(2) > x(1)) then
y(1) = x(1)
y(2) = x(2)
else
y(1) = x(2)
y(2) = x(1)
end if
do i=3,n-1,2
if (x(i+1) > x(i)) then
if (y(1) > x(i)) y(1) = x(i)
if (y(2) < x(i+1)) y(2) = x(i+1)
else
if (y(1) > x(i+1)) y(1) = x(i+1)
if (y(2) < x(i)) y(2) = x(i)
end if
end do
if (odd) then
y(1) = min(y(1),x(n))
y(2) = max(y(1),x(n))
end if
end function min_max_pairs
!
pure function min_max_local(x) result(y)
! same as min_max_pairs but sets
! xi to x(i) and xi1 to x(i+1)
real(kind=wp), intent(in) :: x(:)
real(kind=wp) :: y(2)
real(kind=wp) :: xi,xi1
integer :: i,n
logical :: odd
n = size(x)
if (n < 1) return
if (n == 1) then
y(1) = x(1)
y(2) = x(2)
return
end if
odd = mod(n,2) == 1
if (x(2) > x(1)) then
y(1) = x(1)
y(2) = x(2)
else
y(1) = x(2)
y(2) = x(1)
end if
do i=3,n-1,2
xi1 = x(i+1)
xi = x(i)
if (xi1 > xi) then
if (y(1) > xi) y(1) = xi
if (y(2) < xi1) y(2) = xi1
else
if (y(1) > xi1) y(1) = xi1
if (y(2) < xi) y(2) = xi
end if
end do
if (odd) then
y(1) = min(y(1),x(n))
y(2) = max(y(1),x(n))
end if
end function min_max_local
!
pure function min_max_mean(x) result(y)
real(kind=wp), intent(in) :: x(:)
real(kind=wp) :: y(3)
integer :: i,n
n = size(x)
if (n < 1) return
y(1) = x(1)
y(2:3) = y(1)
do i=2,n
if (x(i) < y(1)) y(1) = x(i)
if (x(i) > y(2)) y(2) = x(i)
y(3) = y(3) + x(i)
end do
if (n > 0) y(3) = y(3)/n
end function min_max_mean
!
pure function min_max_mean_explicit_shape(n,x) result(y)
integer , intent(in) :: n
real(kind=wp), intent(in) :: x(n)
real(kind=wp) :: y(3)
integer :: i
if (n < 1) return
y(1) = x(1)
y(2:3) = y(1)
do i=2,n
if (x(i) < y(1)) y(1) = x(i)
if (x(i) > y(2)) y(2) = x(i)
y(3) = y(3) + x(i)
end do
if (n > 0) y(3) = y(3)/n
end function min_max_mean_explicit_shape
end module min_max_mod
!
program xmin_max_exp
use min_max_mod
implicit none
integer :: i,n
integer, parameter :: nt = 10, nlen = 30, ncol_extremes = 5, ncol_mmm = 3
integer :: icol
real(kind=wp), allocatable :: x(:)
real(kind=wp) :: extremes(2,ncol_extremes),t(nt),xmin_max_mean(3,ncol_mmm)
character (len=nlen) :: labels(nt-1) = [character(len=nlen) :: &
"x=exp(x)","minval(x), maxval(x)","min_max(x)","min_max_explicit_shape(x)", &
"min_max_pairs(x)", &
"min_max_local(x)","minval(x),maxval(x),sum(x)/n","min_max_mean(x)", &
"min_max_mean_explicit_shape(x)"]
character (len=*), parameter :: fmt_cr = "(a20,*(1x,f16.12))"
logical :: print_results
n = 10**8
allocate (x(n))
print*,"wp =",wp
print*,"n =",n
call random_number(x)
print_results = x(1) > 1.0_wp ! .false.
call cpu_time(t(1))
x = exp(x)
call cpu_time(t(2))
extremes(:,1) = [minval(x),maxval(x)]
call cpu_time(t(3))
extremes(:,2) = min_max(x)
call cpu_time(t(4))
extremes(:,3) = min_max_explicit_shape(n,x)
call cpu_time(t(5))
extremes(:,4) = min_max_pairs(x)
call cpu_time(t(6))
extremes(:,5) = min_max_local(x)
call cpu_time(t(7))
xmin_max_mean(:,1) = [minval(x),maxval(x),sum(x)/n]
call cpu_time(t(8))
xmin_max_mean(:,2) = min_max_mean(x)
call cpu_time(t(9))
xmin_max_mean(:,3) = min_max_mean_explicit_shape(n,x)
call cpu_time(t(10))
if (print_results) then
do icol=1,ncol_extremes
print fmt_cr,"min, max:",extremes(:,icol)
end do
do icol=1,ncol_mmm
print fmt_cr,"min, max, mean:",xmin_max_mean(:,icol)
end do
end if
print "(/,a8,5x,a30)","time","task"
print "(f8.4,5x,a30)",(t(i+1)-t(i),trim(labels(i)),i=1,nt-1)
end program xmin_max_exp