Prev: XLF V13.1 release for AIX -- fully compliant Fortran 2003 standard
Next: Matlab mexing with gfortran -- String handling.
From: Uno on 23 Apr 2010 00:28 Richard Maine wrote: > Uno <merrilljensen(a)q.com> wrote: >> sqft = 144 > > Oddly, I recall thinking of that line in your code as being particularly > hard to read. The type promotion aside, I found the variable name > confusing. Only by seeing how it was used in the code could I deduce > that this was a conversion factor to turn square inches into square feet > (by dividing). It would have been better if it were sqft = 144.0 Since I measure to the closest sixteenth, these numbers show up as a rational number of inches, usually having a fractional part. Most clients would be confused if I didn't do this small trick in dimensional analysis. Dividing by a real is not something that fortran's gonna drop the ball on. -- Uno
From: Simon Geard on 21 Apr 2010 04:40 On 20/04/2010 07:35, Uno wrote: > Richard Maine wrote: >> Uno <merrilljensen(a)q.com> wrote: >> ... >>> implicit integer (a-e) >> ... >>> q1) Does anything above look wrong? >> >> Well, one thing that strikes me as "wrong" (with the quotes because it >> is not actually an error, but rather a stylistic choice) is the use of >> implicit typing. >> >> While I have been known to make exceptions in the face of pleas of >> hardship, I have a general policy of declining to help debug code that >> uses implicit typing. It makes the work of debugging substantially >> harder, as well as substantially increasing the number of bugs typically >> present. I figure that if I spend the extra effort to debug the messes >> that sometimes result, I am acting as an "enabler" in the sense of (from >> Merriam Webster online) >> >> "one who enables another to persist in self-destructive behavior (as >> substance abuse) by providing excuses or by making it possible to >> avoid the consequences of such behavior" >> >> Some people have been known to argue that implicit typing simplifies >> things for them enough to make up for any increased debugging problems. >> That position seems incompatible with asking for debugging help. >> >> In this case, I stopped reading the code after seeing the IMPLICIT >> statement. >> > > That's a reasonable reaction. The only variable that ended up in the > (a-e) range was 'cases'. It wou .. hold on, > > $ gfortran -Wall -Wextra m1.f90 -o out > $ ./out > wood supply is 672.00000 > living 258.86633 > dining 177.88020 > hall 28.285591 > sunroom 53.108505 > strip 23.138889 > > total1 is 541.27954 > office 146.99132 > foyer 44.358074 > total2 is 732.62891 > $ cat m1.f90 > implicit real (a-z) > > sqft = 144 > > cases = 28 > footage = 24 > supply = cases * footage > print *, "wood supply is ", supply > > hor = 208.25 > vert = 179 > r1 = hor * vert / sqft > print *, "living ", r1 > > hor = 208.25 > vert = 123 > r2 = hor * vert / sqft > print *, "dining ", r2 > > hor = 85.75 > vert = 47.5 > r3 = hor * vert / sqft > print *, "hall ", r3 > > hor = 79.25 > vert = 96.5 > r4 = hor * vert / sqft > print *, "sunroom ", r4 > > hor = 208.25 > vert = 16 > r5 = hor * vert / sqft > print *, "strip ", r5 > > total1 = r1+r2+r3+r4+r5 > > print *, " " > print *, "total1 is ", total1 > > hor = 118.25 > vert = 179 > r6 = hor * vert / sqft > print *, "office ", r6 > > hor = 40.75 > vert = 156.75 > r7 = hor * vert / sqft > print *, "foyer ", r7 > > total2 = total1+r6+r7 > print *, "total2 is ", total2 > > end program > ! gfortran -Wall -Wextra m1.f90 -o out > $ > > Better? I think what Richard meant was that you should start with 'implicit none' then explicitly declare each variable, e.g. implicit none real :: sqft, footage ! etc. integer :: cases ! etc. Simon
From: glen herrmannsfeldt on 21 Apr 2010 07:28 Richard Maine <nospam(a)see.signature> wrote: > Ron Shepard <ron-shepard(a)NOSPAM.comcast.net> wrote: (snip) >> Not necessarily. If you need something that is in fortran, but not >> in excel or some other language, then you would use fortran. A good >> example of this is eigenvalue problems. Excel doesn't have any >> eigenvalue routines built-in. I sometimes wish that it did, but it >> doesn't. > But I think Glen's point (I sometimes misunderstand him, but I think I > got this one - probably means I'm wrong :-)) was that you wouldn't write > Fortran code to solve a particular Eigenvalue problem. Instead, you > would write (or more likely, use one from a library) a routine that > solved a more general Eigenvalue problem, and you would feed it the > particular array in question (assuming one was talking array > eigenvalues). Yes. In some other languages, one might feed a particular array, though with the usual ability to change that array. Not that I use Excel that much, but that would fit with the way Excel is used. The Mathematica notebook also has a similar idea about combining code and modifiable data. As for Excel, one could write (or translate from Fortran) an eigenvalue routine in VBA for use from Excel. -- glen
From: Uno on 25 Apr 2010 20:24 dpb wrote: [big snips, a lot of code] > What would have been better was a descriptive name for the conversion > factor that relates to how is is used was the point being made. Again, > in trivial code it's not terribly difficult to dig thru and retrieve > such things from context altho it takes time and effort. As code size > and complexity grows, the importance grows with it and it's quite > possible (actually quite common) that even the original coder will > puzzle over "what was I doing there????" when re-visiting code later if > it isn't made patently clear thru naming conventions and/or comments or > straightforward coding what was being implemented. Thanks for your response, dpb. I think my latest version addresses this criticism. > > You seem oblivious to the underlying issues raised re: IMPLICIT NONE -- > whether it's simply inexperience showing or stubbornness for the sake of > maintaining present prejudices and practice it doesn't bode well for > ease in debugging and code maintenance down the road... Well, dpb, I figure that bugs are only as bad as wasps, and when I'm getting my first number, I'm gonna get stung a couple times. I'm aware that implicit none enforces strict typing, and have been so demonstrably for twenty years. I won't back off the fact that the ultimate calculation is a real. That might have been a good comment to add at the git-go. I'd rather talk about subsequent versions of this program: $ pwd /home/dan/source/fortran_stuff $ ls b.f90 directory.mod dw3.f90 fortran_resources.pdf m3.f90 m3.f90~ out $ gfortran -Wall -Wextra m3.f90 -o out $ ./out ernest 1.00000000 2.0000000 parent: forest_root children: douglas helen douglas 6.0000000 7.0000000 parent: ernest helen 3.0000000 4.0000000 5.0000000 parent: ernest children: john john 8.0000000 parent: helen ernest 1.00000000 2.0000000 parent: forest_root children: douglas helen douglas 6.0000000 7.0000000 parent: ernest helen 3.0000000 4.0000000 5.0000000 parent: ernest children: betty john betty 9.0000000 10.0000000 parent: helen children: nigel peter ruth nigel 11.000000 parent: betty peter 12.000000 parent: betty ruth parent: betty john 8.0000000 parent: helen ernest 1.00000000 2.0000000 parent: forest_root children: douglas helen douglas 6.0000000 7.0000000 parent: ernest helen 3.0000000 4.0000000 5.0000000 parent: ernest children: betty betty 9.0000000 10.0000000 parent: helen children: nigel peter ruth nigel 11.000000 parent: betty peter 12.000000 parent: betty ruth parent: betty ernest 1.00000000 2.0000000 parent: forest_root children: douglas helen douglas 6.0000000 7.0000000 parent: ernest helen 3.0000000 4.0000000 5.0000000 parent: ernest children: john betty john 8.0000000 parent: helen betty 9.0000000 10.0000000 parent: helen children: nigel peter ruth nigel 11.000000 parent: betty peter 12.000000 parent: betty ruth parent: betty $ cat m3.f90 ! (c) Copyright Michael Metcalf and John Reid, 1992. This file may be ! freely used and copied for educational purposes provided this notice ! remains attached. Extracted from "Fortran 90 Explained" Oxford ! University Press (Oxford and New York), ISBN 0-19-853772-7. ! !A recurring problem in computing is the need to manipulate a linked !data structure. !This might be a simple linked list like the one encountered in Section !2.13, but often a more general tree structure is required. ! !The example in this Appendix consists of a module that establishes and !navigates one or more such trees, organized as a 'forest', and a short !test program for it. Here, each node is identified by a name and has !any number of children, any number of siblings, and (optionally) some !associated real data. Each root node is regarded as having a common !parent, the 'forest root' node, whose name is 'forest root'. Thus, !every node has a parent. The module provides facilities for adding a !named node to a specified parent, for enquiring about all the nodes !that are offspring of a specified node, for removing a tree or subtree, !and for performing I/O operations on a tree or subtree. ! !The user-callable interfaces are: ! !start: ! must be called to initialize a forest. !add_node: ! stores the data provided at the node whose parent is specified ! and sets up pointers to the parent and siblings (if any). !remove_node: ! deallocate all the storage occupied by a complete tree or ! subtree. !retrieve: ! retrieves the data stored at a specified node and the names of ! the parent and children. !dump_tree: ! write a complete tree or subtree. !restore_tree: ! read a complete tree or subtree. !finish: ! deallocate all the storage occupied by all the trees of the forest. ! module directory ! ! Strong typing imposed implicit none ! ! Only subroutine interfaces, the length of the character ! component, and the I/O unit number are public private public start, add_node, remove_node, retrieve, & dump_tree, restore_tree, finish ! ! Module constants character(*), parameter:: eot = 'End-of-Tree.....' integer, parameter, public :: unit = 4, & ! I/O unit number max_char = 16 ! length of character component ! ! Define the basic tree type type node character(max_char) :: name ! name of node real, pointer :: y(:) ! stored real data type(node), pointer :: parent ! parent node type(node), pointer :: sibling ! next sibling node type(node), pointer :: child ! first child node end type node ! ! Module variables type(node), pointer :: current ! current node type(node), pointer :: forest_root ! the root of the forest integer :: max_data ! max size of data array character(max_char), allocatable, target :: names(:) ! for returning list of names ! The module procedures contains subroutine start ! Initialize the tree. allocate (forest_root) current => forest_root forest_root%name = 'forest_root' nullify(forest_root%parent, forest_root%sibling, forest_root%child) allocate(forest_root%y(0)) max_data = 0 allocate (names(0)) end subroutine start subroutine find(name) character(*), intent(in) :: name ! Make the module variable current point to the node with given name, ! or be null if the name is not there. type(node), pointer :: root ! For efficiency, we search the tree rooted at current, and if this ! fails try its parent and so on until the forest root is reached. if (associated(current)) then root => current nullify (current) else root => forest_root end if do call look(root) if (associated(current)) return root => root%parent if (.not.associated(root)) exit end do contains recursive subroutine look(root) type(node), pointer :: root ! Look for name in the tree rooted at root. If found, make the ! module variable current point to the node type(node), pointer :: child ! if (root%name == name) then current => root else child => root%child do if (.not.associated(child)) exit call look(child) if (associated(current)) return child => child%sibling end do end if end subroutine look end subroutine find subroutine add_node(name, name_of_parent, data) character(*), intent(in) :: name, name_of_parent ! For a root, name = '' real, intent(in), optional :: data(:) ! Allocate a new tree node of type node, store the given name and ! data there, set pointers to the parent and to its next sibling ! (if any). If the parent is not found, the new node is treated as ! a root. It is assumed that the node is not already present in the ! forest. type(node), pointer :: new_node ! allocate (new_node) new_node%name = name if (present(data)) then allocate(new_node%y(size(data))) new_node%y = data max_data = max(max_data, size(data)) else allocate(new_node%y(0)) end if ! ! If name of parent is not null, search for it. If not found, print message. if (name_of_parent == '') then current => forest_root else call find (name_of_parent) if (.not.associated(current)) then print *, 'no parent ', name_of_parent, ' found for ', name current => forest_root end if end if new_node%parent => current new_node%sibling => current%child current%child => new_node nullify(new_node%child) end subroutine add_node subroutine remove_node(name) character(*), intent(in) :: name ! Remove node and the subtree rooted on it (if any), ! deallocating associated pointer targets. type(node), pointer :: parent, child, sibling ! call find (name) if (associated(current)) then parent => current%parent child => parent%child if (.not.associated(child, current)) then ! Make it the first child, looping through the siblings to find it ! and resetting the links parent%child => current sibling => child do if (associated (sibling%sibling, current)) exit sibling => sibling%sibling end do sibling%sibling => current%sibling current%sibling => child end if call remove(current) end if end subroutine remove_node recursive subroutine remove (old_node) ! Remove a first child node and the subtree rooted on it (if any), ! deallocating associated pointer targets. type(node), pointer :: old_node type(node), pointer :: child, sibling ! child => old_node%child do if (.not.associated(child)) exit sibling => child%sibling call remove(child) child => sibling end do ! remove leaf node if (associated(old_node%parent)) old_node%parent%child => old_node%sibling deallocate (old_node%y) deallocate (old_node) end subroutine remove subroutine retrieve(name, data, parent, children) character(*), intent(in) :: name real, pointer :: data(:) character(max_char), intent(out) :: parent character(max_char), pointer :: children(:) ! Returns a pointer to the data at the node, the name of the ! parent, and a pointer to the names of the children. integer count, i type(node), pointer :: child ! call find (name) if (associated(current)) then data => current%y parent = current%parent%name ! count the number of children count = 0 child => current%child do if (.not.associated(child)) exit count = count + 1 child => child%sibling end do deallocate (names) allocate (names(count)) ! and store their names children => names child => current%child do i = 1, count children(i) = child%name child => child%sibling end do else nullify(data) parent = '' nullify(children) end if end subroutine retrieve subroutine dump_tree(root) character(*), intent(in) :: root ! Write out a complete tree followed by an end-of-tree record ! unformatted on the file unit. call find (root) if (associated(current)) then call out(current) end if write(unit) eot, 0, eot contains recursive subroutine out(root) ! Traverse a complete tree or subtree, writing out its contents type(node), intent(in) :: root ! root node of tree ! Local variable type(node), pointer :: child ! write(unit) root%name, size(root%y), root%y, root%parent%name child => root%child do if (.not.associated(child)) exit call out (child) child => child%sibling end do end subroutine out end subroutine dump_tree subroutine restore_tree ! Reads a subtree unformatted from the file unit. character(max_char) :: name integer length_y real, allocatable :: y(:) character(max_char) :: name_of_parent ! allocate(y(max_data)) do read (unit) name, length_y, y(:length_y), name_of_parent if (name == eot) exit call add_node( name, name_of_parent, y(:length_y) ) end do deallocate(y) end subroutine restore_tree subroutine finish ! Deallocate all allocated targets. call remove (forest_root) deallocate(names) end subroutine finish end module directory program test use directory implicit none ! ! Initialize a tree call start ! Fill it with some data call add_node('ernest','',(/1.,2./)) call add_node('helen','ernest',(/3.,4.,5./)) call add_node('douglas','ernest',(/6.,7./)) call add_node('john','helen',(/8./)) call add_node('betty','helen',(/9.,10./)) call add_node('nigel','betty',(/11./)) call add_node('peter','betty',(/12./)) call add_node('ruth','betty') ! Manipulate subtrees open(unit, form='unformatted', status='scratch') call dump_tree('betty') call remove_node('betty') write(*,*); call print_tree('ernest') rewind unit call restore_tree rewind unit write(*,*); call print_tree('ernest') call dump_tree('john') call remove_node('john') write(*,*); call print_tree('ernest') rewind unit call restore_tree write(*,*); call print_tree('ernest') ! Return storage call finish contains recursive subroutine print_tree(name) ! To print the data contained in a subtree character(*) :: name integer i real, pointer :: data(:) character(max_char) parent, self character(max_char), pointer :: children(:) character(max_char), allocatable :: siblings(:) ! call retrieve(name, data, parent, children) if (.not.associated(data)) return self = name; write(*,*) self, data write(*,*) ' parent: ', parent if (size(children) > 0 ) write(*,*) ' children: ', children allocate(siblings(size(children))) siblings = children do i = 1, size(children) call print_tree(siblings(i)) end do end subroutine print_tree end program test ! gfortran -Wall -Wextra m3.f90 -o out $ So, how do I populate nodes with a room? -- Uno
From: Richard Maine on 26 Apr 2010 02:43
Uno <merrilljensen(a)q.com> wrote: > dpb wrote: > > You seem oblivious to the underlying issues raised re: IMPLICIT NONE .... > I'm aware that implicit none enforces strict typing, Actually, no, that is *NOT* the point being made. If that's what you think it is about, then you are still missing it. The type aspect is one part, but in many ways not the most important part. As Louis said >>> The whole idea behind 'implicit none' is to force you to declare >>> variables so that if you misspell something, the compiler catches it >>> for you: and as I tried to elaborate >>> I don't think you understood Louis's comment - or my prior one. The >>> problem Louis refers to applies to *ANY* implicit typing. Having all >>> the types be real lowers the chance of being confused about what >>> type something is, but it does *NOTHING* to avoid the problem that >>> Louis refers to or many others of its ilk. but the message doesn't appear to be getting through. The most important part about implicit none for the current purposes is *NOT* that it makes you declare what type each variable is. Yes, implicit none does that, but that's not the most important part here. The important part is that implicit none makes you declare what names you are using for variables. That is what helps avoid the typographical errors. It is perhaps unfortunate coincidence of terms that a "typing error" could refer either to an error relating to data type or a typographical error. Those are entirely unrelated problems, except that the same words can be used in both contexts and implicit none can relate to both. But the errors I am talking about are of the typographical variety, which has nothing to do with strict typing. -- Richard Maine | Good judgment comes from experience; email: last name at domain . net | experience comes from bad judgment. domain: summertriangle | -- Mark Twain |