Announcement

Collapse
No announcement yet.

Why is A\B <> fix(A/B) ?

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

  • #21
    Originally posted by Jeff Blakeney View Post
    ... the confusion ...
    FIX rounds by truncation at the decimal point. I guess it's called rounding because it produces "round" (i.e. whole) numbers. The documentation makes it very clear that it does not try to deliver the closest whole-number value -- that is the job of CINT (and its allies). (You just have to be aware of the "special handling" that CINT applies when the fraction = .5. In that case, CINT rounds to the nearest EVEN number, whether that is up or down.)

    INT does NOT do the same thing as FIX. Try it on negative numbers and you will see the difference. INT does the exact opposite of CEIL. (I believe that INT is the equivalent of what other languages more descriptively call the Floor function.) INT always rounds down (i.e. towards negative infinity), CEIL always rounds upwards (i.e. towards positive infinity).

    INT rounds numeric_expression to the largest integer-class value that is less than or equal to numeric_expression.
    And, Tom, in response to:
    "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?"
    I say, I do not expect the right answers to come out, but I do expect the machine to behave like a machine, not like a capricious creature with a mind of its own. In other words, it should deal with like situations in a like (and hence predictable) manner.
    Last edited by Mottel Gutnick; 21 Oct 2009, 08:38 PM.

    Comment


    • #22
      A better Modulo function

      Originally posted by Jeff Blakeney View Post
      ... Bob Zale that said in another thread that PB follows the IEEE standard for rounding ...
      Coincidentally, I read that post just yesterday. I wanted to comment on it as follows. (It's off topic whether I post it there or here, so it might as well be here because it is a useful demo of the different consequences of using int and fix.)

      It's a pity PB doesn't follow the same standard with regard to the MOD (modulo) function. Then programmers wouldn't have to create their own functions like the one shown below.

      To be fair,
      (a) the IEEE standard doesn't mention Modulo; it mentions the Remainder function,
      (b) other BASICs' (and possibly other languages') modulo functions also work the same way as PB's MOD, and
      (c) it would cause no end of chaos and confusion if PB were to suddenly change how MOD works,

      so a more realistic wish would be that PB provide, in addition to MOD, a separate Remainder function that works as detailed below.

      Code:
      ' FnModulo&&
      ' ----------
      '   Gives the remainder (R) of the division A/B, defined as: R = A - QB,
      '   where Q is an integer derived from q, and q = A/B. (i.e. q is the
      '   quotient of the division, and Q is the integer quotient.)
      
      '   NOTE: This function sometimes produces a different remainder (R) from the
      '   result (M) obtained from BASIC's inbuilt MOD function. The difference
      '   lies in the method of converting q to Q.
      
      '   The MOD function converts q to Q by truncating q. The decimal portion is
      '   discarded, leaving only the integer portion. This endows the MOD function
      '   with the properties that:
      '   (1) for A < 0, M will be <= 0, for all values of B, positive or negative.
      '       Thus, for non-zero M, SGN(M) = SGN(A)
      '   (2) ABS(M) will be the same as ABS(A) MOD ABS(B).
      
      '   This function is the same as that used on HP scientific calculators of the
      '   early 1980s which had an inbuilt modulo function. That function is defined
      '   as: "X - [<X/Y> * Y], where <> denotes the largest integer less than or
      '   equal to the indicated result." Here too, Q is defined as the greatest
      '   integer less than or equal to q (a conversion to integer AKA the Floor
      '   function), e.g. for q = 3.9, Q = 3, for q = -2.2, Q = -3.
      
      '   This method endows this function with two important properties:
      '   (1) For non-zero R, SGN(R) = SGN(B), thus,
      '       for B > 0, R will be => 0 for all values of A, even for negative A.
      '   (2) when the signs of A & B are the same, R is the same as M, but when
      '       the signs of A and B differ, R = B + M.
      
      '   These two properties ensure sensible results for all modular arithmetic
      '   (especially subtraction) performed on members of a set of finitely-numbered
      '   items where the item numbering wraps around after the highest number is
      '   reached and starts again from the first number for subsequent members of
      '   the set, e.g. weekday numbering. This fn computes weekday shifts counting
      '   backwards, whereas MOD will not. Assuming Sunday = weekday 1, to find the
      '   weekday (W), 8 days before Friday, you can use: W = FnModulo&&((6-8),7) or
      '   W = (6-8) MOD 7. With method 1, W = 5 (Thursday); with method 2, W = -2.
      
      
      function FnModulo&& (A&&,B&)
      '        ----------
          local Q&
      
          Q& = int(A&&/B&)
          function = A&& - (Q& * B&)
      end function  ' FnModulo&&  -----------------------------------------
      Last edited by Mottel Gutnick; 22 Oct 2009, 12:06 AM. Reason: added new subject line

      Comment


      • #23
        Actually, you already have your solution in hand.

        When you find that you need a special function which differs from the "standard", you simply write it yourself! I'm pretty sure that's why we call this a "Programming Language". {smile} You get to make those choices!

        Best regards,

        Bob Zale
        PowerBASIC Inc.

        Comment


        • #24
          > in addition to MOD, a separate Remainder function that works as detailed below.

          ???

          If you stick wth integers MOD *is* remainder.

          BTW... FORMAT$ will do rounding under certain conditions (See help file). You need to be careful with your test code you don't interpret "character output from FORMAT$()" as "internal value of a numeric variable."
          Michael Mattias
          Tal Systems (retired)
          Port Washington WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #25
            Mottel, you are right that I screwed up my interpretation of some of the commands.

            FIX simply drops the fractional part and returns the whole number. -1.5 becomes -1, 1.5 becomes 1 and 2.5 becomes 2.

            INT returns the largest integer that is less than or equal to the value passed. -1.5 becomes -2, 1.5 becomes 1 and 2.5 becomes 2.

            CINT rounds to the nearest integer but has a special case for values of .5 where, if the integer portion is even, the integer portion is returned but if the integer portion is odd then the return value is incremented by one if it is positive and decremented by one if it is negative. -1.5 becomes -2, 1.5 becomes 2, 2.5 becomes 2.

            CEIL returns the smallest integer that is greater than or equal to the value passed. This is the opposite of INT. -1.5 becomes -1, 1.5 becomes 2, 2.5 becomes 3.

            Sorry for any confusion I may have caused.
            Jeff Blakeney

            Comment


            • #26
              Here is your Remainder function in 2 super fast forms, MACRO and MACRO FUNCTION, almost like the compiler might do it itself:

              Added: accidentally removed initial metastatements in 1st post, so added them back in. Also added $WAITKEY.
              Code:
              [COLOR="Red"]#COMPILE EXE
              #DIM ALL
              #REGISTER NONE[/COLOR]
              
              MACRO FUNCTION mfModuloFast(a, b, c) 'a and c are QUADs, b is LONG
              '        ----------
                   !lea ecx, c                     ;c is a QUAD used by the macro, and will hold the final answer
                   !lea eax, a
                   !mov dword ptr[ecx], &h3f000000 ;exactly 0.5
                   !lea edx, b
                   !fld dword [ecx]                ;0.5
                   !fldz                           ;0.0
              
                   !fild qword [eax]
                   !fild dword [edx]
                   !fdivp st(1), st(0)             ;A/B
                   !mov edx, [edx]                 ;will be a bit faster than !imul dword ptr[edx]
                   !fsub st(0), st(2)              ;round down 0.5
                   !fistp dword [ecx]              ;INT
                   !mov eax, [ecx]                 ;Q
                   !imul edx                       ;* B
                   !mov [ecx], eax
                   !mov [ecx+4], edx
                   !lea eax, a                     ;A
                   !fild  qword [ecx]
                   !fild  qword [eax]
                   !fsubrp                         ;A - (Q * B)
                   !fistp qword [ecx]              ;save as c
              
                   !fstp st(0)                     ;clear
                   !fstp st(0)
                   'above asm does this:
                   'Q = INT(A/B)
                   'c = A - (Q * B)
              END MACRO = c
              
              MACRO mModuloFast(a, b, c) 'a and c are QUADs, b is LONG
              '        ----------
                   !lea ecx, c                     ;c is a QUAD used by the macro, and will hold the final answer
                   !lea eax, a
                   !mov dword ptr[ecx], &h3f000000 ;exactly 0.5
                   !lea edx, b
                   !fld dword [ecx]                ;0.5
                   !fldz                           ;0.0
              
                   !fild qword [eax]
                   !fild dword [edx]
                   !fdivp st(1), st(0)             ;A/B
                   !mov edx, [edx]                 ;will be a bit faster than !imul dword ptr[edx]
                   !fsub st(0), st(2)              ;round down 0.5
                   !fistp dword [ecx]              ;INT
                   !mov eax, [ecx]                 ;Q
                   !imul edx                       ;* B
                   !mov [ecx], eax
                   !mov [ecx+4], edx
                   !lea eax, a                     ;A
                   !fild  qword [ecx]
                   !fild  qword [eax]
                   !fsubrp                         ;A - (Q * B)
                   !fistp qword [ecx]              ;save as c
              
                   !fstp st(0)                     ;clear
                   !fstp st(0)
                   'above asm does this:
                   'Q = INT(A/B)
                   'c = A - (Q * B)
              END MACRO
              
              FUNCTION PBMAIN () AS LONG
                  LOCAL a, c, d, t AS QUAD, b, ii AS LONG
                  RANDOMIZE
                  TIX t
                  FOR ii = 1 TO 10000000
                     a = RND * &h7fffffffffffffff * RND(1, -1)
                     b = RND(&h80000000, &h7fffffff)
              
                     c = fnModulo(a, b)       'c holds the same result in all 3 of these examples
                     mModuloFast(a, b, c)
                     c = mfModuloFast(a, b, c)
                  NEXT
                  TIX END t
                  ? STR$(t)
                  WAITKEY$
              
              END FUNCTION
              
              FUNCTION FnModulo(A AS QUAD,B AS LONG) AS QUAD
              '        ----------
                  LOCAL Q AS LONG
              
                  Q = INT(A/B)
                  FUNCTION = A - (Q * B)
              END FUNCTION
              Last edited by John Gleason; 22 Oct 2009, 04:47 PM. Reason: added metastatements in red

              Comment


              • #27
                Originally posted by Michael Mattias View Post
                If you stick wth integers MOD *is* remainder.
                Not when SGN(dividend) <> SGN (divisor).

                I first became aware of this in the 1980s when a program I had "coded" on an HP programmable calculator did not work correctly when ported to a PC and coded in BASIC. I traced the problem to the difference between the definition of the inbuilt Modulo function on the HP calculator and BASIC's MOD function.

                There is an explanation of the underlying theory behind this in Wikipedia's articles on the Modulo operation (main article, listing different Modulo implementations in different languages) and Remainder.

                It is important for programmers to be aware of the difference between the two methods.

                Comment


                • #28
                  >Not when SGN(dividend) <> SGN (divisor).
                  Code:
                  MACRO Remainder (dividend,divisor) =   (dividend MOD divisor) * IIF&(SGN(Dividend)=SGN(divisor), 1&, -1&)
                  Something like that.
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #29
                    Originally posted by John Gleason View Post
                    Here is your Remainder function in 2 super fast forms, MACRO and MACRO FUNCTION, ...
                    Thanks John, but it wouldn't compile for me (PBCC 5.02) and I don't know enough about assembly to correct it.
                    Error 497 ... Assembler syntax error
                    Line 74: mModuloFast(a, b, c)
                    Macro Expansion(13): !LEA EDX, b

                    Comment


                    • #30
                      Originally posted by Michael Mattias View Post
                      ... Something like that.
                      Not sure if I understood that correctly. It looks to me like you're just reversing the sign of the Result when SGN(dividend) <> SGN(divisor). If so, that's incorrect. You have to add Result + divisor.

                      Comment


                      • #31
                        >>wouldn't compile...

                        Sorry about that Mottel, I have it up and running now above.

                        Comment

                        Working...
                        X