Follow

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?

@neauoire @winduptoy Can you do multiplication?

@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.

result = (thing * coefficient) >> 8

a coefficient of 0 to 256 would be same as 0.0 to 1.0

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

@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 #00c0.

Start with 86 on the stack → 86,

“#00 SWP” → 00 86,

“#00c0”, 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 This is such a great question that I made it a website post!

https://ald.nu/notes/uxn/scaling-shorts/

gemini://ald.nu/notes/uxn/scaling-shorts/

Devine Lu Linvega@neauoire@merveilles.town@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.