replica nfl jerseysreplica nfl jerseyssoccer jerseyreplica nfl jerseys forums.silverfrost.com :: View topic - Bug with element by element logical comparison
forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Bug with element by element logical comparison

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support
View previous topic :: View next topic  
Author Message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Fri Jun 24, 2011 5:19 pm    Post subject: Bug with element by element logical comparison Reply with quote

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
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Fri Jul 01, 2011 8:20 am    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Fri Jul 01, 2011 3:48 pm    Post subject: Reply with quote

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
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Fri Jul 01, 2011 4:01 pm    Post subject: Reply with quote

Can you give me the reference to the paragraph in Fortran 95 Standard and I will check it out.
Back to top
View user's profile Send private message AIM Address
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Fri Jul 01, 2011 4:39 pm    Post subject: Reply with quote

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
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Sat Jul 02, 2011 8:07 am    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Sat Jul 02, 2011 8:09 am    Post subject: Reply with quote

Correction L needs a dimension L(4).
Maybe I am getting somewhere.
Back to top
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Sat Jul 02, 2011 8:17 am    Post subject: Reply with quote

Finally! Yes there is a bug in the compiler and I will aim to get it fixed.
Back to top
View user's profile Send private message AIM Address
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Sat Jul 02, 2011 10:22 am    Post subject: Reply with quote

Excellent! Glad the penny's dropped. Very Happy

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 Question

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
View user's profile Send private message
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Sun Apr 29, 2012 4:02 pm    Post subject: Reply with quote

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
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Wed May 02, 2012 12:13 pm    Post subject: Reply with quote

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
View user's profile Send private message AIM Address
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 8210
Location: Salford, UK

PostPosted: Thu May 03, 2012 12:41 pm    Post subject: Reply with quote

I have now fixed this bug for the next release.
Back to top
View user's profile Send private message AIM Address
davidb



Joined: 17 Jul 2009
Posts: 560
Location: UK

PostPosted: Thu May 03, 2012 5:33 pm    Post subject: Reply with quote

Thank you. Smile
_________________
Programmer in: Fortran 77/95/2003/2008, C, C++ (& OpenMP), java, Python, Perl
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> Support All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
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