Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Getting values from second to last loop of a -while- loop

    Hi fellow Statalisters,

    I am using a -while- loop for a particular application, where I need to retrieve a particular value from the second to the last loop.

    In the fictitious example below, the -while- loop will end when it `n' either equals or surpasses `N' = 400 on the last loop. I need to retrieve the values of `n' and `i', not on the last loop (where `n' may be greater than `N') but on the loop previous, where `n' is just below `N', or equal to `N'.

    In my application, `n' is not linear or incremental, so it is likely that the last loop will almost always produce an `n' that is greater than `N'

    I hope I have stated my problem clearly enough.

    Thanks in advance!

    Ariel

    Code:
    local N = 400
    local i = 0.01
    local p = 0.20
    
    while `n' <= `N' {
    
        local n1 = "something" + invnorm(`i')
        local n = ceil(`n1' / `p')
    
        local i = `i' + 0.01
        if `i' == 1 exit
    }
    
    di "`n'"
    di "`i'"

  • #2
    I think this version is probably greatly simplifying what is happening with "something" in n1, but recording the n and i values before updating them should generally work to get what you want.
    Code:
    local N = 400
    local i = 0.01
    local p = 0.20
    
    **create a starting value for n and "something"
    **note that adding to a string "something" isn't valid code so make this a macro
    local n=1
    local something=2
    
    **for display purposes create a loop count
    local loopn=1
    
    while `n' <= `N' {    
        **before n or i get modified record their values
        local ln=`n'
        local li=`i'
    
        local n1 = `something' + invnorm(`i')
        local n = ceil(`n1' / `p')
    
        local i = `i' + 0.01
        
        **display values current values then iterate the loop count (remove these two lines from final code)
        display "loop `loopn' n=`n' i=`i'"
        local ++loopn
        
        if `i' == 1 exit
    }
    
    di "`n'"
    di "`i'"
    di "`ln'"
    di "`li'"

    Comment


    • #3
      Code:
      local N = 400
      local i = 0.01
      local p = 0.20
      
      local n = 0
      while `n' <= `N' {
      
          local n1 = "something" + invnorm(`i')
          local prev_n `n'
          local n = ceil(`n1' / `p')
          local prev_i `i'
          local i = `i' + 0.01
          if `i' == 1 exit
      }
      
      di  `prev_n'
      di  `prev_i'
      Added: I would not use the final -if `i' == 1 exit- as a way of breaking out of the loop if you do not succeed with `n' > `N" by then. The reason is that floating point arithmetic is inexact. The number 0.01 has no exact finite-precision representation in binary (just as 1/3 has no finite-precision exact representation in decimal). Thus it is entirely possible that when you add 0.01 repeatedly, you might never land exactly on 1. (In fact, in this example, I think you do, but that is just luck that you cannot, in general, count on when writing code.) A safer way to do this is:

      Code:
      local N = 400
      local i = 1
      local p = 0.20
      
      local n = 0
      while `n' <= `N'  & `i' < 100 {
      
          local n1 = "something" + invnorm(`i'/100)
          local prev_n `n'
          local n = ceil(`n1' / `p')
          local prev_i `i'
          local ++i
      }
      
      di  `prev_n'
      di  `prev_i'
      This relies exclusively on integer arithmetic to iterate i, and you will not have to worry about floating point rounding errors.
      Last edited by Clyde Schechter; 09 Aug 2022, 17:26.

      Comment


      • #4
        Thank you Sarah and Clyde!

        This code is extremely helpful!

        Clyde, your additional comment about `i' is very thoughtful! That issue did not occur to me...

        Thank you again!

        Ariel

        Comment

        Working...
        X