A single line function to modify MOD for better pattern recognition....
#1
Code: (Select All)
DIM AS INTEGER i, j
DO
    CLS
    INPUT "Input any integer: "; i: PRINT
    INPUT "Input a modulo as a non-zero integer: "; j
    IF j = 0 THEN _CONTINUE
    i$ = LTRIM$(STR$(i))
    LOCATE 5, 2: PRINT LTRIM$(STR$(i)); " modx"; j; "="; modx(i, j)
    SLEEP
    IF INKEY$ = CHR$(27) THEN SYSTEM
LOOP

FUNCTION modx (i, j)
    modx = (ABS(i) - ABS(j) * (ABS(i \ j) + (1 - SGN(i)) \ 2)) * SGN(i MOD j)
END FUNCTION

So modx is a way we can modify our QB64 MOD operator so we can work with patterns. It conforms with online modulo calculators.

For comparison, see the first result for modx and compare it to the second result of MOD. Note they are the same until the numbers turn negative.

Code: (Select All)
$CONSOLE:ONLY
' Testing modx 5
FOR i = 20 TO -20 STEP -1
    i$ = LTRIM$(STR$(i))
    LOCATE , 4 - LEN(i$): PRINT LTRIM$(STR$(i));: LOCATE , 5: PRINT "modx j ="; modx(i, 5), "QB64 MOD: "; i MOD 5
NEXT

FUNCTION modx (i, j)
    modx = (ABS(i) - ABS(j) * (ABS(i \ j) + (1 - SGN(i)) \ 2)) * SGN(i MOD j)
END FUNCTION

Note that modx also works with negative modulo integers. I'll leave it to the more math proficient if this utility could be extended to floating point operations.

The function can be modified again to change the zero output to the modulo number. See the two modx, modx_p1 and modx_p2 compared below:

Code: (Select All)
' Two pattern formulas with MOD.
$CONSOLE:ONLY
' Testing modx_p1 5
FOR i = 20 TO -20 STEP -1
    i$ = LTRIM$(STR$(i))
    LOCATE , 4 - LEN(i$): PRINT LTRIM$(STR$(i));: LOCATE , 5: PRINT "modx j ="; modx_p1(i, 5), "QB64 MOD: "; i MOD 5
NEXT
PRINT: PRINT "Press a key for next pattern...": SLEEP

' Testing modx_p2 5
FOR i = 20 TO -20 STEP -1
    i$ = LTRIM$(STR$(i))
    LOCATE , 4 - LEN(i$): PRINT LTRIM$(STR$(i));: LOCATE , 5: PRINT "modx j ="; modx_p2(i, 5), "QB64 MOD: "; i MOD 5
NEXT

FUNCTION modx_p1 (i, j)
    modx_p1 = (ABS(i) - ABS(j) * (ABS(i \ j) + (1 - SGN(i)) \ 2)) * SGN(i MOD j)
END FUNCTION

FUNCTION modx_p2 (i, j)
    modx_p2 = (ABS(i) - ABS(j) * (ABS(i \ j) + (1 - SGN(i)) \ 2)) * SGN(i MOD j) + ABS(j) - ABS(j * SGN(i MOD j))
END FUNCTION

So what the second example is useful for is things like file record look up and calendar apps, etc. Here is a quick example of how it could be used for a calendar.

Code: (Select All)
WIDTH 80, 42
_SCREENMOVE 0, 0
FOR i = 1 TO 31
    PRINT "Day"; i, modx(i, 7)
NEXT

FUNCTION modx (i, j)
    modx = (ABS(i) - ABS(j) * (ABS(i \ j) + (1 - SGN(i)) \ 2)) * SGN(i MOD j) + ABS(j) - ABS(j * SGN(i MOD j))
END FUNCTION

Now I put the second pattern function together after I made the first, which makes me wonder if instead of adding the last part of the equation, if I could optimize it by changing the prior existing equation. I won't be looking into it now, as I got side tracked from another project for this, but optimization changes are always welcomed. Just be sure any changes will work for all possible possible negative and positive number and modulo situations.

Also, if you find any holes in the function, please feel free to post your findings. I'm not certifying this as 100%. Steve and Bplus also have working models posted in another thread. Mine is just a one-liner, which totally suits my personality to a tee... Eeew ya carnsarn idiom!

Pete
Reply
#2
That's some complicated math stuff there!

Here's all one would ever need with MOD -- no matter which pattern they like best:

Code: (Select All)
For i = 10 To -10 Step -1
    Print i Mod 5, ModX(i, 5)
Next

Function ModX (num1, num2)
    ModX = ((num1 Mod num2) + num2) Mod num2
End Function
Reply
#3
Thumbs Up 
Well Steve posted while I was about to...

Testing Pete's in a very common situation for us hobbyists:
Code: (Select All)
_Title "MOD versus modx test Petes new thing ;-))" ' b+ 2022-11-28
Screen _NewImage(800, 600, 32)
x = 300: y = 300: dx = -5
Do
    Cls
    Print "spacebar to exit this first screen, I want circle to exit stage left and enter stage right..."
    Circle (x, y), 20
    x = (x + dx) Mod _Width ' head left loop around and head left???
    _Display 'no blinking
    _Limit 10 ' 10 xs per sec
Loop Until _KeyDown(32)
Cls
Locate 15, 20: Print "That sucks, I am talking about normal MOD for negative numbers."
Print
Locate 17, 20: Print "   OK try Pete's new and improved super dupper modx(), zzz..."
_Display
Sleep
_KeyClear
Cls

x = 300: y = 300: dx = -5
Do
    Cls
    Print "escape to quit, circle should leave screen on left and return on right"
    Circle (x, y), 20
    x = modx(x + dx, _Width) ' head left loop around and head left???
    If x > 400 Then
        Locate 30, 30: Print "It works! It works! Holy crap it works!"
    End If
    _Display 'no blinking
    _Limit 10 ' 10 xs per sec
Loop Until _KeyDown(27)

Function modx (i, j)
    modx = (Abs(i) - Abs(j) * ((Abs(i) \ Abs(j)) + (1 - Sgn(i)) \ 2)) * Sgn(i Mod j)
End Function

This is actual situation that comes up and you wish there was a better way. 

Steve's thing should work fine for this but Pete takes on Negative Modulus! What a guy!

Negative Modulus sounds to me like a psychologist looking for business.

OK Pete does this hold pattern for a Modulus of a negative _Float?

2 points for anyone who can come up with some example where a modulus of negative float would be needed.

I confess I am still getting over doing negative integers with MOD let alone floats positive or negative!
b = b + ...
Reply
#4
Well Steve fixed his and it has much less use of ABS:
Code: (Select All)
_Title "MOD versus modx test Petes new thing" ' b+ 2022-11-28
Screen _NewImage(800, 600, 32)
x = 300: y = 300: dx = -5
Do
    Cls
    Print "spacebar to exit this first screen, I want circle to exit stage left and enter stage right..."
    Circle (x, y), 20
    x = (x + dx) Mod _Width ' head left loop around and head left???
    _Display 'no blinking
    _Limit 10 ' 10 xs per sec
Loop Until _KeyDown(32)
Cls
Locate 15, 20: Print "That sucks, I am talking about normal MOD for negative numbers."
Print
Locate 17, 20: Print "  OK try Pete's new and improved super dupper modx(), zzz..."
_Display
Sleep
_KeyClear
Cls

x = 300: y = 300: dx = -5
Do
    Cls
    Print "escape to quit, circle should leave screen on left and return on right"
    Circle (x, y), 20
    x = Steve_ModX(x + dx, _Width) ' head left loop around and head left???
    If x > 400 Then
        Locate 30, 30: Print "It works! It works! Holy crap it works!"
    End If
    _Display 'no blinking
    _Limit 10 ' 10 xs per sec
Loop Until _KeyDown(27)

Function modx (i, j)
    modx = (Abs(i) - Abs(j) * ((Abs(i) \ Abs(j)) + (1 - Sgn(i)) \ 2)) * Sgn(i Mod j)
End Function

Function Steve_ModX (num1, num2)
    Steve_ModX = ((num1 Mod num2) + Abs(num2)) Mod num2 ' fixed for neg modulus with ABS
End Function

BTW don't save file from _title if ;-)) in _title
b = b + ...
Reply
#5
Yes, I posted to Steve in the other thread he had a bit more work to do. I took a different approach form ours and his, Steve's original function, and used SGN() to make up for the differences. Basically the difference in positive to negative numbers is the positive uses the largest number that can be divided into the given number while a negative number uses that result - 1.

7 mod 5 as...

7 = (5 * 1) + 2 where 5 goes into 7 a max of 1 time. [7 mod 5 = 2]

-7 = (5 * -2) + 3 where 5 goes into -7 a max of -1 time and subtract 1 = -2. [-7 mod 5] = 3

Personally I'm going to use these as pattern functions going forward. In the past I used to adjust for zero for everything positive and I probably did something completely different if I came across negative numbers. @bplus Your circle demo was great!

Pete
Reply




Users browsing this thread: 2 Guest(s)