Abs(quad.q)

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
juergenkulow
Enthusiast
Enthusiast
Posts: 581
Joined: Wed Sep 25, 2019 10:18 am

Abs(quad.q)

Post by juergenkulow »

Please change in documentation Abs:

Code: Select all

@Function Result.f(.d)(.q) = Abs(Number.f(.d)(.q))

@Description
  Returns the absolute value of the given value.

@Parameter "Number.f or Number.d or Number.q" 
and add in pbcompilerc

Code: Select all

; q=Abs(quad.q)
!v_q= llabs(v_q);
See: Strange behavior of Abs()
SMaag
Enthusiast
Enthusiast
Posts: 302
Joined: Sat Jan 14, 2023 6:55 pm
Location: Bavaria/Germany

Re: Abs(quad.q)

Post by SMaag »

here a first solution for the ABS() Problem in C-Backend when using values with more than 53Bits

To see the Bug: Use C-Backend and set CPU to MMX/SSE Version or activate 'Optimize generated code'

Updated!

Code: Select all


; This is a test to solve tha PB's ABS() Problem at C-Backend
; because at ASM Backend the 80Bit Float unit is used for ABS() what works perfect for 64Bit INT
; In C-Backend a MMX Version is used for ABS(). This is a problem because MMX use only 64Bit Floats
; with a manitassa of 53 Bits. This will cause bugs if the ABS() is used for values with more bits
; like address calculation!

; Assembler_ShiftArithmeticRight_Bits : This is how to cacluclate the NumberOfBits to shift
; its 63 for x64 und 31 for x32
#ABS_SAR_BITS = (SizeOf(Integer)*8-1)    

; This is the optimized Abs Version (translated from Assembler to PB-Code; Soure Math.asm from Linux Asm Project
; X!(X>>63)-(X>>63) ; x64
; X!(X>>31)-(X>>31) ; x32

; PB 6.04 on Ryzen 5800 the Macro is nearly same speed as PB's ABS()
; for 50Mio calls PB_ABS() = 53ms  AbsI = 58ms
Macro AbsI(X)
   (X!(X>>(SizeOf(Integer)*8-1))-(X>>(SizeOf(Integer)*8-1)))
EndMacro

; only for x32 we need an extra Macro for AbsQ() which shifts 63 Bit for Quads
CompilerIf #PB_Compiler_Backend =#PB_Backend_Asm
  Macro AbsQ(X)
    Abs(X)
  EndMacro
CompilerElse  ; C-Backend
  Macro AbsQ(X)
    (X!(X>>63)-(X>>63))
  EndMacro
CompilerEndIf

Procedure procAbs(X)
  CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
    CompilerIf #PB_Compiler_64Bit
      !MOV RDX, [p.v_X]
      !MOV RAX, RDX
      !SAR RDX, 63
      !XOR RAX, RDX
      !SUB RAX, RDX
      ProcedureReturn 
    CompilerElse
      !MOV EDX, [p.v_X]
      !MOV EAX, EDX
      !SAR EDX, 31
      !XOR EAX, EDX
      !SUB EAX, EDX
      ProcedureReturn   
    CompilerEndIf
    
  CompilerElse ; C-Backend
    ProcedureReturn X!(X>>63)-(X>>63)
  CompilerEndIf
EndProcedure

Define I, K, L, N, t1, t2, t3

CompilerIf #PB_Compiler_Debugger
  ; to see the Bug you have to switch on Compiler\Compiler Options\Optimze generated code
  ; or set CPU with MMX/SSE 
   N = 1234567891234567890   ; in C Backend the difference is 46
  ; N =  1<<54 -1             ; in C Backend the difference is 1
  Debug "N = " + N
  Debug "Hex(N) = " + Hex(N)
  Debug #Null$
  
  Debug "In C-Backend this is wrong! If Compiler\Compiler Options\Optimze generated code is activated or MMS/SSE CPU is selected"
  K = Abs(N)
  Debug "PB Abs(N)  = " + K
  K = Abs(-N)
  Debug "PB Abs(-N) = " + K

  Debug #Null$
  Debug "Macro AbsI()"
  K = AbsI(N)
  Debug K
  K = AbsI(-N)
  Debug K
  
  Debug #Null$ 
  K = AbsI(N)
  L= Abs(N)
  K -L
  Debug "AbsI(N) - Abs(N) = " + K
  Debug "The difference should be 0 but in C-Backend it is not!"
  
CompilerElse
  
  #Start = 100000000000000005
  #LOOPS = 50000000  ; 50Mio
  
  t1 = ElapsedMilliseconds()
  For I = 1 To #LOOPS
    K =  AbsI(-I)
    L =  AbsI(I)
  Next
  t1 = ElapsedMilliseconds() - t1
  
  t2 = ElapsedMilliseconds()
  For I = 1 To #LOOPS
    K =  Abs(-I)
    L =  Abs(I)
  Next
  t2 = ElapsedMilliseconds() - t2
  
  t3 = ElapsedMilliseconds()
  For I = 1 To #LOOPS
    K =  procAbs(-I)
    L =  procAbs(I)
  Next
  t3 = ElapsedMilliseconds() - t3
  
  MessageRequester("Time", "Macro AbsI() = " + Str(t1) + #CRLF$ + "PB Abs() = " + Str(t2)+ #CRLF$ + "ASM procAbs() = " + Str(t3))
CompilerEndIf
Post Reply