Announcement

Collapse
No announcement yet.

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

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

  • John Gleason
    replied
    >>wouldn't compile...

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

    Leave a comment:


  • Mottel Gutnick
    replied
    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.

    Leave a comment:


  • Mottel Gutnick
    replied
    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

    Leave a comment:


  • Michael Mattias
    replied
    >Not when SGN(dividend) <> SGN (divisor).
    Code:
    MACRO Remainder (dividend,divisor) =   (dividend MOD divisor) * IIF&(SGN(Dividend)=SGN(divisor), 1&, -1&)
    Something like that.

    Leave a comment:


  • Mottel Gutnick
    replied
    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.

    Leave a comment:


  • John Gleason
    replied
    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

    Leave a comment:


  • Jeff Blakeney
    replied
    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.

    Leave a comment:


  • Michael Mattias
    replied
    > 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."

    Leave a comment:


  • Bob Zale
    replied
    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.

    Leave a comment:


  • Mottel Gutnick
    replied
    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

    Leave a comment:


  • Mottel Gutnick
    replied
    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.

    Leave a comment:


  • Jeff Blakeney
    replied
    Originally posted by Tom Hanlin View Post
    "\" stipulates an integer division. There is no floating point, so there is no rounding to be done.
    Division of any kind can result in a floating point number and therefore rounding can be performed. I just ran this like test program:

    Code:
    FUNCTION PBMAIN () AS LONG
    
        MSGBOX "9 / 10 = "     + FORMAT$(9/10)       + $CRLF + _
               "9 \ 10 = "     + FORMAT$(9\10)       + $CRLF + _
               "FIX(9/10) = "  + FORMAT$(FIX(9/10))  + $CRLF + _
               "INT(9/10) = "  + FORMAT$(INT(9/10))  + $CRLF + _
               "CINT(9/10) = " + FORMAT$(CINT(9/10)) + $CRLF + _
               "CEIL(9/10) = " + FORMAT$(CEIL(9/10))
    
    END FUNCTION
    Not all the result are what I was initially expecting. I got the following results:

    9 / 10 = .9
    9 \ 10 = 0
    FIX(9/10) = 0
    INT(9/10) = 0
    CINT(9/10) = 1
    CEIL(9/10) = 1
    I'm pretty sure it was Bob Zale that said in another thread that PB follows the IEEE standard for rounding and I think there might be some confusion about the usage of the term rounding in the documentation. The documentation for the FIX statement says that it doesn't do any rounding, which is shown with these results, but it also says that INT and CINT do perform rounding but the results show that CINT does but INT doesn't. Looking at the documentation for INT, CINT and CEIL it seems that the "rounding" these functions are doing is simply to drop any fractional results (INT) or go to the next higher integer if there are fractional results (CINT and CEIL).

    Perhaps the confusion is on my part because when I think of rounding I think of the scientific rounding that I was taught in school where 1.1 becomes 1, 1.5 becomes 2, 1.9 becomes 2, 2.1 becomes 2, 2.5 becomes 2 and 2.9 becomes 3. I don't know what the IEEE standard Bob mentioned is or how it works.

    What it boils down to in PB is that integer division (using the \ operator), FIX and INT will all give the same results by dropping any fractional result and CINT and CEIL will give a different result by incrementing the integer portion by one if the fractional portion is not zero.

    Mottel, you were right, FIX(A\B) was a typo on my part and should have been FIX(A/B).

    Leave a comment:


  • Tom Hanlin
    replied
    "On two occasions, I have been asked , "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?" I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question." - Charles Babbage

    Yes, overflow detection would be a great feature. Yes, it's on the list. No, you may not expect the compiler to produce predictable results when you give it data that doesn't fit into the buckets you specified.

    Leave a comment:


  • Mottel Gutnick
    replied
    Originally posted by Michael Mattias View Post
    Send in a new feature suggestion ...
    MCM
    Is there an area in the forums for putting in such requests or do you email them directly to support?

    ADDENDUM:
    Er, belay that request Scottie ... just found the link to the Feature Request Webpage in a sticky post on another forum.
    Last edited by Mottel Gutnick; 20 Oct 2009, 07:29 PM. Reason: Addendum

    Leave a comment:


  • Mottel Gutnick
    replied
    Originally posted by Jeff Blakeney View Post
    ... FIX simply drops any fractions and returns the integer digits. I'm not sure if ... A\B will ... always be equal to FIX(A\B).
    The original subject line may have been slightly misleading. A\B returns the same result as fix(A/B) except when overflow occurs.

    ADDENDUM:

    Whoops, just noticed your typo Jeff. Just to be absolutely clear: you wrote "FIX(A\B)" which is EXACTLY the same as A\B except that the FIX() portion is entirely redundant. I'm sure you meant to write "FIX(A/B)", which is what I was comparing/contrasting with A\B.
    Last edited by Mottel Gutnick; 20 Oct 2009, 06:23 PM. Reason: Addendum added

    Leave a comment:


  • Michael Mattias
    replied
    > surely the compiler should at least deal with overflow in a predictable manner?

    Send in a new feature suggestion for #DEBUG OVERFLOW ON. You should get the coveted "checkmark" since I asked for that literally years ago.

    MCM

    Leave a comment:


  • Mottel Gutnick
    replied
    Originally posted by Tom Hanlin View Post
    The result of an invalid operation is undefined. I hope that is clear? You should not rely on it.
    What's invalid about Q = A\B or Q = fix(A/B)? They are valid statements. It is the values thrown at them that cause the overflow condition, which is not always predictable. (The program may be using values input by a user.) Since PB programs no longer generate run-time errors in case of overflow, surely the compiler should at least deal with overflow in a predictable manner?

    Leave a comment:


  • Michael Mattias
    replied
    COBOL:
    Code:
     WORKING STORAGE SECTION. 
       77  A    PICTURE  S9(9) USAGE BINARY.     << as close as you can get to a BASIC LONG integer
       77  B    PICTURE  S9(9) USAGE BINARY. 
       77  C    PICTURE  S9(9) USAGE BINARY. 
       77  A    PICTURE  S9(9) USAGE BINARY. 
    
    .....
    DIVIDE
       A INTO B 
         GIVING  C 
           REMAINDER  D 
    END-DIVIDE
    BASIC
    Code:
     LOCAL A, B, C, D AS LONG
    
     C =  B\A
     D  = B MOD A
    COBOL
    Code:
     [SAME W-S]
    DIVIDE  
       A INTO B 
           GIVING  C  [b][COLOR="Red"]ROUNDED[/COLOR][/b] 
              REMAINDER  D 
    END-DIVIDE
    BASIC:
    Code:
      C =  B/A 
      D =  B MOD A
    MCM

    Leave a comment:


  • Tom Hanlin
    replied
    "\" stipulates an integer division. There is no floating point, so there is no rounding to be done.

    Leave a comment:


  • Jeff Blakeney
    replied
    According to the PB documentation CINT and INT will do rounding while FIX simply drops any fractions and returns the integer digits. I'm not sure if doing an integer division (using the \ operator) will also do rounding but if it does, then A\B will not always be equal to FIX(A\B).

    Leave a comment:

Working...
X