- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I'm migrating my digital fortran projects now to Intel Fortran 12. Example code (I stripped it down)
CHARACTER * 40 VAR_:NAME (20)
..
IF ( INDEX_TEST .GT.0 .AND. VAR_NAME (INDEX_TEST) .EQ. 'xxx' ) THEN
INDEX_TEST maybe 0. Therefore I have the first condition. In Digital Foratran, the second conditionion is not handled, if the fist condition is not true.
In Intel fortran, the statment crashes when INDEX_TEST=0, because the second condition is always handled.
For my understanding, this is an error in the compiler. I'm using this kind of syntax on different compilers since more than 30 years, it seems, thatonly theintel fortran compilers work like this. Is there a compiler option to change this?
I'm migrating my digital fortran projects now to Intel Fortran 12. Example code (I stripped it down)
CHARACTER * 40 VAR_:NAME (20)
..
IF ( INDEX_TEST .GT.0 .AND. VAR_NAME (INDEX_TEST) .EQ. 'xxx' ) THEN
INDEX_TEST maybe 0. Therefore I have the first condition. In Digital Foratran, the second conditionion is not handled, if the fist condition is not true.
In Intel fortran, the statment crashes when INDEX_TEST=0, because the second condition is always handled.
For my understanding, this is an error in the compiler. I'm using this kind of syntax on different compilers since more than 30 years, it seems, thatonly theintel fortran compilers work like this. Is there a compiler option to change this?
Link Copied
14 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The Fortran standard does not specify the sequence of terms evaluated in an if instruction. The assumption ist wrong that the compiler has to treat the terms from left to right and stop the evaluation if a term becomes true. CVF and other older compilers evaluated the terms from left to right and quit if true, allright, but not the IVF compiler anymore. The IVF compiler designers left the possibility to evaluate the clauses in arbitrary sequence or in parallel to leave more room for optimizations. The compiler conforms to the standard, it's behavior is not an error. The workaround is to use two consecutive if instructions, the first with the 0 condition for the array index, the second with the if clause for the array member.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
So I have to scan my code for such dangerous statemets. Thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It may or may not be obvious, but the same problem applies to .OR. and other booleans also. It applies not just to IF's, but to any conditional, for instance, on a loop control. They can of course be nested in complicated ways. They can be tricky to "unwind" and you may have to unwind hundreds, and ones you overlook stay in your code as latent defects but they will all eventually blow up your program. A "CVF compatibility mode" would have been nice but instead we have a new, rich source of potential defects with a long half-life.
I strongly recommend you investigate VS IDE scripts to help your review. I've attached some scripts below, they may help get you started.
I strongly recommend you investigate VS IDE scripts to help your review. I've attached some scripts below, they may help get you started.
[vb]Imports System Imports EnvDTE Imports EnvDTE80 Imports EnvDTE90 Imports System.Diagnostics Imports System.Windows Public Module Module1 Function PrepareFindANDs(ByVal prompt As String) As String Dim what As String DTE.Find.MatchWholeWord = False DTE.Find.Action = vsFindAction.vsFindActionFind DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument DTE.Find.MatchCase = False DTE.Find.Backwards = False DTE.Find.MatchInHiddenText = True DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral what = ".and." DTE.Find.FindWhat = what Return what End Function Function CountANDs() As Integer Dim textSelection As EnvDTE.TextSelection Dim textSelectionPointSaved As TextPoint Dim count As Integer = 0 Dim findResult As EnvDTE.vsFindResult Dim firstFindLocation As EnvDTE.TextPoint textSelection = DTE.ActiveWindow.Selection textSelectionPointSaved = textSelection.ActivePoint.CreateEditPoint() textSelection.StartOfDocument() PrepareFindANDs("Count Occurrences") ' The Version 7.0 & 7.1 macros used the following While statement: ' While ((findResult = vsFindResult.vsFindResultFound) And (InStr(DTE.StatusBar.Text, "Passed") <> 1)) ' However, with the Find2.WaitForFindToComplete property the check ' for specific text to be shown in the status bar can be removed. CType(DTE.Find, EnvDTE80.Find2).WaitForFindToComplete = True findResult = DTE.Find.Execute() While (findResult = vsFindResult.vsFindResultFound) If (firstFindLocation Is Nothing) Then Dim foundSelection As EnvDTE.TextSelection foundSelection = DTE.ActiveWindow.Selection firstFindLocation = foundSelection.ActivePoint.CreateEditPoint Else Dim foundSelection As EnvDTE.TextSelection foundSelection = DTE.ActiveWindow.Selection If (firstFindLocation.EqualTo(foundSelection.ActivePoint)) Then Exit While End If End If count = count + 1 findResult = DTE.Find.Execute() End While '' Restore caret to location before invoking this command. textSelection.MoveToPoint(textSelectionPointSaved) Return count End Function Sub UnfoldShortCircuit() Dim selection As EnvDTE.TextSelection Dim startPoint As EnvDTE.EditPoint Dim endPoint As TextPoint Dim originalText As String selection = DTE.ActiveDocument.Selection() If selection.Text = "" Then MsgBox("Select one complete line." + vbCr + _ "If clause runs over multiple lines," + vbCr + _ "delete CR/LF until the clause is on one line.", _ MsgBoxStyle.Information, "Unfold Short Circuit") Exit Sub Else ' ask user if they want to unfold-short-circuit End If originalText = selection.Text ' Determine whether IF-THEN or DO-WHILE Dim containsIF As Boolean = originalText.ToUpper.Contains("IF") Dim containsTHEN As Boolean = originalText.ToUpper.Contains("THEN") Dim containsDO As Boolean = originalText.ToUpper.Contains("DO") Dim containsWHILE As Boolean = originalText.ToUpper.Contains("WHILE") Dim IF_token_end As Integer Dim THEN_token_start As Integer Dim WHILE_token_end As Integer Dim controlStructKind As String = "" If containsIF And containsTHEN Then controlStructKind = "IFTHEN" IF_token_end = originalText.ToUpper.IndexOf("IF") + 2 THEN_token_start = originalText.ToUpper.LastIndexOf("THEN") ElseIf containsDO And containsWHILE Then controlStructKind = "DOWHILE" WHILE_token_end = originalText.ToUpper.IndexOf("WHILE") + 5 Else MsgBox("Select a line that contains a complete " + _ "IF-conditions-THEN or DO-WHILE-conditions", _ MsgBoxStyle.Exclamation, "Unfold Short-Circuit") Exit Sub End If ' andClause = most of the stuff between the IF and the THEN Dim andClause As String = "" If controlStructKind = "IFTHEN" Then andClause = originalText.Substring(IF_token_end, THEN_token_start - IF_token_end) ElseIf controlStructKind = "DOWHILE" Then andClause = originalText.Substring _ (WHILE_token_end, originalText.Length - WHILE_token_end - 2) End If andClause = Trim(andClause) Dim AND_token_start As Integer AND_token_start = andClause.ToUpper.IndexOf(".AND.") If AND_token_start < 1 Then MsgBox("Did not find an .AND. in the selection.", _ MsgBoxStyle.Exclamation, "Unfold Short-Circuit") End If Dim lhs As String = "" Dim rhs As String = "" ' lhs = most of the stuff from the IF to the .AND. lhs = andClause.Substring(1, AND_token_start - 1) ' rhs = most of the stuff from the .AND. to the THEN rhs = andClause.Substring(AND_token_start + 5, andClause.Length - AND_token_start - 6) 'Exit Sub ' Insert boilerplate Metrics.LoadMetrics() DTE.UndoContext.Open("Unfold Short-Circuit") Try startPoint = selection.TopPoint.CreateEditPoint() startPoint.Insert("C* IVFJPH Unfold short-circuit operator." + vbCrLf) If controlStructKind = "DOWHILE" Then startPoint.Insert(vbTab + vbTab + "DO" + vbCrLf) End If startPoint.Insert(vbTab + vbTab + "BOTH_TRUE = .FALSE." + vbCrLf) startPoint.Insert(vbTab + vbTab + "IF " + lhs + " THEN" + vbCrLf) startPoint.Insert(vbTab + vbTab + vbTab + "IF " + rhs + " THEN" + vbCrLf) startPoint.Insert(vbTab + vbTab + vbTab + vbTab + "BOTH_TRUE = .TRUE." + vbCrLf) startPoint.Insert(vbTab + vbTab + vbTab + "END IF" + vbCrLf) startPoint.Insert(vbTab + vbTab + "END IF" + vbCrLf) If controlStructKind = "IFTHEN" Then startPoint.Insert(vbTab + vbTab + "IF ( BOTH_TRUE ) THEN" + vbCrLf) ElseIf controlStructKind = "DOWHILE" Then startPoint.Insert(vbTab + vbTab + "IF (BOTH_TRUE .EQ. .FALSE.) EXIT" + vbCrLf) End If startPoint.Insert("C* IVFJPH Original text commented below." + vbCrLf) startPoint.Insert("C* IVFJPH ") Dim anItem As ModuleMetric If myMetrics.Contains(ProjectName() + DTE.ActiveDocument.Name) Then anItem = myMetrics.Item(ProjectName() + DTE.ActiveDocument.Name) myMetrics.Remove(ProjectName() + DTE.ActiveDocument.Name) Else anItem = New ModuleMetric anItem.Name = DTE.ActiveDocument.Name anItem.Project = ProjectName() anItem.Path = DTE.ActiveDocument.Path anItem.ANDcount = CountANDs() anItem.FIXcount = 0 anItem.Inspected = 0 anItem.Commented = 0 End If anItem.FIXcount = anItem.FIXcount + 1 myMetrics.Add(anItem, ProjectName() + DTE.ActiveDocument.Name) Finally ' If an error occurred, then make sure that the undo context is cleaned up. ' Otherwise, the editor can be left in a perpetual undo context. DTE.UndoContext.Close() Metrics.SaveMetrics() End Try End Sub Sub FindNextAND() Dim textSelection As EnvDTE.TextSelection Dim startPoint As EnvDTE.EditPoint textSelection = DTE.ActiveWindow.Selection Dim result As Boolean = textSelection.FindText(".and.") If result = False Then textSelection.StartOfDocument() LoadMetrics() Dim anItem As ModuleMetric If myMetrics.Contains(ProjectName() + DTE.ActiveDocument.Name) Then anItem = myMetrics.Item(ProjectName() + DTE.ActiveDocument.Name) myMetrics.Remove(ProjectName() + DTE.ActiveDocument.Name) Else anItem = New ModuleMetric anItem.Name = DTE.ActiveDocument.Name anItem.Project = ProjectName() anItem.Path = DTE.ActiveDocument.Path anItem.ANDcount = CountANDs() anItem.FIXcount = 0 End If anItem.Inspected = 1 myMetrics.Add(anItem, ProjectName() + DTE.ActiveDocument.Name) SaveMetrics() End If ' textSelection.StartOfLine() End Sub End Module [/vb]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting jeremy_h
A "CVF compatibility mode" would have been nice but instead we have a new, rich source of potential defects
I'm amazed that so much code was made somewhat intentionally non-portable by requiring CVF in this way.
The only translator in my experience which supported C-style shortcuts was f2c (which used literal C && and || translation).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I trust Steve's opinion. I don't want to go too far off-topic but to answer your amazement, short-circuit eval was an important performance optimization, starting with VAX and continuing through CVF. For decades it was in our style guide as a preferred coding idiom. Because of this, we have more latent defects moving from CVF to IVF than from VAX to CVF.
Well OK, whine over. This is just the way it is. The IDE macros are a help, and we hope that anybody finding this thread will take a look at them. We reviewed many hundreds k sloc using this, which (if you look carefully) also collect metrics so we could see which modules were likely to be the most troublesome.
Well OK, whine over. This is just the way it is. The IDE macros are a help, and we hope that anybody finding this thread will take a look at them. We reviewed many hundreds k sloc using this, which (if you look carefully) also collect metrics so we could see which modules were likely to be the most troublesome.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The compiler may choose to do comparisons in any order, and to any level of completeness, that is logically equivalent. The optimizer may choose to move some comparisons earlier in the code if it feels it is useful (and still correct.) The underlying principle is that you, as a Fortran programmer, must not depend on any particular order of evaluation not specified by the standard. If you do, the results are unpredictable.
The compiler may choose to do short-circuiting, but that is an optimization, not a semantic requirement. Neither VAX Fortran nor CVF would always evaluate a compound logical expression in strict left-to-right order. Just because it seemed to in your program, that doesn't mean it was deliberate on the part of the compiler.
The compiler may choose to do short-circuiting, but that is an optimization, not a semantic requirement. Neither VAX Fortran nor CVF would always evaluate a compound logical expression in strict left-to-right order. Just because it seemed to in your program, that doesn't mean it was deliberate on the part of the compiler.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I had to make the same experience.
When I started at my current work, Ive never used Fortran before. And from C++ I was used to that the && operator would not evaluate the second expression, only & does.
Sure, it would make life (or coding) in Fortran easier, when youd have the same behaviour. But we havent, so we have to code two (or more) if clauses, when your expression requires this.
Markus
When I started at my current work, Ive never used Fortran before. And from C++ I was used to that the && operator would not evaluate the second expression, only & does.
Sure, it would make life (or coding) in Fortran easier, when youd have the same behaviour. But we havent, so we have to code two (or more) if clauses, when your expression requires this.
Markus
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>Sure, it would make life (or coding) in Fortran easier, when youd have the same behaviour.
Since FORTRAN was created first, then if you insist on same behavior then get the C/C++ group to change their syntax. This is not likely to happen. Same issue can be said about comparing other languages syntax rules e.g. Forth, Lisp, ...
Jim Dempsey
Since FORTRAN was created first, then if you insist on same behavior then get the C/C++ group to change their syntax. This is not likely to happen. Same issue can be said about comparing other languages syntax rules e.g. Forth, Lisp, ...
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim, only because Fortran is older doesnt mean that the behaviour is better. Why shouldnt you learn from other approaches? This sounds tpyical german, a thought-terminating clich is (translated) "We always did it this way, it always proved of value."
It is logical that when you have an AND comparison and the term on lhs is false, you dont need to evaluate rhs.
Markus
It is logical that when you have an AND comparison and the term on lhs is false, you dont need to evaluate rhs.
Markus
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
It's equally as logical that if the rhs is false then you don't need to evaluate the lhs, and maybe it's faster to evaluate the right hand side in some circumstances first. Maybe it's faster to evaluate the two operands in parallel - perhaps relevant in the context of defined operations on user defined types or with all that fancy out-of-sequence instruction execution that processors can do these days.
By not having short-circuiting the compiler has the freedom to do what it thinks is best.
By not having short-circuiting the compiler has the freedom to do what it thinks is best.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What seems "logical" is only such when you learned the "logical" way first.
Remember that Fortran originated as a language for mathematicians and scientists, and in math, logical operations have commutative and associative properties. The way the language is defined is that there is no strict left to right order and that the compiler may evaluate any logically equivalent expression to any degree of completeness. This gives compilers flexibility to optimize, but the lack of a specific order and short-circuiting in the language does trip up people who assume that left-to-right and short-circuiting is an immutable law of programming.
There have been proposals to add short-circuit operators to Fortran, but they have not yet found acceptance.
Remember that Fortran originated as a language for mathematicians and scientists, and in math, logical operations have commutative and associative properties. The way the language is defined is that there is no strict left to right order and that the compiler may evaluate any logically equivalent expression to any degree of completeness. This gives compilers flexibility to optimize, but the lack of a specific order and short-circuiting in the language does trip up people who assume that left-to-right and short-circuiting is an immutable law of programming.
There have been proposals to add short-circuit operators to Fortran, but they have not yet found acceptance.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
>>doesnt mean that the behaviour is better
Number 1, you did not ask for better, you asked for same behavior.
Number 2, better as it applies to IF parsing is subjective
Consider:
IF(funcA() && funcB() && funcC()) call DoSomething()
Where each funcX is relatively long and where the compiler is multi-threaded aware. The compiler could set an internalshared reduction variable to .false. then perform all functions in parallel with a reduction operator of .OR. to the internal shared reduction variable.
What you are considering as "better" results in serial processing of the IF statement.
WhatFORTRAN considers as "better" results in the possibility for the compiler to multi-thread the expression .OR. use serial processingbut reorder the expressions due to heuristics or what it can descern from compiling the code in the func's.
Maybe Steve can comment on this:
What happens with
IF((((funcA()) && funcB()) && funcC())) call DoSomething()
IOW use parens to force evalution order
(this may also require the functions to be non-PURE)
Jim Dempsey
Number 1, you did not ask for better, you asked for same behavior.
Number 2, better as it applies to IF parsing is subjective
Consider:
IF(funcA() && funcB() && funcC()) call DoSomething()
Where each funcX is relatively long and where the compiler is multi-threaded aware. The compiler could set an internalshared reduction variable to .false. then perform all functions in parallel with a reduction operator of .OR. to the internal shared reduction variable.
What you are considering as "better" results in serial processing of the IF statement.
WhatFORTRAN considers as "better" results in the possibility for the compiler to multi-thread the expression .OR. use serial processingbut reorder the expressions due to heuristics or what it can descern from compiling the code in the func's.
Maybe Steve can comment on this:
What happens with
IF((((funcA()) && funcB()) && funcC())) call DoSomething()
IOW use parens to force evalution order
(this may also require the functions to be non-PURE)
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for all the answers! This makes it more clearer to me :-)
Of course it makes sense to reorder the evaluation when you have something like
IF(funcA() && funcB() && funcC()) call DoSomething()
instead of
if(a>0 .and. array(a) > b) call DoSomething()
Especially nowadays reordering makes even more sense with multithreading and/or multi core CPUs and/or multi CPUs systems that you had not "in the early days".
Markus
Of course it makes sense to reorder the evaluation when you have something like
IF(funcA() && funcB() && funcC()) call DoSomething()
instead of
if(a>0 .and. array(a) > b) call DoSomething()
Especially nowadays reordering makes even more sense with multithreading and/or multi core CPUs and/or multi CPUs systems that you had not "in the early days".
Markus

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