Page 1 of 1
Unsigned division ?
Posted: Sat Mar 01, 2008 1:26 am
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.
Posted: Sat Mar 01, 2008 1:41 am
by peterb
convert long to quad and back to long
Integer.l = $FFFFFFFE
res.q = Integer & $FFFFFFFF / 2
Integer = res
Debug Integer
Posted: Sat Mar 01, 2008 12:15 pm
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)
Posted: Sat Mar 01, 2008 3:15 pm
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 ?

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

Posted: Sat Mar 01, 2008 5:17 pm
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.
Posted: Sat Mar 01, 2008 5:39 pm
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.
Posted: Sat Mar 01, 2008 5:58 pm
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.
Posted: Sat Mar 01, 2008 6:18 pm
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.
Posted: Sat Mar 01, 2008 11:28 pm
by Dare
Posted: Sun Mar 09, 2008 4:00 am
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
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 "/"
