 |
forums.silverfrost.com Welcome to the Silverfrost forums
|
View previous topic :: View next topic |
Author |
Message |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Fri Jun 24, 2011 5:19 pm Post subject: Bug with element by element logical comparison |
|
|
I have uncovered a bug with logical comparisons of character variables in arrays.
Fortran's logical comparison == (or .eq.) should work for arrays (and array sections) on an element by element basis. For character variables this should be done on the same basis as for scalars, i.e. the character variable with the smallest length should first be padded with trailing blanks so both character variables have the same length.
However, this doesn't seem to work for arrays of character variables where the elements have a trimmed length of 1 (i.e. only one non-blank character in the first position).
In the following code, test 1 passes, but test 2 fails in two different ways.
I get the following output. Strangely the last array printed only has one element (Maybe there's a second bug with print logical array, but I have not looked hard at this).
TEST 1
Should print T F (AND DOES!)
T F
TEST 2
Should print T F (BUT DOESN'T!)
F F
Should print T F (BUT DOESN'T)
F
Hopefully, the code below is small enough to allow this to be debugged.
Code: |
program anon
implicit none
logical :: flags(2)
character(len=3) :: s
print '(1x/"TEST 1"/)'
! Set s to 'AB ', i.e. it has one trailing blank
s = 'AB'
! The character array elements 'AB' and 'BB' should be padded with one blank to
! length 3 before carrying out the comparisons.
print *,'Should print T F (AND DOES!)'
flags = (s == (/'AB','BB'/))
print *, flags
print '(1x/"TEST 2"/)'
! Set s to 'A ', i.e. it has two trailing blanks
s = 'A'
! The character array elements 'A' and 'B' should be padded with two blanks to
! length 3 before carrying out the comparisons.
print *,'Should print T F (BUT DOESN''T!)'
flags = (s == (/'A','B'/))
print *, flags
print *,'Should print T F (BUT DOESN''T)'
print *, (s == (/'A','B'/))
end program anon
|
Best Regards
David. |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Fri Jul 01, 2011 8:20 am Post subject: |
|
|
My initial thought is that character variables and character arrays are different types objects so I would not attempt the test for equality. I have not looked at the Standard to see if it has anything to say about this.
The compiler does not appear to handle this kind of code very well - error messages are missing or have little or no meaning, results are produced when I would expect a compilation error.
I could check this out but I am wondering why you would want to do this kind of test for equality. |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Fri Jul 01, 2011 3:48 pm Post subject: |
|
|
Hi Paul
The standard says that the comparison should be done element by element, and where one operand is a scalar it should be broadcast to an array of the same shape and size first. This is the basic rule for integer, real variables. For character there is the additional rule of appending sufficient blanks to make the characters being compared the same size.
There is no error in the code I posted, so you should not get a compiler error. I didn't when I tried it. Moreover, you will see that Test 1 clearly works and meets the standard, while Test 2 does not. It is simply the case that the compiler does not correctly append blanks (spaces) to the array elements before doing the comparison.
Typically, you might use this functionality with the intrinsic function any. E.g. to check if an item is in a list you could write the following.
Code: |
character(len=10) :: colour
read(*,*) colour
! Note spaces in array elements are needed in Fortran 95 as
! they must be the same length.(This has been relaxed in F2003).
! The compiler should add another 4 spaces to each element to
! make the lengths agree with that of colour.
if (any(colour == (/'RED ', 'YELLOW', 'BLUE '/))) then
print *, 'Colour is Primary'
end if
|
There are possibly other uses involving lexical comparison intrinsic functions (which are elemental and accept arrays), e.g. LGE, LGT, LLE, LLT as well (And when using where and intrinsics which accept array MASKS as well).
Perhaps I wasn't clear in my first post, but the above snippet of code will actually work with your compiler. The error only shows up when the strings have one character, e.g. the following exposes the bug.
Code: |
character(len=10) :: colour
print *,'Enter first letter'
read(*,*) colour
if (any(colour == (/'R', 'Y', 'B'/))) then !<< BUG
print *, 'Colour is Primary'
end if
|
But I didn't want to give the impression the error was in any so I posted a rather obscure way of constructing an array of logicals and printing them out as this is where the error lies. (There are other issues relating to use of any which you have acknowledged).
So your compiler works most of the time but there's some sort of "off by one" error which occurs for strings of len_trim = 1.
Please note, I am not trying to be critical, just helpful. I can get around this issue easily enough.
By the way, the requirement for logical expressions to work with arrays has been in the Standard since Fortran 90.
I program with several commercial and open source Fortran compilers and they all pass my Test 2.
Kind Regards
David.
Last edited by davidb on Fri Jul 01, 2011 4:58 pm; edited 2 times in total |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Fri Jul 01, 2011 4:01 pm Post subject: |
|
|
Can you give me the reference to the paragraph in Fortran 95 Standard and I will check it out. |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Fri Jul 01, 2011 4:39 pm Post subject: |
|
|
I only have a draft of the standard here. This is what it says in three relevant sections. The first section is about conformable arrays, the second section refers to the need for intrinsic operations (+, *, /, == etc) to work with arrays as well as scalars, whilst the third is all about how to check characters for equality.
The bold text is my emphasis, just so you can see the main bits of interest.
ISO/IEC 1539-1 (Part 1) - the base language
2.4.5 Array
Two arrays are conformable if they have the same shape. A scalar is conformable with any array. Any intrinsic operation defined for scalar objects may be applied to conformable objects. Such operations are performed element-by-element to produce a resultant array conformable with the array operands. Element-by-element operation means corresponding elements of the operand arrays are involved in a "scalar-like" operation to produce the corresponding element in the result
array, and all such element operations may be performed in any order or simultaneously. Such an operation is described as elemental
7.2 Interpretation of intrinsic operations.
"The intrinsic operations are those defined in 7.1.2. These operations are divided into the following categories: numeric, character, relational, and logical. The interpretations defined in the following sections apply to both scalars and arrays; the interpretation for arrays is obtained by applying the interpretation for scalars element by element."
7.2.3. Relational intrinsic operations
"For a character relational intrinsic operation, the operands are compared one character at a time in order, beginning with the first character of each character operand. If the operands are of unequal length, the shorter operand is treated as if it were extended on the right with blanks to the length of the longer operand. If both x1 and x2 are of zero length, x1 is equal to x2; if every character of x1 is the same as the character in the corresponding position in x2, x1 is equal to x2. Otherwise, at the first position where the character operands differ, the character operand x1 is considered to be less than x2 if the character value of x1 at this position precedes the value of x2 in the collating
sequence (4.3.2.1.1); x1 is greater than x2 if the character value of x1 at this position follows the value of x2 in the collating sequence."
Regards
David.
PS. If you have Metcalf, Reid and Cohen's "Explained" book you might look at the example of comparing arrays in Section 3.10, p. 46 in my edition.
Last edited by davidb on Sat Jul 02, 2011 11:40 am; edited 1 time in total |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Sat Jul 02, 2011 8:07 am Post subject: |
|
|
Forgive me but I am still missing the point. If for simplicity I work with integers then the following code
Code: | integer a(4),b
logical f(4),L
a = (/1,2,3,4/)
b=2
f = (a == (/1,2,3,4/))
L = (b == (/1,2,3,4/))
end |
is OK for f but fails to compile for L. I assume that this is correct.
How does this translate for character variables? |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Sat Jul 02, 2011 8:09 am Post subject: |
|
|
Correction L needs a dimension L(4).
Maybe I am getting somewhere. |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Sat Jul 02, 2011 8:17 am Post subject: |
|
|
Finally! Yes there is a bug in the compiler and I will aim to get it fixed. |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Sat Jul 02, 2011 10:22 am Post subject: |
|
|
Excellent! Glad the penny's dropped.
Your integer case works, giving T T T T in the first case, and F T F F in the second (T is .true., F is .false.). So the principle is clear. But there are issues with characters.
I did try to convert your integer case to character verbatim, but I got an internal compiler error. This is different behaviour from what I saw in my Test 2 above (which compiled and gave the wrong result). So maybe the same bug manifests itself in different ways
I narrowed the code down to the following (by deleting things).
This compiles in DEBUG mode but not using CHECKMATE.
Code: |
character(len=1) :: a(4)
logical f(4)
a = (/'1','2','3','4'/)
f = (a == (/'1','2','3','4'/))
end
|
Good luck with finding it.
David. |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Sun Apr 29, 2012 4:02 pm Post subject: |
|
|
Paul, did this get fixed?
I am still getting incorrect behaviour with v6.2.
I can provide a simple example of a code which demonstrates the issue if needed.
David. _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Wed May 02, 2012 12:13 pm Post subject: |
|
|
We have had a go at this bug but it turns out to be a very tricky one to fix.
Hence it remains unfixed but not forgotten. |
|
Back to top |
|
 |
PaulLaidler Site Admin
Joined: 21 Feb 2005 Posts: 8211 Location: Salford, UK
|
Posted: Thu May 03, 2012 12:41 pm Post subject: |
|
|
I have now fixed this bug for the next release. |
|
Back to top |
|
 |
davidb
Joined: 17 Jul 2009 Posts: 560 Location: UK
|
Posted: Thu May 03, 2012 5:33 pm Post subject: |
|
|
Thank you.  _________________ Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|