Announcement

Collapse
No announcement yet.

gremlins

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • gremlins

    Hi all,

    I need help with a small piece of code ...

    Code:
    #COMPILE EXE
    #DIM ALL
    
    
    FUNCTION GetChiPValue(BYVAL X AS EXT, BYVAL F AS EXT) AS EXT
    '
    ' FUNCTION PCHI2 - CALCULATES THE P-VALUE FROM
    ' THE CHI-SQUARE VALUE AND THE DEGREES OF FREEDOM
    ' The probability is calculated using series expansion 26.4.6. For the
    ' gamma functions 6.1.12, 6.1.8 and 6.1.1 are used.
    ' In: Handbook of mathematical Functions. Editors: Abramowitz M & Stegun IA,
    ' Dover, New York, 1972.
    ' Original code by Erik Christensen
            LOCAL D##,E##,R##,G##,H##,SL##,S##,T##,P##,C##,SK##,Q##
            Q = 1
            IF X = 0 OR F = 0 THEN GOTO 26
            D = F : E = D / 2 : R = F - INT(F / 2) * 2
            G = 1
            IF R > .3 THEN GOTO 20
        19  E = E - 1
            IF E < 1.8 THEN GOTO 22
            G = G * E : GOTO 19
        20  G = SQR(ATN(1) * 4) ' = PI
        21  E = E - 1
            IF E < .3 THEN GOTO 22
            G = G * E: GOTO 21
        22  H = ((X / 2) ^ (D / 2) * EXP(-X / 2)) / (X * G)
            SL = H * 2 * X / D : S = 0 : T = 0 : P = 1
        23  D = D + 2 : P = P * X / D : S = S + P : C = ABS(S - T)
            IF C < 1E-16 THEN GOTO 24
            T = S : GOTO 23
        24  SK = (S + 1) * SL : Q = 1 - SK
        25  IF Q < 1E-16 THEN Q = 1E-16
        26  FUNCTION = Q
    
    END FUNCTION
    
    
    FUNCTION PBMAIN () AS LONG
        LOCAL xxx AS EXT
        xxx = GetChiPValue(4.605, 2)
        MSGBOX( FORMAT$( xxx, "0.000000000000000000000000000" ) )
    END FUNCTION
    If I compile and execute the above code, the message box pops up with the (wrong) answer 0.000000000000000100000001686.

    If I compile and DEBUG the above code and then run it in debug mode I get a different (!) answer (the right one): 0.100008508707700254000000000.

    Am I the only one whose getting this kind of behaviour?

    Cheers,

    Alan.

  • #2
    After modifying to cc404, I tried your code otherwise as-is. Same results.

    Replaced FORMAT$ with USING$ and still got the same results. Hmmmmm.....

    Don't have a clue.
    There are no atheists in a fox hole or the morning of a math test.
    If my flag offends you, I'll help you pack.

    Comment


    • #3
      #Register None

      Alan,

      Add

      Code:
      #Register None
      This can go in the function GetChiPValue or at the top of the app.


      Originally posted by Alan Vella View Post
      Hi all,


      If I compile and execute the above code, the message box pops up with the (wrong) answer 0.000000000000000100000001686.

      If I compile and DEBUG the above code and then run it in debug mode I get a different (!) answer (the right one): 0.100008508707700254000000000.

      Am I the only one whose getting this kind of behaviour?

      Cheers,

      Alan.
      Last edited by Brian Chirgwin; 21 Jan 2009, 02:28 PM. Reason: shorted Alan's quote

      Comment


      • #4
        OK, now if I add another procedure like this:

        Code:
        #COMPILE EXE
        #DIM ALL
        
        
        SUB myProc(BYVAL str AS STRING)
            MSGBOX str
        END SUB
        
        
        FUNCTION GetChiPValue(BYVAL X AS EXT, BYVAL F AS EXT) AS EXT
        '
        ' FUNCTION PCHI2 - CALCULATES THE P-VALUE FROM
        ' THE CHI-SQUARE VALUE AND THE DEGREES OF FREEDOM
        ' The probability is calculated using series expansion 26.4.6. For the
        ' gamma functions 6.1.12, 6.1.8 and 6.1.1 are used.
        ' In: Handbook of mathematical Functions. Editors: Abramowitz M & Stegun IA,
        ' Dover, New York, 1972.
        ' Original code by Erik Christensen
                LOCAL D##,E##,R##,G##,H##,SL##,S##,T##,P##,C##,SK##,Q##
                Q = 1
                IF X = 0 OR F = 0 THEN GOTO 26
                D = F : E = D / 2 : R = F - INT(F / 2) * 2
                G = 1
                IF R > .3 THEN GOTO 20
            19  E = E - 1
                IF E < 1.8 THEN GOTO 22
                G = G * E : GOTO 19
            20  G = SQR(ATN(1) * 4) ' = PI
            21  E = E - 1
                IF E < .3 THEN GOTO 22
                G = G * E: GOTO 21
            22  H = ((X / 2) ^ (D / 2) * EXP(-X / 2)) / (X * G)
                SL = H * 2 * X / D : S = 0 : T = 0 : P = 1
            23  D = D + 2 : P = P * X / D : S = S + P : C = ABS(S - T)
                IF C < 1E-16 THEN GOTO 24
                T = S : GOTO 23
            24  SK = (S + 1) * SL : Q = 1 - SK
            25  IF Q < 1E-16 THEN Q = 1E-16
                myProc(STR$(q))
            26  FUNCTION = Q
        
        END FUNCTION
        
        
        FUNCTION PBMAIN () AS LONG
            LOCAL xxx AS EXT
            xxx = GetChiPValue(4.605, 2)
            MSGBOX( FORMAT$( xxx, "0.000000000000000000000000000" ) )
        END FUNCTION
        Running the above will give you the write answer in the two message boxes (the one in myProc and the one in pbMain).

        If however I comment the line

        Code:
        myProc(STR$(q))
        in myProc and re-run it I get the different answer in the message box from pbMain.

        I've using PB for the past two years for my PhD research work and I've seen this behaviour before. Would appreciate it alot if someone could shed some light on this.

        Comment


        • #5
          Solution

          Hi Alan;

          The problem with your second example is LOCAL variables are cleared when the function or sub they reside in are exited. The solution is to declare the variables as STATIC, STATIC variables are not cleared when a sub or function is exited.

          Code:
          'Change this:
          LOCAL D##,E##,R##,G##,H##,SL##,S##,T##,P##,C##,SK##,Q##
          
          'To this:
          STATIC D##,E##,R##,G##,H##,SL##,S##,T##,P##,C##,SK##,Q##
          Last edited by Walt Thompson; 21 Jan 2009, 04:44 PM. Reason: Correct spelling

          Comment


          • #6
            The OPs code is very typical of things I do. Though I haven't seen any weirdness recently, I may have had a similar problem in the past. I'd really like to know what's going on so I can avoid it, assuming it's some easily understood construct. I'd love to see a comment by PB staff, who understand what's going on under the hood.

            Comment


            • #7
              Good catch, Alan. Thanks for reporting it. Actually, this is a very rare issue which seems to have been around for many years. But it occurred so infrequently that we've never had a report.

              For those who may be interested in the specific circumstances, here's how the planets aligned to cause it: Your line 22 with the EXP() function is the culprit. PowerBASIC is very good at rearranging an expression to simplify it and minimize the number of temporary values stored... but some are alway needed. At the EXP(), there are 2 temps plus the argument to EXP(). That makes 3. The EXP() function needs 2 more, and then there are 4 register variables for a total of nine. Unfortunately, the FPU has just eight registers, not nine, and it overflows at run-time The compiler should have generated an error during compilation, but its internal data showed that EXP() needed 1 temp, not 2. We've corrected it now, and it will be just fine in the next PBWIN 9.01 update. Yes, very soon.

              For now, you can simplify the noted expression, or add a #REGISTER NONE directive to disable allocation of register variables. Sorry you had a problem.

              Best regards,

              Bob Zale
              PowerBASIC Inc.

              Comment


              • #8
                Thanks all for your super-quick replies.

                I think I'll just include the #REGISTER NONE at the top of my code and register the variables manually.

                While we're on the the topic of registered variables I have one quick question: If I register two integer variables in a procedure A, then call procedure B from procedure A and register another two integer variables in procedure B ... will they not be registered since I have already used my maximum of two integer register variables in procedure A?

                Comment


                • #9
                  From PB/WIN 9 Help:

                  Register variables are always local to the procedure where they appear.
                  Basically you get a brand new set of registers for each call to a procedure, excluding the 3 (IIRC) registers used internally by PowerBASIC.
                  kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

                  Comment


                  • #10
                    Thanks Bob! I fooled with that example for quite a while before giving up. FWIW, I went back to some very old code I remembered having a similar problem with. As usual, no problem with PB and no use of EXP, I did however find a plain old programmers typo I never noticed before.

                    Comment

                    Working...
                    X