Announcement

Collapse
No announcement yet.

Newbie questions

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

  • Newbie questions

    I'm new to the PowerBASIC world, but (years ago) I used to do some Pascal programming. I'm trying to get back into the swing of things, but stumbling on some of the basic aspects of the language. For example, I'm not having much luck implementing a function like this:

    (*-----------------------------------------------------------------------*)
    (* ATN2: arctangent of y/x for two arguments *)
    (* (correct quadrant; -180 deg <= ATN2 <= +180 deg) *)
    (*-----------------------------------------------------------------------*)
    FUNCTION ATN2(Y,X:REAL):REAL;
    CONST RAD=0.0174532925199433;
    VAR AX,AY,PHI: REAL;
    BEGIN
    IF (X=0.0) AND (Y=0.0)
    THEN ATN2:=0.0
    ELSE
    BEGIN
    AX:=ABS(X); AY:=ABS(Y);
    IF (AX>AY)
    THEN PHI:=ARCTAN(AY/AX)/RAD
    ELSE PHI:=90.0-ARCTAN(AX/AY)/RAD;
    IF (X<0.0) THEN PHI:=180.0-PHI;
    IF (Y<0.0) THEN PHI:=-PHI;
    ATN2:=PHI;
    END;
    END;

    Worse, I have some mathematical functions like this that used Assembler (under Virtual Pascal), and I couldn't get those to operate, either.

    I think I'm just missing something fundamental in the constructs, but I'd appreciate any pointers.

    Best,

    Frank

  • #2
    Hi,

    raw, unoptimized translation of your code could look like this:
    Code:
    '(*-----------------------------------------------------------------------*)
    '(* ATN2: arctangent of y/x for two arguments *)
    '(* (correct quadrant; -180 deg <= ATN2 <= +180 deg) *)
    '(*-----------------------------------------------------------------------*)
    MACRO RadiansToDegrees(dpRadians) = (dpRadians*57.29577951308232##)
    
    FUNCTION ATN2( y AS EXT, x AS EXT) AS EXT
      
      LOCAL ax, ay, phi AS EXT
    
      IF x = 0.0 AND y = 0.0 THEN
    
        FUNCTION = 0
    
      ELSE
    
        ax = ABS(x)
        ay = ABS(y)
        IF ax > ay THEN
          phi = RadiansToDegrees( ATN(ay/ax) )
        ELSE
          phi = 90.0 - RadiansToDegrees( ATN(ax/ay) )
        END IF
        
        IF x < 0.0 THEN phi = 180 - phi
        IF y < 0.0 THEN phi = -phi
      
        FUNCTION = phi
    
      END IF
    
    END FUNCTION
    EXT or EXTENDED is the most precise floating point datatype in PowerBasic.
    As you can see PB does not use any general BEGIN/END or semicolons.

    Only "scary" function in my sample is MACRO - think of it as text substitution engine. This way you can use it as function in code ( looks clean ), but in fact it converts:
    Code:
    phi = RadiansToDegrees( ATN(ay/ax) )
    to:
    Code:
    phi = (ATN(ay/ax) * 57.29577951308232##)
    ## symbols on the end force compiler to use EXTENDED precision for work with the number.


    Hope it helps,
    Petr
    Last edited by Petr Schreiber jr; 26 Nov 2007, 01:41 PM.
    [email protected]

    Comment


    • #3
      Many thanks. I think I see what I was doing wrong.

      Frank

      Comment


      • #4
        Okay, now the trickier stuff. Here's an old Virtual Pascal routine:

        FUNCTION ArcTan2(Y,X: REAL): REAL; ASSEMBLER;
        ASM fld Y
        fld X
        fpatan
        END; { ArcTan2. }

        Can someone show me how this would work in PowerBASIC?

        Thanks for the handholding.

        Frank

        Comment


        • #5
          I've not had asm need for floating point, but based on your code and some posts and your code, might be similar to this:
          Code:
          FUNCTION ArcTan2(BYVAL Y AS SINGLE,BYVAL X AS SINGLE)AS SINGLE
              ! emms             ;no MMX while FP used 
              ! fld Y
              ! fld X
              ! fpatan
              ! fstp Y
              FUNCTION = Y
          END FUNCTION
          Maybe Bob, Hutch, Paul or another FP assembler user can beat this code or point out any error.
          Rick Angell

          Comment


          • #6
            The FPATAN instruction returns the angle between the X axis and the line from the origin to the point (X,Y), where Y (the ordinate) is ST(1) and X (the abscissa) is ST(0). The angle depends on the sign of X and Y independently, not just on the sign of the ratio Y/X. This is because a point (-X,Y) is in the second quadrant, resulting in an angle between pi/2 and pi, while a point (X,-Y) is in the fourth quadrant, resulting in an angle between 0 and pi/2. A point (-X,-Y) is in the third quadrant, giving an angle between -pi/2 and -pi.
            Code:
            FUNCTION Atan2 (X, Y) 
            
              v1 =  Y/X
              A1 =  ATN(v1) 
              s  =  SGN(Y)
            
              FUNCTION = ABS(A1) * s
            END FUNCTION
            ????

            (May need special handling when Y=0 ???)
            Michael Mattias
            Tal Systems Inc. (retired)
            Racine WI USA
            [email protected]
            http://www.talsystems.com

            Comment


            • #7
              Actually, Michael, your formula is not returning the correct angle in the quadrants (radians or angles). The assembler version does. Here's a quick compare to try with coordinate pairs like (45,45),(45,-45),(-45,-45) and (-45,45) or could use the same absolute values for X and Y, e.g. 10,10 with the signs as noted. So we can quickly see the angular displacement from the X axis counter clockwise for 45,135,225,315 degrees in each quadrant. In the assembler version the function handles quadrants correctly observing "The angle depends on the sign of X and Y independently, not just on the sign of the ratio Y/X." and not on the sign of Y either. So it returns the corrected radian value as a posative or negative radian value from 0.

              Code:
              #COMPILE EXE
              #DIM ALL
              MACRO RadiansToDegrees(dpRadians) = (dpRadians*57.29577951308232##)
              
              FUNCTION Atan2 (BYVAL Y AS SINGLE,BYVAL X AS SINGLE)AS SINGLE
                LOCAL v1,A1 AS SINGLE
                LOCAL s AS LONG
                v1 =  Y/X
                A1 =  ATN(v1)
                s  =  SGN(Y)
                FUNCTION = ABS(A1) * s
              END FUNCTION
              
              FUNCTION ArcTan2(BYVAL Y AS SINGLE,BYVAL X AS SINGLE)AS SINGLE
                  ! emms
                  ! fld Y
                  ! fld X
                  ! fpatan
                  ! fstp Y
                  FUNCTION = Y
              END FUNCTION
              
              FUNCTION PBMAIN () AS LONG
                  LOCAL y,x,theta AS SINGLE,answer AS STRING
              repeat:
                  ? ""
                  INPUT "enter the ordinate,abcissa: " ,y,x
                  theta = RadiansToDegrees(ArcTan2(y,x))
                  IF SGN(theta) = -1  THEN theta = 360 +theta
                  ? "ArcTan2 result: "+FORMAT$(ArcTan2(y,x)),theta
                  theta = RadiansToDegrees(Atan2(y,x))
                  IF SGN(theta) = -1  THEN theta = 360 +theta
                  ? "Atan2   result: "+FORMAT$(Atan2(y,x)),theta
                  ? ""
                  ? "press q to quit or another key to continue ...
                  answer$ = WAITKEY$
                  IF LCASE$(answer$) <> "q" THEN GOTO repeat
              
              END FUNCTION
              Last edited by Richard Angell; 27 Nov 2007, 10:23 AM. Reason: edits
              Rick Angell

              Comment


              • #8
                I was guessing. But I'm sure someone could tweak that suggestion to make it right.

                But of course, you knew I would suggest "something" because this thread hits not one (1), but two (2) of my "hot button don't do that" topics:

                1. Trying to do verb-for-verb, function-for-function ports of software. (In this case, Pascal==> BASIC)

                2. Using assembly language when the compiler provides sufficient intrinsic functions to get the job done... perhaps in this case to replace intrinsic functions not available in the Pascal Compiler.

                That is, converting from one language to another should not be a 'hardware' or 'software' thing so much as it should be a 'wetware' thing. (Wetware= that stuff between your ears).

                MCM
                Michael Mattias
                Tal Systems Inc. (retired)
                Racine WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  Maybe something along these lines, mght be simpler ... but hey I put something into similar macro a long time ago and don't use them everyday either. Result is in radians.
                  Code:
                  MACRO Pi = 3.141592653589793## 
                  FUNCTION Atan2 (BYVAL Y AS SINGLE,BYVAL X AS SINGLE)AS SINGLE
                    LOCAL v1 AS SINGLE
                    LOCAL A1 AS EXTENDED
                    LOCAL sy,sx,quadrant AS LONG
                    sy  =  SGN(Y)
                    sx  =  SGN(X)
                    v1 =  Y/X
                    A1 =  ATN(v1)
                    SELECT CASE sx
                        CASE -1
                            IF sy = -1 THEN
                                A1 = -pi + A1
                            ELSEIF sy = 0 THEN
                                A1 = pi
                            ELSEIF sy = 1 THEN
                                A1 = pi + A1
                            END IF
                        CASE 0
                            IF sy = -1 THEN
                                A1 = pi + (pi/2)
                            ELSEIF sy = 0 THEN
                                A1 = 0
                            ELSEIF sy = 1 THEN
                                A1 = pi/2
                            END IF
                    END SELECT
                    FUNCTION = A1
                  END FUNCTION
                  Rick Angell

                  Comment


                  • #10
                    Michael:

                    I understand your hot buttons, and I'm not trying to do direct Pascal to Basic conversions, just trying to reboot from one, half-forgotten way of doing things to another. I thought I'd start with the math library.

                    As for the Assembler, hey, I have an entire math unit, mostly in ASM, that provides many functions that didn't exist in Pascal and don't natively exist in PowerBASIC. If most of the work is done in ASM, and it can be made to work in PB with little fuss, why not? Granted, though, this won't always be possible for me.

                    Richard:

                    Thanks so much for your responses and code.

                    Comment


                    • #11
                      It's not clear to me why PB/CC 4.04 gives the following results with FORMAT$ and STR$:

                      Code:
                      3.1415926535897932384626 = Pi
                      3.14159265358979         = Variable set to above, no formal formatting
                      3.14159265358979312      = Displayed through FORMAT$(a,18)
                      3.14159265358979312      = Displayed through STR$(a,18)
                      As displayed by FORMAT$ and STR$, shouldn't the last pair of digits be 23 (if truncated) or 24 (if rounded) rather than 12 that's actually displayed?

                      Frank

                      Code:
                      #COMPILE EXE
                      #DIM ALL
                      
                      FUNCTION PBMAIN () AS LONG
                      LOCAL a AS EXT
                      
                      a=3.1415926535897932384626
                                
                      PRINT " 3.1415926535897932384626 = Pi"
                      PRINT a "        = Variable set to above, no formal formatting"
                      
                      PRINT " " + FORMAT$(a,18) + "      = Displayed through FORMAT$(a,18)"
                      PRINT STR$(a,18) + "      = Displayed through STR$(a,18)"
                      WAITKEY$
                      
                      END FUNCTION
                      Last edited by Francis Reddy; 4 Dec 2007, 07:49 AM.

                      Comment


                      • #12
                        Count digits. Compare with documented limits. Your question will answer itself.

                        Also refer to the documentation on assigning numeric literals. Ok, so that's really hard to find. Suffice it to say there is a difference between:

                        a=3.1415926535897932384626!
                        and
                        a=3.1415926535897932384626#
                        and
                        a=3.1415926535897932384626##

                        MCM
                        Michael Mattias
                        Tal Systems Inc. (retired)
                        Racine WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          Michael:

                          The only variable is defined as EXT, so I don't see how differences between single, double, and extended precision apply here, unless there are differences in the way over-precise values are handled (which I did not see in the help).

                          According to the documentation under single precision, a too-precise value is supposed to be rounded. Altering 3.14...3238 to 3.14...312 doesn't seem to follow that rule, whereas 3.14...324 would. If you're rounding, why change the next to last digit?

                          Comment


                          • #14
                            Chapter 3, Data Types
                            Check under the heading "Numeric Literals". Page 108 in the hard copy.
                            Rod
                            I want not 'not', not Knot, not Knott, not Nott, not knot, not naught, not nought, but aught.

                            Comment


                            • #15
                              Extended-precision values require 10 bytes of storage each. They have a range of approximately +/- 3.4x10^-4932 to 1.2x10^4932, and offer 18 digits of precision. All 18 digits can be "displayed" using the extended STR$ format (eg, STR$(var##,18)).
                              How many digits in "3.1415926535897932384626?"

                              How does that number compare to the documented limit for signficant digits for data type EXT?
                              Michael Mattias
                              Tal Systems Inc. (retired)
                              Racine WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                Actually, the best way of storing Pi in extended precision is doing like this:

                                Pi## = 4*ATN(1)

                                Because although not more than 18 significant digits can be printed and read, at least 19 significant digits are stored in memory and used in calculations in the 10 bytes extended precision format.

                                Want to check it ?
                                Code:
                                DEFEXT A-Z
                                FUNCTION PBMAIN()
                                   PI=4*ATN(1)  '.......   PI = 3.14159265358979323846....  21 digits
                                   PRINT STR$(Pi,18) '...output 3.14159265358979324     18 digits printed
                                   Pidec=PI*10-31
                                   PRINT STR$(Pidec, 18) '.. outp .415926535897932385 two more digits recovered 
                                   WAITKEY$
                                END FUNCTION
                                Regards
                                Aldo
                                Last edited by Aldo Vitagliano; 5 Dec 2007, 08:21 AM. Reason: comment additions to code
                                Aldo Vitagliano
                                alvitagl at unina it

                                Comment


                                • #17
                                  First of all, we must acknowledge the fact that digital computers cannot natively represent real numbers such as pi or e. By truncating such numbers to an arbitrary precision, we can only represent a real number in terms of a rational approximation.

                                  In calculus, the student will see that an irrational number exists only as the limit of the sequence of its rational approximations.


                                  PowerBASIC compilers have chosen to represent real numbers in terms of the PC's internal representation of single, double and extended-precision approximations.

                                  Consider an extension to the above program by:
                                  Code:
                                  #COMPILE EXE
                                  #DIM ALL
                                   
                                  FUNCTION PBMAIN () AS LONG
                                  LOCAL a,b,c AS EXT
                                   
                                  '-------------------------------------------------------------
                                  PRINT "'--- Part 1 is the original program"
                                  PRINT "'    It shows that the ""closest"" precise value of pi"
                                  PRINT "'    should be 3.14159265358979323##,
                                  PRINT "'    yet it prints as 3.14159265358979312
                                  PRINT "'    a difference of 0.00000 00000 00000 11
                                   
                                  a=3.1415926535897932384626##
                                   
                                  PRINT " 3.1415926535897932384626 = Pi"
                                  PRINT a "        = Variable set to above, no formal formatting"
                                   
                                  PRINT " " + FORMAT$(a,18) + "      = Displayed through FORMAT$(a,18)"
                                  PRINT STR$(a,18) + "      = Displayed through STR$(a,18)"
                                   
                                  PRINT:PRINT
                                   
                                  '-------------------------------------------------------------
                                  PRINT "'--- Part 2 is a modified version of Part 1
                                  PRINT "'    obtained by trial and error by incrementing
                                  PRINT "'    3.14159265358979312 by 0.00000 00000 00000 01
                                  PRINT "'    until the printed version is greater than 3.14159265358979312.
                                  PRINT "'    This value is 3.14159265358979334
                                  PRINT "'    a difference of 0.00000 00000 00000 22
                                   
                                  b=3.14159265358979333##     ' 18 digits
                                   
                                  PRINT " 3.14159265358979311      = Pi"
                                  PRINT b "        = Variable set to above, no formal formatting"
                                   
                                  PRINT " " + FORMAT$(b,18) + "      = Displayed through FORMAT$(b,18)"
                                  PRINT STR$(b,18) + "      = Displayed through STR$(b,18)"
                                   
                                  PRINT:PRINT
                                   
                                  '-------------------------------------------------------------
                                  PRINT "'--- Part 3 is a modified version of Part 1
                                  PRINT "'    obtained by trial and error by decrementing
                                  PRINT "'    3.14159265358979312 by 0.00000 00000 00000 01
                                  PRINT "'    until the printed version is less than 3.14159265358979312.
                                  PRINT "'    This value is 3.14159265358979279
                                  PRINT "'    a difference of 0.00000 00000 00000 33
                                   
                                  c=3.14159265358979289##     ' 18 digits
                                   
                                  PRINT " 3.14159265358979334      = Pi"
                                  PRINT c "        = Variable set to above, no formal formatting"
                                   
                                  PRINT " " + FORMAT$(c,18) + "      = Displayed through FORMAT$(c,18)"
                                  PRINT STR$(c,18) + "      = Displayed through STR$(c,18)"
                                   
                                  WAITKEY$
                                   
                                  END FUNCTION
                                  Code:
                                  '--- Part 1 is the original program
                                  '    It shows that the "closest" precise value of pi
                                  '    should be 3.14159265358979323##,
                                  '    yet it prints as 3.14159265358979312
                                  '    a difference of 0.00000 00000 00000 11
                                   3.1415926535897932384626 = Pi
                                   3.14159265358979         = Variable set to above, no formal formatting
                                   3.14159265358979312      = Displayed through FORMAT$(a,18)
                                   3.14159265358979312      = Displayed through STR$(a,18)
                                   
                                  '--- Part 2 is a modified version of Part 1
                                  '    obtained by trial and error by incrementing
                                  '    3.14159265358979312 by 0.00000 00000 00000 01
                                  '    until the printed version is greater than 3.14159265358979312.
                                  '    This value is 3.14159265358979334
                                  '    a difference of 0.00000 00000 00000 22
                                   3.14159265358979311      = Pi
                                   3.14159265358979         = Variable set to above, no formal formatting
                                   3.14159265358979312      = Displayed through FORMAT$(b,18)
                                   3.14159265358979312      = Displayed through STR$(b,18)
                                   
                                  '--- Part 3 is a modified version of Part 1
                                  '    obtained by trial and error by decrementing
                                  '    3.14159265358979312 by 0.00000 00000 00000 01
                                  '    until the printed version is less than 3.14159265358979312.
                                  '    This value is 3.14159265358979279
                                  '    a difference of 0.00000 00000 00000 33
                                   3.14159265358979324      = Pi
                                   3.14159265358979         = Variable set to above, no formal formatting
                                   3.14159265358979267      = Displayed through FORMAT$(c,18)
                                   3.14159265358979267      = Displayed through STR$(c,18)
                                  This program shows that the "true" value of pi is somewhere between 3.14159265358979279 and 3.14159265358979334, but cannot be represented exactly as 3.14159265358979324 in binary code, since floating-point is not represented internally as decimal. This is what we call "floating-point error."

                                  If you require greater precision than this, I suggest you look at
                                  Eddy Van Esch's HIME Huge Integer Math and Encryption library.
                                  Regards,
                                  Bob

                                  Comment


                                  • #18
                                    Aldo and Robert:

                                    Thank you both for the informative replies.

                                    Frank

                                    Comment


                                    • #19
                                      Francis,

                                      Use this calculator to see what happens

                                      IEEE-754 Floating-Point Conversion
                                      "The trouble with quotes on the Internet is that you can never know if they are genuine." - Abraham Lincoln.

                                      Comment


                                      • #20
                                        Thanks Arthur for the interesting link.
                                        However, the calculator does not support 80 bits Extended precision conversion.
                                        Aldo Vitagliano
                                        alvitagl at unina it

                                        Comment

                                        Working...
                                        X