News:

;) This forum is the property of Proton software developers

Main Menu

Div by 65535

Started by TimB, Nov 27, 2025, 11:52 AM

Previous topic - Next topic

TimB

Hi All

I have an averaging routine where I total ADC values into a Dword, I keep a count of the no of additions using a word var and when it rolls over I divide the Dword by 65535

If I use word = dword / 65535 it uses the built in Dword div routine. So I decided I would just swap bytes

                    wADCAvrg = dNCOptoAvrhh                                      ; This is a very quick way to / by 65535
                    wADCAvrgh = dNCOptoAvrhhh

However looking at the asm I see that the compiler is actually not working the way I though it would and is doing the job just with the first line
See that asm

F1_001208 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] wADCAvrg = DNCOPTOAVRHH
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH
    movff CheckForOptoDriftdNCOptoAvrHH,CheckForOptoDriftwADCAvrg
F1_001209 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] WADCAVRGH = DNCOPTOAVRHHH
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH 

My question is... Is it ok to use that to do the div just have the line

wADCAvrg = dNCOptoAvrhh

And use the fact the compiler knows the var is a word and transfers both bytes or do something else


RGV250

#1
Hi Tim,
My first thought is to shift the Dword left x 16 which would probably be simpler?

I think that would divide by 65536 though if that extra 1 makes a difference.

Regards,
Bob

JonW

Your original thought about dividing by 65535 was spot-on for the averaging use case though. Here's the thing: when you're accumulating ADC samples into a DWORD and using a WORD counter, you naturally hit the rollover at 65536 (2^16). At that point, dividing by 65536 gives you the average, which is mathematically correct. The "divide by 65535" idea would only be needed if you were doing something like accumulating exactly 65535 samples and then averaging - but with a WORD counter rolling over naturally, 65536 is your natural boundary.

I'm with Bob that a shift (right, not left, right Bob?  ;D ) by 16 bits is your cleanest approach:

wADCAvrg = dNCOptoAvrHH >> 16

This is more explicit about what you're doing (dividing by 65536), the compiler will generate minimal code for it, and it's immediately obvious to anyone reading the code what the intent is. Much cleaner than either the byte-swapping approach or implicit assignment from DWORD to WORD, but I like the way you have thought about it.


RGV250

Quote(right, not left, right Bob?  ;D )
Oops, I actually thought right and then changed my mind without putting it on paper to check. Definitely a senior moment.

Bob

TimB

Thanks

Yes roll over on a word is 65536 not 65535

I double checked what was produced with dword / 65536 and its still a complex div call

wADCAvrg = dNCOptoAvr >> 16

Produces the same code as
wADCAvrg = dNCOptoAvrhh


F1_001151 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] wADCAvrg = dNCOptoAvr >> 16
    movff CheckForOptoDriftdNCOptoAvrHH,CheckForOptoDriftwADCAvrg
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH

F1_001153 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] wADCAvrg = DNCOPTOAVRHH
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH
    movff CheckForOptoDriftdNCOptoAvrHH,CheckForOptoDriftwADCAvrg

JonW

The compiler is smart as, but I prefer the >>

Bob. you got me thinking too  haha

Fanie

#6
Quote from: TimB on Nov 27, 2025, 01:06 PMF1_001151 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] wADCAvrg = dNCOptoAvr >> 16
    movff CheckForOptoDriftdNCOptoAvrHH,CheckForOptoDriftwADCAvrg
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH

F1_001153 equ $ ; in [OPTO_STEPPER RS485 V2.BAS] wADCAvrg = DNCOPTOAVRHH
    movff CheckForOptoDriftdNCOptoAvrHHH,CheckForOptoDriftwADCAvrgH
    movff CheckForOptoDriftdNCOptoAvrHH,CheckForOptoDriftwADCAvrg


Now you know where the hieroglyphics in the pyramids come from.
Translated - "And in these four scrolls they divided by 65536"
Why, remains a mystery.

John Lawton

Ah, the good old days:

Dim L as Integer

Variable names can be <too> long :)

John

Wimax

#8
Hi Tim,

Please, let me know if this could be useful:


    Dim highb as DWord
    Dim lowb  as DWord
    Dim s    as DWord
    Dim carry as DWord
    Dim Ro as DWord

    highb = x>>16    ' Integer division by 2^16
    lowb = x & 0xFFFF' Takes 16 LSB
    s = highb + lowb

    carry = 0
    IF s >= 65535 THEN Inc carry
    IF s = 131070 THEN Inc carry

   Ro = high + carry

;)

Frizie

High and Low are compiler keywords...
Ohm sweet Ohm | www.picbasic.nl

Wimax

Thank you for your comment  ;) . Code written but not tested, changed the variables