Announcement

Collapse
No announcement yet.

VAL rounds a variable

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

  • #21
    If you study the ROUND function in the help file, you'll find that it does the job, even though it seems to be prone to giving misleading results. I too at one time was concerned about this issue, I delved into it and for whatever difference I could make, it wasn't worth the time, nor the programming overhead.
    Typing ROUND(var,x) was quicker all around and for all intents and purposes just as accurate. And an awful lot less head scratching.

    When you consider the fact that once you've rounded a number it is no longer accurate anyway, why worry about the accuracy of rounding, other than to give you a margin of error?

    Rod
    Rod
    In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

    Comment


    • #22
      Just for your information, I more accurately checked my roundUp function above for speed, and it is ~360 ticks on average. No speed demon for sure, but I have not been able to find any errors in it (yet) thru billions of loops, and that's priority 1.

      Comment


      • #23
        rounding info http://support.microsoft.com/kb/196652
        p purvis

        Comment


        • #24
          may have a winner on this one, needs testing

          Code:
          'compiled with pbcc 4.03
          'round.bas
          
          #COMPILE EXE
          #DIM ALL
          
          FUNCTION roundme(BYVAL X AS EXT, BYVAL Factor AS LONG) AS EXT
               IF FACTOR THEN
               FUNCTION=(FIX((X * 10^Factor) + (SGN(x)*(0.5))))*(1/10^factor)
               ELSE
               FUNCTION=FIX(x)+(FIX(((FRAC(X)+SGN(x)*(0.5)))))
               
               END IF
          END FUNCTION
          
          
          FUNCTION PBMAIN () AS LONG
          LOCAL MM AS STRING
          LOCAL M AS EXT
          LOCAL roundto AS LONG
          
          start:
          
          INPUT "input amount ",mm
          mm=TRIM$(mm)
          IF mm="" THEN EXIT FUNCTION
          INPUT "input no of decimals ",roundto
          
          M=VAL(MM)
          PRINT MM
          PRINT STR$(roundme(M,roundto))+"  rounded decmials"+STR$(roundto)
          PRINT
          GOTO start
          
          END FUNCTION
          Last edited by Paul Purvis; 15 Jun 2008, 06:40 PM.
          p purvis

          Comment


          • #25
            This is an old PBDOS function I used to use to round results to any value e,g, 2, 0.25, .3333333, -.01, -.0015, 25

            Code:
             
            FUNCTION Roundto(BYVAL Number!,BYVAL Rounding!) AS SINGLE
                     LOCAL Scalednumber???
                     IF Rounding!=0  THEN
                        FUNCTION=Number!
                     ELSE
                        Scalednumber???=INT(0.5+ABS(Number!)/Rounding!)
                        FUNCTION=SGN(Number!)*Rounding!*Scalednumber???
                     END IF
                 END FUNCTION
            I found it quite useful.
            Dave.

            You're never too old to learn something stupid.

            Comment


            • #26
              These are the two functions I use for such things. They are courtesy of a posting in Poffs by José.

              Code:
              FUNCTION truncate (BYVAL value AS EXT, BYVAL digits as ext) EXPORT AS EXT
                  if value = 0 then function = 0 : exit function
                  function = value
                  digits = min(digits, 18##)
                  function = fix((10^digits) * value) / (10^digits)
              END FUNCTION
              FUNCTION RoundIt (BYVAL value AS EXT, BYVAL digits as ext) EXPORT AS EXT
                  if value = 0 then function = 0 : exit function
                  function = value
                  digits = min(digits, 18##)
                  function = fix((10^digits) * value + sgn(value) * .5##) / (10^digits)
              END FUNCTION

              Comment


              • #27
                Venice, we've had a problem. I ran this test code Paul, and it doesn't quite match yet between your code and mine. I'll compare these other posted algos asap too.
                Code:
                'compiled with pbcc 4.04
                'round.bas
                
                #COMPILE EXE
                #DIM ALL
                
                FUNCTION roundUp(BYVAL a AS EXT, BYVAL b AS LONG) AS EXT
                   LOCAL x, y AS EXT, neg AS LONG
                   LOCAL z AS QUAD       '<< has to be quad! if it's EXT, z MOD 5 = 5 occasionally. Don't know why.
                
                   IF a < 0 THEN
                      a = -a
                      neg = 1
                   END IF
                
                   x = ROUND(a, b)      'in 8.04 (and probably most recent CC ver.) round to even, or banker's rounding
                   IF x >= a THEN
                      IF neg = 1 THEN x = -x
                      FUNCTION = x
                      EXIT FUNCTION
                   END IF
                
                   y = 10 ^ (b + 1)
                   z = a * y            'move decimal point to end
                
                   IF z MOD 5 = 0 THEN  'see if last digit is a 5
                      x = z + 5         'round up if it is
                      IF neg = 1 THEN
                         FUNCTION = ROUND(-x / y, b)
                      ELSE
                         FUNCTION = ROUND( x / y, b)
                      END IF
                      EXIT FUNCTION
                   END IF
                
                   IF neg = 1 THEN
                      FUNCTION = -x     'use from ROUND calculation already done above
                   ELSE
                      FUNCTION = x
                   END IF
                
                END FUNCTION
                
                FUNCTION roundmeR(BYVAL X AS EXT, BYVAL Factor AS LONG) AS EXT
                     IF FACTOR THEN
                     FUNCTION=ROUND((FIX((X * 10^Factor) + (SGN(x)*(0.5))))*(1/10^factor),factor)
                     ELSE
                     FUNCTION=ROUND(FIX(x)+(FIX(((FRAC(X)+SGN(x)*(0.5))))),factor)
                
                     END IF
                END FUNCTION
                
                FUNCTION roundme(BYVAL X AS EXT, BYVAL Factor AS LONG) AS EXT
                     IF FACTOR THEN
                     FUNCTION=(FIX((X * 10^Factor) + (SGN(x)*(0.5))))*(1/10^factor)
                     ELSE
                     FUNCTION=FIX(x)+(FIX(((FRAC(X)+SGN(x)*(0.5)))))
                
                     END IF
                END FUNCTION
                
                FUNCTION PBMAIN () AS LONG
                LOCAL MM AS STRING
                LOCAL M AS EXT
                LOCAL roundto, numDig, count AS LONG
                
                DO
                   roundto = RND(0,10)
                   numDig = 2
                   INCR count
                   M= ROUND(RND * 10^numDig, roundto+1)
                   IF (roundUp(M,roundto)) <> (roundMeR(M,roundto)) THEN
                      PRINT "Original    = " & STR$(M)
                      PRINT "Difference  = " & STR$(roundUp(M,roundto) - roundMe(M,roundto))
                      PRINT "roundUp     = " & STR$(roundUp(M,roundto), 18)
                      PRINT "roundMe     = " & STR$(roundMe(M,roundto), 18)
                      PRINT "roundMeR    = " & STR$(roundMeR(M,roundto), 18)
                      PRINT "Total tries = " & STR$(count)
                      WAITKEY$
                   END IF
                LOOP
                
                END FUNCTION

                Comment


                • #28
                  Another test: Clay's RoundIt() function produces identical results to the RoundMeR() function above, which both mismatch occasionally compared to roundUp(). It's a bit of a sticky wicket.

                  Comment


                  • #29
                    John,

                    PB's ROUND() function uses banker's rounding. Mine (José's) does not. Maybe that explains the difference?

                    Comment


                    • #30
                      Originally posted by Clay Clear View Post
                      PB's ROUND() function uses banker's rounding. Mine (José's) does not. Maybe that explains the difference?
                      There must be a subtle error somewhere, because like your (Jose's) code, mine does not follow banker's rounding either, even tho it does use ROUND in its algorithm. Our code compares exactly thru hundreds of iterations, but occasionally (1 in 200 or so) mis-matches, with Jose's code rounding down when it should round up. Here are a couple examples below and we can see ...345 should round to ...35 and ...175 should round to ...18.
                      Code:
                      Original    =  85.31382345
                      Difference  =  1.00000000002876E-7
                      roundUp     =  85.3138235
                      roundIt     =  85.3138234
                      roundMe     =  85.3138234
                      roundMeR    =  85.3138234
                      Total tries =  471
                      
                      Original    =  12.41271175
                      Difference  =  1.00000000000273E-7
                      roundUp     =  12.4127118
                      roundIt     =  12.4127117
                      roundMe     =  12.4127117
                      roundMeR    =  12.4127117
                      Total tries =  852

                      Comment


                      • #31
                        John
                        thanks for the comparison runs
                        i going to use your roundup code
                        dependability in standards are a must for me.
                        p purvis

                        Comment


                        • #32
                          John,

                          If you're going to use the PB ROUND() intrinsic in your rounding code, then I think it's inevitable that you will sooner or later get hit by banker's rounding.

                          Comment


                          • #33
                            Keep in mind that banker's rounding will only occur if all of the digits to the right of the "5" being rounded are EXACTLY zero (e.g., as obtained by the following fractions: 1/4 , 1/8, 1/16, etc.). This must be tested by determining the digits stored in memory for the variable; the STR$ function is not sufficiently accurate for this purpose. Two stored values having exactly the same result with STR$(variable, 18) can yield different rounding results if they are not absolutely identical.

                            Comment


                            • #34
                              With the exception of counted things, no measurement is sufficiently precise for bankers rounding to have any significance whatsoever.
                              Under normal circumstances physical measurements have inherent errors greater than that produced by incorrect bankers rounding.
                              However if you enjoy counting angels on the head of a pin then this discussion may have some value.
                              Dave.

                              You're never too old to learn something stupid.

                              Comment


                              • #35
                                The late Rear Admiral Grace M. Hopper, considered as the "mother" of COBOL, commissioned a battery of tests designed to test the validity of computer manufacturer's COBOL compilers in the late '50s and early '60s. She found that computers that used binary floating point representation of decimal numbers presented certain rounding anamolies that computers that used decimal arithmetic did not. (IBM System/360 uses decimal arithmetic for example). The reason for these anamolies was due to the fact that 0.005 and 0.00005 cannot be represented exactly in binary.

                                See Microsoft and Lotus spreadsheet errors.

                                See also The trouble with rounding floating point numbers.

                                And B. Floating Point Arithmetic: Issues and Limitations.

                                The closest thing we have to decimal arithmetic are the Currency (@) and Extended-Currency (@@) data types.
                                Regards,
                                Bob

                                Comment


                                • #36
                                  Welp, my intent in writing that function was to try to create a 100% accurate and consistent algorithm for all possible inputs that would round up on 5. I've tested the begeebers out of the thing and haven't been able to find any flaw yet. Therefore, that testing mathematically proves it is a perfect algorithm, for now and forever. j/k 'bout the perfect algo proof thing.

                                  Nevertheless, negative findings for any errors over more and more tests and time does bode well for the code, and I'm afraid that's all I can think of to "prove" its validity. Kinda like DNA testing: I can't say I am definitely the father with greater than 99.9991% accuracy (analogy here is finding no errors in rounding algo), but I can say with 100% certainty I am definitely not papa (analogy is someone can find where the code rounds the wrong way).

                                  Comment


                                  • #37
                                    Hey John --

                                    Could you please indicate the purpose of each of the functions in your round.bas code? RoundUp is obviously intended to always round up the numerical variable. What are roundmeR and roundme intended to do?

                                    Sorry, if this is a simplistic question, but the issue of rounding floating point variables is anything but simplistic. I find nothng wrong with the function ROUND provided by PB as it performs the function accurately if you intend to use traditional rounding (along with banker's rounding on exact "5").

                                    If someone can find a numerical value that is incorrectly rounded by PB, I hope they submit it on this forum.

                                    Thanks,
                                    Walter
                                    Last edited by Walter Henn; 16 Jun 2008, 09:41 PM.

                                    Comment


                                    • #38
                                      If someone can find a numerical value that is incorrectly rounded by PB, I hope they submit it on this forum.
                                      You SHOULD hope they send a source code example to [email protected], as this forum is not an official venue for submitting bug reports.
                                      Michael Mattias
                                      Tal Systems (retired)
                                      Port Washington WI USA
                                      [email protected]
                                      http://www.talsystems.com

                                      Comment


                                      • #39
                                        Originally posted by Walter Henn View Post
                                        but the issue of rounding floating point variables is anything but simplistic.
                                        Amen to that!

                                        All three functions below attempt to do the same thing: round the number a to the specified number of decimal places b, with the special condition that the rounded number preceding a trailing 5 must always round up. This is in lieu of the "banker's rounding" rule where preceding odd numbers round up and preceding even numbers are unchanged. The functions are all present together in the test code to verify if they match over all possible input values, and it turns out they do not. (Not shown in the code below, but also tested later was RoundIt(). My testing showed it to be functionally identical to RoundMeR().)
                                        Code:
                                        FUNCTION roundUp(BYVAL a AS EXT, BYVAL b AS LONG) AS EXT
                                           LOCAL x, y AS EXT, neg AS LONG
                                           LOCAL z AS QUAD       '<< has to be quad! if it's EXT, z MOD 5 = 5 occasionally. Don't know why.
                                        
                                           IF a < 0 THEN
                                              a = -a
                                              neg = 1
                                           END IF
                                        
                                           x = ROUND(a, b)      'in 8.04 (and probably most recent CC ver.) round to even, or banker's rounding
                                           IF x >= a THEN
                                              IF neg = 1 THEN x = -x
                                              FUNCTION = x
                                              EXIT FUNCTION
                                           END IF
                                        
                                           y = 10 ^ (b + 1)
                                           z = a * y            'move decimal point to end
                                        
                                           IF z MOD 5 = 0 THEN  'see if last digit is a 5
                                              x = z + 5         'round up if it is
                                              IF neg = 1 THEN
                                                 FUNCTION = ROUND(-x / y, b)
                                              ELSE
                                                 FUNCTION = ROUND( x / y, b)
                                              END IF
                                              EXIT FUNCTION
                                           END IF
                                        
                                           IF neg = 1 THEN
                                              FUNCTION = -x     'use from ROUND calculation already done above
                                           ELSE
                                              FUNCTION = x
                                           END IF
                                        
                                        END FUNCTION
                                        
                                        FUNCTION roundmeR(BYVAL X AS EXT, BYVAL Factor AS LONG) AS EXT
                                             IF FACTOR THEN
                                             FUNCTION=ROUND((FIX((X * 10^Factor) + (SGN(x)*(0.5))))*(1/10^factor),factor)
                                             ELSE
                                             FUNCTION=ROUND(FIX(x)+(FIX(((FRAC(X)+SGN(x)*(0.5))))),factor)
                                        
                                             END IF
                                        END FUNCTION
                                        
                                        FUNCTION roundme(BYVAL X AS EXT, BYVAL Factor AS LONG) AS EXT
                                             IF FACTOR THEN
                                             FUNCTION=(FIX((X * 10^Factor) + (SGN(x)*(0.5))))*(1/10^factor)
                                             ELSE
                                             FUNCTION=FIX(x)+(FIX(((FRAC(X)+SGN(x)*(0.5)))))
                                        
                                             END IF
                                        END FUNCTION

                                        Comment


                                        • #40
                                          seems i am just seeing some of the light of things.
                                          i am sure what i am going to say is old news to many people, but just today for the first time, i am seeing something strange to me and maybe somebody can shed the light once more.

                                          my final test program to rounding used a input number from a string using the VAL statement and i had been also done testing where i would assign a variable a fixed value.

                                          i did not really expect these results
                                          where the first assignment to M using 11.455 without a specific variable tail will not return the same value of 11.455## and val(input string of "11.455")

                                          just about all my previous coding involved saving the data in a string and/or a full value of the number ex. "1234.45",1234.45
                                          so basically i did not save or read values in compressed formats.
                                          and i always used variable descriptors with any numbers because i was forced to by the compiler i was using.

                                          so even though this subject has been covered before, it is again, affecting rounding computations.
                                          please supply 11.455 to your input when running the code
                                          coding will do a better job of explaining my words
                                          Code:
                                          #COMPILE EXE
                                          #DIM ALL
                                          
                                          FUNCTION PBMAIN () AS LONG 
                                          
                                          LOCAL MM AS STRING
                                          LOCAL M AS EXT
                                          
                                          start:
                                          INPUT "input amount ",mm
                                          mm=TRIM$(mm)
                                          IF mm="" THEN EXIT FUNCTION
                                          INPUT "input no of decimals ",roundto
                                          m=11.455
                                          PRINT M
                                          m=11.455##
                                          PRINT M
                                          M=VAL(MM)
                                          PRINT M  
                                          waitkey$
                                          end function
                                          Last edited by Paul Purvis; 17 Jun 2008, 02:00 PM.
                                          p purvis

                                          Comment

                                          Working...
                                          X