Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

What's the most efficient way to compare arrays?

rwg
Novice
9,125 Views
What's the most efficient way to compare arrays in Fortran 90/95?
Is there an intrinsic function to compare arrays in Fortran 90/95?

A very elegant way is

IF(ALL(ARRAY1.EQ.ARRAY1)) THEN
CALL DOEQUAL
ELSE
CALL DOUNEQUAL
ENDIF

which works for all types of array1 and array2 as long as they have the same type and length,but I think it isslow because an array of logicals is created first. So much faster would be

DO I=1,SIZE(ARRAY1)
IF(ARRAY1(1).EQ.ARRAY2(I)) EXIT
ENDDO
IF(I.GT.N) THEN
CALL DOEQUAL
ELSE
CALL DOUNEQUAL
ENDIF

But this is very unelegant. Writing a function containingthe do-loop and returning .TRUE. or. .FALSE. would make it as elegant as ALL(ARRAY1.EQ.ARRAY2) but there is the overhead of the function-call and for each type of ARRAY there has to be a another function. So is there another elegant and fast way to compare arrays in fortran 90/95?
0 Kudos
4 Replies
Arjen_Markus
Honored Contributor II
9,125 Views
As always with this type of questions: have you determined that it is actually slow by measuring the time it
takes?

An alternative, lacking the generic character of ALL() or ANY() is:

logical function equal( array1, array2 )
integer, dimension(:), intent(in) :: array1, array2
integer :: i

equal =size(array1) == size(array2)
if ( equal ) then
do i = 1,size(array1)
equal = array1(i) == array2(i)
if ( .not. equal )exit
enddo
endif
end function equal

This function will return whenever it is possible to conclude the two arrays are
not equal, thus minimising the amount of work.

But it is not generic - you would have to create specific versions for all types of
arrays you want to compare.

I would go for ALL or ANY, ignoring possible performance problems until
I had established that the performance is really an issue.

Regards,

Arjen
0 Kudos
anthonyrichards
New Contributor III
9,125 Views
If they are arrays of INTEGERs, then the comparison can be exact.

However, if they are arrays of REALs, you should allow a small tolerance when comparing REALs, especially if they are results from different computational paths.

Therefore, if REAL, you must consider doing the comparison element-by element anyway.
0 Kudos
TimP
Honored Contributor III
9,125 Views
IF(ALL(abs(ARRAY1 - ARRAY2) < tolerance)))
is potentially vectorizable, except that these array operations probably don't figure in typical compiler development benchmark suites. You're welcome to submit a small case of a missed optimization which is important to you.
When OpenMP user defined reductions are supported by compilers, it will become easier to parallelize such operations. A concept for parallelization of a 2-D comparison with current facilities:

logical local_equal, global_equal
global_equal = .true.
!$omp parallel do private(local_equal),shared(global_equal)
do j = 1,size(ARRAY1,2)
local_equal = all(abs(ARRAY1(:,j) - ARRAY2(:,j)) < tolerance)))
!$omp critical
global_equal = local_equal .and. global_equal
!$omp end critical
end do

With the current renewed interest in vector-parallel optimization, your input might help implement more efficiency in such operations.
0 Kudos
jimdempseyatthecove
Honored Contributor III
9,125 Views
logical global_equal
global_equal = .true.
!$omp parallel do shared(global_equal)
do j = 1,size(ARRAY1,2)
if(all(abs(ARRAY1(:,j) - ARRAY2(:,j)) < tolerance)))) cycle
global_equal = false
exit
end do

When first index is very large you might consider

integer split
logical global_equal
global_equal = .true.
split = size(ARRAY1,1) / 2
!$omp parallel do shared(global_equal)
do j = 1,size(ARRAY1,2)
if(all(abs(ARRAY1(1:split,j) - ARRAY2(1:split,j)) < tolerance))))then
if(all(abs(ARRAY1(split+1:,j) - ARRAY2(split+1:,j)) < tolerance)))) cycle
endif
global_equal = false
exit
end do

To be safe, you should add tests for first index being small (i.e. split becomming 0), and force split to multiple of 2 or 4 depending on kind of array (how many fit in SSE/AVX register).

Depending on your data, i.e. mostely not equal, a serial double do loopwould be fastest.

Jim Dempsey
0 Kudos
Reply