Unsigned division ?

Just starting out? Need help? Post your questions and find answers here.
Phlos
User
User
Posts: 85
Joined: Fri May 16, 2003 7:17 pm

Unsigned division ?

Post by Phlos »

Hello,

How can I do a unsigned division with long ?

Code: Select all

Integer.l = $FFFFFFFE
Integer / 2
Debug Hex(Integer)
PureBasic handles only signed value, so it will output -2 / 2 = -1 = $FFFFFFFF
But how can I get the good result ($7FFFFFFF) ?

Thank you.
peterb
User
User
Posts: 60
Joined: Sun Oct 02, 2005 8:55 am
Location: Czech Republic
Contact:

Post by peterb »

convert long to quad and back to long

Integer.l = $FFFFFFFE
res.q = Integer & $FFFFFFFF / 2
Integer = res
Debug Integer
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Or with inline asm:

Code: Select all

Macro Div2(Integer)
  EnableASM
  mov eax, Integer
  shr eax, 1
  mov Integer, eax
  DisableASM
EndMacro

Integer.l = -2
Div2(Integer)
Debug Hex(Integer)
Phlos
User
User
Posts: 85
Joined: Fri May 16, 2003 7:17 pm

Post by Phlos »

Thank you, I knew for both solution...but the quad is not a solution (if I have the same problem with quad what I do ? :D +very slow with quad !), and the asm one make the source code quite bad to read and implement (the division by 2 was just an easy example, I have a lot of division to do and not by 2^x) :/

So Pure basic can't do a proper unsigned division, what a shame for a programming language... :evil:
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

You can divide by anything with this code.

Code: Select all

Procedure Div(A, B)
  !mov eax, [p.v_A]
  !xor edx, edx
  !div dword [p.v_B]
  ProcedureReturn 
EndProcedure
Although I somehow doubt you need to use unsigned numbers.
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi Phlos.

Will you really be dealing with unsigned quads that have the high order bit set? That is a huge number!

For longs, use quads. It is easier and accurate.

For quads, worry about that when you get to it!


However here is something done for longs that could be quad-ified ..

Your question has been niggling at me since I saw it. I went to bed and it continued to niggle and then a thought occurred so I got up and tried it. It is now pushing 3am and I am woozy (and it all your fault!) so forgive this bit of code :)

And this, BTW, still has to iron out an inaccuracy of +/- 1 in some cases. However it should handle division by any value within that qualification. I will look at it again in the morning (later this morning) and either fix the issue or think "idiot, what were you thinking" and abandon it. :)

Code: Select all

; Note that if we divide by 1 and are returning a long, result will be -ve (and unchanged value)
; This should give a result accurate +/- 1 
;        .. Not yet worked out sure how to fix the inaccuracy

Procedure uLongDiv(value.l, divisor.l)

  If value >= 0                   ; If positive, do normal divide
    result = value / divisor      ;   This eliminates inaccuracies here

  Else                            ; Otherwise ..
    temp = value >> 1             ;   Halve the value by shifting right
    temp & $7FFFFFFF              ;   Mask out the high bit (because the shift is arithmetic)
    result = temp / divisor       ;   Divide
    result << 1                   ;   Double result by shifting left (or just * 2)
    temp = value & $01            ;   Mask out all but the low bit of value
    temp / divisor                ;   Divide again (just in case we are dividing by 1)
    result + temp                 ;   Combine the two results
  EndIf
Debug result
  ProcedureReturn result
EndProcedure

v.q = $0FFFFFFFF
Debug v / 2
Debug v / 3
Debug v / 4
Debug v / 5
Debug v / 6
Debug v / 7
Debug v / 99

Debug "============="

r = uLongDiv(-1,2)
r = uLongDiv(-1,3)
r = uLongDiv(-1,4)
r = uLongDiv(-1,5)
r = uLongDiv(-1,6)
r = uLongDiv(-1,7)
r = uLongDiv(-1,99)
Edit and PS

The above is just broken down into steps so that I could think it through. You could make it tighter.

And if you fix the 1-out inaccuracy, let us know how.

Night.
Dare2 cut down to size
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Gah.

Just got back into bed and realised that the blooming divisor could have the high order bit set.

In which case I assume you return 0 (truncate) as this would be dividing by a value over half the size?


And an asm solution is probably the real go, there must be asm code that shows dividing (by other then 2,4,8 (shifting)).

And I really think you won't need quads that big!

Please don't ask another question like this as I need my sleep. :)

Night.
Dare2 cut down to size
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

And an asm solution is probably the real go, there must be asm code that shows dividing (by other then 2,4,8 (shifting)).
Just look above your posts.
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

:D
Dare2 cut down to size
Phlos
User
User
Posts: 85
Joined: Fri May 16, 2003 7:17 pm

Post by Phlos »

Thank you Dare & Trond.

You can do any procedure you want (in pure basic or asm), but this is not a good way. It should be fixed in "low level" by Fred... unsigned is a must have for any programming language.

Do you really want to code a big app by that way :

b = $FFFFFFFF
a = (Div(Div(b, 53), 23)) + 43

Or by that way ?

b.u = $FFFFFFFF
a.u = ((b / 53) / 23 + 43)

That's hard to read your code when you are calling functions to make basic arithmetic operations, well that's just insane :shock:

If Fred doesn't want to waste his time with unsigned integer, he should provide us a way to redefine operators like in C++, so we can easily do your solution and still have an easy readable code with operator "/" :D
Post Reply