Uxn folks:

Maybe my brain is just dragging today.

I have a bunch of bytes in the range 0-255 that I need to scale down uniformly by some coefficient. In the absence of floats, how would I do this?

· · Web · · ·

@winduptoy Multiple people have tried to explain binary division to me over the years and it still hasn't sunk in. I've done my best to always do without.

It has to do with shifting the divider left, so 0.8 becomes 8, then doing your operation, then shift-right to cull the decimals. I don't know beyond that.

@neauoire @winduptoy Can you do multiplication?

@loke @neauoire
I've got a bunch of values between 0-255 and I need them all scaled uniformly down by x. I'm guessing x would be an integer between 0-255 where 0 represents 0.0 and 255 represents 1.0. If that can be done with integer multiplication, I'd love to know how.

@neauoire @winduptoy If you have multiplication available, then consider your 8-bit number as a fixpoint number in the range 0 to 1.

The scale factor is also going to be a fixpoint in the range 0 to 1, so 0.8 is going to be 0.8*255 = 204.

So, to scale your number by 0.8, all you have to do is to multiply it by 204 and shift the result right by 8 bits: (n*204) >> 8

*writes it down*

@neauoire Thanks for the direction! I'll post something when I get it figured out.

@winduptoy now that I think about it, @brendan is probably the best person to ask for this.

@neauoire @winduptoy yeah, if you can express the scaling factor as a rational with a power of two divisor, you can do integer multiplication and a bit shift

@winduptoy if you load your byte into a 16bit register and do same for your coefficient. multiply them together and shift that right by 8 bits
result = (thing * coefficient) >> 8
a coefficient of 0 to 256 would be same as 0.0 to 1.0

@winduptoy

convert the coefficient to an unsigned short - if it's between 0 and 1, multiply it by 256, take the integer part, and then do 00 SWAP
convert the bytes to unsigned shorts (again, 00 SWAP)
MUL2-iply each of the resulting shorts by the short coefficient, for a short result in the range 0..65025
DROP the low byte of the result (or, if you want to get fancy, shift it right 7 places and add it to the high byte)

not knowing uxn all that well, i'm not going to attempt to actually write source for it, but hopefully this is enough of a leg-up

not sure whether this is helpful, but this is how one might do it on a 6803:

ldx #(ARRAY)
loop:
lda 0,x
ldb #(int(COEFFT*256))
mul ; A:B ← A * B
lslb ; if you want to round
sta 0,x ; ignore B now
inx
cpx #(ARRAY_END)
bne loop

@winduptoy Just to say @millihertz has the approach spot on here, well done! 😊

Let's say 0x86 is your byte to scale, and the scaling factor is ¾. We use units of 1/256 so the scaling short is written as .

“#00 SWP” → 00 86,
”, the scaling factor → 00 86 00 c0,
“MUL2” → 64 80,
“POP” → 64, your result ✅

(You can also see that it rounds down, if anyone needs to round to the nearest integer you can put “#0080 ADD2” between the MUL2 and the POP.)

@alderwick @millihertz EXCELLENT! Thank you everyone!!! I should have something cool to share soon!

@alderwick I see that this logic works exactly the same for shorts.
(0x0190 times 0x00c0 = 0x012c00, POP = 0x012c)
(400 times ¾ = 300)

However, that third byte in 0x012c00 presents a problem for Uxn. MUL4 does not exist, so do you have any tips on accomplishing the same thing with shorts without having to summon a demon? I'm imagining the solution looks like a gnarly mess of shifting and popping, and I have no clue how to make the highest bits carry over into something bigger than a short...

@winduptoy the starling codebase has large integer multiplication methods, if you need them.

@winduptoy the technique I use is to multiply the bytes of the large integers as shorts so that all the overflow is accounted for.

@winduptoy This is such a great question that I made it a website post!

@alderwick 🤩 Unbelievably helpful! I love the learning and sharing on Merveilles, absolutely the best community. Thanks Andy!

Revel in the marvels of the universe. We are a collective of forward-thinking individuals who strive to better ourselves and our surroundings through constant creation. We express ourselves through music, art, games, and writing. We also put great value in play. A warm welcome to any like-minded people who feel these ideals resonate with them.