How To

Is there an elegant solution for negative modulo operations

4

SP4CEBAR 2021-10-03 17:57 (Edited)

I'm trying to find an elegant solution to making X MOD 4 output 0,1,2,3,0,1,2,3... for every integer of X

Normally when you do something like:
FOR I=-7 TO 7
PRINT I,I MOD 4
NEXT I
The negative outputs of mod will be flipped, and they share the same zero with the positive outputs, this makes it quite annoying to get it to be 0,1,2,3,0,1,2,3... continuously for every integer value of I

These are some ways I've come up with:

The exact method:
FOR I=-7 TO 7
A=I<0
PRINT I,-A*3+(I-A) MOD 4
NEXT I

I tried to turn the input into an unsigned variable (which worked well, but idk how reliable it is):
FOR I=-7 TO 7
PRINT I,(I+2^14) MOD 4
NEXT I
Does anyone know what value of 2^n would be optimal for turning the floats from NX into something that'll sort of work as an unsigned variable?
I guess I shouldn't add very big values to it, because that'll make it discard relatively insignificant numbers right?


nathanielbabiak 2021-10-03 18:41 (Edited)

Umm... Your original instruction (X MOD 4) provides the pattern you've indicated is desired: {0,1,2,3, 0,1,2,3, 0, 1,2,3, 0,1,2,3}. For integer values of X, you'll get the repeating pattern {3,2,1,0, 3,2,1, 0, 1,2,3, 0,1,2,3} as: ABS(X) MOD 4. For float values of X, you'll need to take the integer value first, but not with the INT instruction (which rounds towards negative infinity), you'll need to take the integer value with \ (which rounds towards zero: ABS(X\1) MOD 4.


rilden 2021-10-03 19:27 (Edited)

Try this:

FOR I=-7 TO 7
PRINT I,I AND 3
NEXT I

This trick only works for powers of 2. If N is a power of 2 then you can replace A MOD N with A AND (N-1).

The largest integer that can be represented exactly is 2^24, or 16777216. You can verify it by running this program:

NUMBER 0,0,16777215,8
NUMBER 0,1,16777216,8
NUMBER 0,2,16777217,8


SP4CEBAR 2021-10-04 10:37

@nathanielbabiak I'm sorry, you may have misunderstood my question
@rilden thanks! That helps a lot


SP4CEBAR 2021-10-04 16:51

Wait a second, so the logical operators in NX are bitwise, that's quite handy to know


SP4CEBAR 2021-10-04 16:54 (Edited)

Now I've just got to find an alternative for integer divisions:
FOR I=-7 TO 7
PRINT I,I\4
NEXT I
This outputs {-1,-1,-1,-1,0,0,0,0,0,0,0,1,1,1,1} which isn't a continuous sequence


nathanielbabiak 2021-10-04 17:35

What sequence would you like it to be?


SP4CEBAR 2021-10-04 17:59 (Edited)

The desired sequence would be something like {-2,-2,-2,-2,-1,-1,-1,-1,0,0,0,0,1,1,1,1,2,2,2,2}

I'm making a Chunk Loading Program which refreshes NX's 32x32 background by loading 8x8 chunks. Currently, it doesn't support loading negative cells. The subprogram that loads the cells receives a set of (virtual) cell coordinates and uses modulo to translate that to the 32x32 background. Integer division is also used by the program, it's used to determine the chunk coordinates of the chunk group that's currently loaded (the scroll position is divided by 64 using integer division).

It looks like bitwise NAND would be able to produce the desired sequence, but It looks like NX's NOT() function isn't bitwise, can I make a bitwise NAND?


SP4CEBAR 2021-10-04 18:12 (Edited)

this sort of works
FOR I=-7 TO 7
PRINT I,I AND (2^23-4)
NEXT I
I filled up most of the mantissa of the float
Unfortunately the negative numbers that are put in come out as being large and sort of overflowed numbers


nathanielbabiak 2021-10-04 20:10 (Edited)

You can create any bitwise operation as a combination of other bitwise operations. For NAND, you can do this.

The desired output sequence has more than 15 entries. What are the input values (or modified loop instructions) that yield those 20 outputs?


rilden 2021-10-04 22:17

@SP4CEBAR this will give you the correct sequence:
FOR I=-7 TO 7
PRINT I,INT(I/4)
NEXT I


SP4CEBAR 2021-10-05 10:40 (Edited)

Wait, so integer division isn't the same as NX integrated integer division, that's interesting

@natanielbabiak it's nice that a NAND gate can be constructed out of NOR gates, unfortunately that still requires a bitwise NOT gate


SP4CEBAR 2021-10-05 10:40

Thanks for all the answers and support!


nathanielbabiak 2021-10-05 11:34 (Edited)

For a bitwise not, you can use XOR $FF (8 bit), or XOR $FFFF (16 bit), or XOR $FFFFFF (24 bit). Doesn't the plain old NOT instruction also work too?


SP4CEBAR 2021-10-05 13:36 (Edited)

@nathanielbabiak thanks, that would work but idk how reliable it is for the floats in NX, according to my experiments the NOT instruction does: -(input)-1, which doesn't seem to look like bitwise NOT


nathanielbabiak 2021-10-05 13:46

It's providing a signed 32 bit result, rather than an unsigned result. NOT 0 = -1 = $FFFFFFFF.


SP4CEBAR 2021-10-05 13:55

So the value -1 has all mantissa bits high?, that would make sense


SP4CEBAR 2021-10-05 14:00 (Edited)

Either way, I've used the X AND 3, and the INT(X/4) to map the cell coordinates in my Chunk Loader and it all works without any problems. Thanks again for all the support!


CubicleHead 2021-10-12 12:58

I can't understand any of this but it is hilarious to read it out loud


SP4CEBAR 2021-10-12 20:41 (Edited)

Yeah, The mixture of code and English really makes a nice blend


Log in to reply.