- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
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?
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
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

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page