Absolute Val for Integers?

Just starting out? Need help? Post your questions and find answers here.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Absolute Val for Integers?

Post by wilbert »

I don't see a reason for a $8000000000000000 exception as the problem is not really with the abs function.
If you look at the input value as a signed integer (which it is) and the output value as an unsigned integer (which it is) the returned value is fine.
The main problem is that PB doesn't support unsigned integers.
If you format the output as an unsigned integer, it will show 9223372036854775808.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Absolute Val for Integers?

Post by idle »

wilbert wrote:I don't see a reason for a $8000000000000000 exception as the problem is not really with the abs function.
If you look at the input value as a signed integer (which it is) and the output value as an unsigned integer (which it is) the returned value is fine.
The main problem is that PB doesn't support unsigned integers.
If you format the output as an unsigned integer, it will show 9223372036854775808.
I don't think it's an exception either but it just means you need to check the result is > 0
it's still a valid point though and if you wanted to do a bool comparison with it wrapping it to 0 makes sense
even so it's still not ideal but as an inline macro it's not to far from the optimal solution.

Code: Select all

Macro IABS(v) ;in place no branching and gets peep hole optimized with overflow to 0 
   (((v) ! ((v)>>((SizeOf(integer)<<3)-1))) - ((v)>>((SizeOf(integer)<<3)-1))) ;& ($8000000000000000-1)
EndMacro
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Absolute Val for Integers?

Post by Josh »

Why should AbsI check for an exception? You already have the same problem with basic arithmetical operation:

Code: Select all

z.q = -9223372036854775808
Debug z
Debug 0 - z
Debug z - 1
To 99.99%, a program will not come into this range and if a programmer believes that this is a critical area for him, he must check the value by himself.


@Idle
That doesn't run at x86:

Code: Select all

Macro IABS(v) ;in place no branching and gets peep hole optimized with overflow to 0 
   (((v) ! ((v)>>((SizeOf(integer)<<3)-1))) - ((v)>>((SizeOf(integer)<<3)-1))) ;& ($8000000000000000-1)
EndMacro

                                 ; x86                 x64
Debug       $8000000000000000-1  ; 9223372036854775807 9223372036854775807
Debug Iabs ($8000000000000000-1) ; 9223372028264841217 9223372036854775807
sorry for my bad english
User avatar
Olliv
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Sep 22, 2009 10:41 pm

Re: Absolute Val for Integers?

Post by Olliv »

Good luck
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Absolute Val for Integers?

Post by idle »

@josh
The macro will work fine for integers but it won't work for quads on x86 and you can ignore the code after the comment.
that was for discussion on what to do on the range limit.
Windows 11, Manjaro, Raspberry Pi OS
Image
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Absolute Val for Integers?

Post by Little John »

wilbert wrote:As a macro ... :)

Code: Select all

Macro _Abs(n)
  ((n)*(Bool((n)>0)*2-1))
EndMacro

Debug _Abs(100 - 110564567689766987)
Debug _Abs(-2.75)
Cool. 8)
And pretty fast. Thank you!
I wonder why the built-in Abs() function is not implemented this way.
User avatar
NicTheQuick
Addict
Addict
Posts: 1504
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Absolute Val for Integers?

Post by NicTheQuick »

Little John wrote:
wilbert wrote:As a macro ... :)

Code: Select all

Macro _Abs(n)
  ((n)*(Bool((n)>0)*2-1))
EndMacro

Debug _Abs(100 - 110564567689766987)
Debug _Abs(-2.75)
Cool. 8)
And pretty fast. Thank you!
I wonder why the built-in Abs() function is not implemented this way.
Because there are way too many operations taking place: one comparison, two multiplications and one substraction. Also the paramater gets called twice which is a terrible idea when the parameter is a function call. There is a single ASM instruction which can convert a value to its absolute value. That would be the correct way for a built-in function.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Absolute Val for Integers?

Post by wilbert »

NicTheQuick wrote:There is a single ASM instruction which can convert a value to its absolute value. That would be the correct way for a built-in function.
That is the way the built-in function works but that single ASM instruction (fabs) operates on floating point values, not integer values.
For 32 bit integers it is accurate enough but for 64 bit integers it isn't. That is what is made clear in the first post from this thread.
A single ASM instruction to get the absolute value of a 64 bit integer value doesn't exist.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
NicTheQuick
Addict
Addict
Posts: 1504
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Absolute Val for Integers?

Post by NicTheQuick »

Making a float value positive is easy because you only have to clear one single bit.

But I didn't expect that there is no ASM instruction to make an integer positive. :shock:

Was this method already mentioned here? But the problem remains that v is called twice.

Code: Select all

Macro Abs_(v)
	((((v) >> 62) | 1) * (v))
EndMacro

a = -1876543

a = Abs_(a)

Debug a
Shitty IDE doesn't let me work anymore.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Absolute Val for Integers?

Post by mk-soft »

Only Integers

Update

Code: Select all

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Procedure AbsI(value.i)
    ! mov rax, qword[p.v_value]
    ! bt rax, 63
    ! jnb __absi_no
    ! not rax
    ! add rax, 1
    ! __absi_no:
    ProcedureReturn
  EndProcedure
CompilerElse
  Procedure AbsI(value.i)
    ! mov eax, dword[p.v_value]
    ! bt eax, 31
    ! jnb __absi_no
    ! not eax
    ! add eax, 1
    ! __absi_no:
    ProcedureReturn
  EndProcedure
CompilerEndIf

qVal.i = -2100
Debug AbsI(qVal)

lVal.l = -2200
Debug AbsI(lVal)
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Absolute Val for Integers?

Post by wilbert »

A small comparison between different ASM methods (x64).
On my computer there's very little difference in speed.

Code: Select all

Procedure AbsI(value.i)
  ! mov rax, qword[p.v_value]
  ! bt rax, 63
  ! jnb __absi_no
  ! not rax
  ! add rax, 1
  ! __absi_no:
  ProcedureReturn
EndProcedure

Procedure AbsI_2(value.i)
  !mov rax, [p.v_value]
  !cqo
  !add rax, rdx
  !xor rax, rdx
  ProcedureReturn
EndProcedure

Procedure AbsI_3(value.i)
  !mov rax, [p.v_value]
  !neg rax
  !cmovs rax, [p.v_value]
  ProcedureReturn
EndProcedure

n = 12345678

t1 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI(n)
Next
t2 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI_2(n)
Next
t3 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI_3(n)
Next
t4 = ElapsedMilliseconds()

MessageRequester("Results", Str(t2-t1)+" vs "+Str(t3-t2)+" vs "+Str(t4-t3))
Windows (x64)
Raspberry Pi OS (Arm64)
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Absolute Val for Integers?

Post by Little John »

NicTheQuick wrote:
Little John wrote:I wonder why the built-in Abs() function is not implemented this way.
Also the paramater gets called twice which is a terrible idea when the parameter is a function call.
I agree. However, this is only because that macro is written in a way so that it can be called like a function. A built-in function doesn't have to work exactly like this, but could copy the value of the parameter to a variable.
wilbert wrote:A small comparison between different ASM methods (x64).
On my computer there's very little difference in speed.
Same here on my computer.
And even a bit faster than any of these three procedures (using the same test code as you did) is

Code: Select all

Macro _Abs(n)
  ((n)*(Bool((n)>0)*2-1))
EndMacro
:-)
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: Absolute Val for Integers?

Post by Josh »

I don't know if I completely misunderstand something here, but what about a simple 0-x?

Code: Select all

Procedure AbsI(value.i)
  ! mov rax, qword[p.v_value]
  ! bt rax, 63
  ! jnb __absi_no
  ! not rax
  ! add rax, 1
  ! __absi_no:
  ProcedureReturn
EndProcedure

Procedure AbsI_2(value.i)
  !mov rax, [p.v_value]
  !cqo
  !add rax, rdx
  !xor rax, rdx
  ProcedureReturn
EndProcedure

Procedure AbsI_3(value.i)
  !mov rax, [p.v_value]
  !neg rax
  !cmovs rax, [p.v_value]
  ProcedureReturn
EndProcedure

n = 12345678

t1 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI(n)
Next
t2 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI_2(n)
Next
t3 = ElapsedMilliseconds()
For i=1 To 200000000
  r = AbsI_3(n)
Next
t4 = ElapsedMilliseconds()
For i=1 To 200000000
  If n < 0
    n = 0 - n
  EndIf
Next
t5 = ElapsedMilliseconds()

MessageRequester("Results", Str(t2-t1)+" vs "+Str(t3-t2)+" vs "+Str(t4-t3)+" vs "+Str(t5-t4))
sorry for my bad english
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Absolute Val for Integers?

Post by mk-soft »

I added AbsQ(Value)

Update
- Added wilberts code

Code: Select all

;-TOP
; AbsI and AbsQ
; By mk-soft and wilbert from 24.01.2019

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Procedure AbsI(value.i)
    !mov rax, [p.v_value]
    !neg rax
    !cmovs rax, [p.v_value]
    ProcedureReturn
  EndProcedure
CompilerElse
  Procedure AbsI(value.i)
    !mov eax, [p.v_value]
    !neg eax
    !cmovs eax, [p.v_value]
    ProcedureReturn
  EndProcedure
CompilerEndIf

CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
  Procedure.q AbsQ(value.q)
    !mov rax, [p.v_value]
    !neg rax
    !cmovs rax, [p.v_value]
    ProcedureReturn
  EndProcedure
CompilerElse
  Procedure.q AbsQ(value.q)
    ! lea    eax,dword[p.v_value]
    ! mov    edx,dword[eax+4]
    ! mov    eax,dword[eax]
    ! bt edx, 31
    ! jnb __absq_no
    ! not    eax
    ! not    edx
    ! add    eax,1
    ! adc    edx,0
    ! __absq_no:
    ProcedureReturn
  EndProcedure
CompilerEndIf

;-

Define iVal.i = $80000001

Debug AbsI(iVal)

Define qVal.q = $8000000000000001

r1.q = AbsQ(qVal)
Debug r1
Debug Hex(r1)
Last edited by mk-soft on Thu Jan 24, 2019 10:05 pm, edited 2 times in total.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
mk-soft
Always Here
Always Here
Posts: 6204
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Absolute Val for Integers?

Post by mk-soft »

P.S.
The third method by Wilbert is the fastest . The fourth method cannot return a return value and is therefore invalid.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Post Reply