Expressing X/Y as a Percentage

Armp

Senior Member
I'm converting some code over to Picaxe, and need to express the ratio of two unsigned 16 bit integers as a percentage in the form pp.p%.

The original 32 bit code was simple:

A = 1000 * x / y ' Given x<=Y. Returns 0 - 1000 for all values. ie 3/4 = 750; 45000/60000 = 750.

I just can't seem to find an 'elegant' way to do this on a 20M2. All efforts so far have required loops, shifts, iterations or other unnatural actions.

I know I can get the MSW and LSW of 1000*x - but then what?

Suggestions?
 

hippy

Ex-Staff (retired)
I know I can get the MSW and LSW of 1000*x - but then what?
You can get MSW / y and also MSW // y to get the remainder but how the reminder is best used with LSW / y I'm not sure.

I think you're going to end up with 'unnatural actions' no matter what, simply because the PICAXE isn't 32-bit natively. I think you can do a division of 32-bit by 16-bit in just 16 loops maximum and that's probably what I'd use if no "maths wizard" stepped forward with an answer. There should be a number of examples on the web and it should just be a case of converting to PICAXE basic, but that may be easier said than done.
 

Armp

Senior Member
What are the maximum values of X & Y your code will be dealing with?
65535 theoretically, but it should not normally exceed 60000.

I think you're going to end up with 'unnatural actions' no matter what, simply because the PICAXE isn't 32-bit natively. I think you can do a division of 32-bit by 16-bit in just 16 loops maximum and that's probably what I'd use if no "maths wizard" stepped forward with an answer. There should be a number of examples on the web and it should just be a case of converting to PICAXE basic, but that may be easier said than done.
Yup - that's what I was afraid of! I was just hoping there was a 'trick' I'd missed as I'm getting rather short of space - but google didn't find one. Sure feels like there should be one :cool:
 

Technical

Technical Support
Staff member
When you get to high numbers you won't loose much resolution (you only seem to want 1 decimal place) by scaling (pre-dividing) right at the start.

So if, for instance in the 45000 / 60000 case you could prescale
x = x / 1000
y = y / 1000
then run the formula

So you could possibly first check if X and Y are high values and then scale them accordingly.
 

Armp

Senior Member
So you could possibly first check if X and Y are high values and then scale them accordingly.
Yup - tried that, comes under the heading 'unnatural'!

Then I tried along the lines of this pseudocode:

If X<66 X=X*1000
If X<656 X=X*100 Y=Y/10
if X<6554 X=X*10 Y=Y/100
else y=y/1000
A=X/Y
But not close enough... Need to bring that MSW in somehow....
 

Armp

Senior Member
Tried a different approach using Divide and Modulus.
Pretty good : +/- 2 over most of the values I tried.
Need to tweak the scaling a bit, then try to break it!
Suggestions and comments welcomed....

'Given X<=Y, Y<>0. Calculates ratio as 0->1000.

DO WHILE X > 3276 ' Scale so X <65535/20 to avoid overflow.
X = X+1/2
Y = Y+1/2
LOOP

Z = X*20/Y*50 ' Get Quotient of 1000*X/Y
Res = X*20//Y *20/y*5+1/2 + Z ' Process Remainder and ADD
 

Armp

Senior Member
Solved???

This looks like it works - but I can't prove it for all values! Any volunteers?

'Symbols for Arguments
Symbol X = w0
Symbol Y = w1
Symbol Z = w2
Symbol Mult = w3

'Test Case
x=466
y=10000

'Fract1000: ' X<=Y, Y>0 Result Z=1000*X/Y

'If X<>0 AND Y<>0 then ' Redundant data check....

Mult = Y/X ' PreCondition X
X=X*Mult

Z = Y/3276+1 ' Scale X,Y to avoid overflow
X = X/Z : Y = Y/Z

Z = X*20/Y*50 ' Get Quotient
Z = X*20//Y *20/Y*5+Mult/2 + Z / Mult ' Process Remainder and ADD

'Else Z=0 'X or Y was 0

'EndIf


'Return
61 bytes....
 
Top