Page 1 of 2

Posted: Sun Jun 02, 2002 3:26 pm
by BackupUser
Restored from previous forum. Originally posted by freak.

Hi All,

The PB Manual says for Abs():
This function works correctly only with float numbers. With integer it will fail if the integer is too big (losse of precision). Another function will be added to do that.
And the Pow() function works that way, too.

When are these other functions going to be added?
They would be very useful, since I don't use floats very much.

Please Fred, can u do that?

That's it...
Timo

--

A debugged program is one for which you have not yet found the conditions that make it fail.

Posted: Wed Sep 19, 2007 4:51 pm
by Bonne_den_kule
... can you do that?

Posted: Wed Sep 19, 2007 5:07 pm
by Kaeru Gaman
second!


@Bonne

as a workaround:
if you need n² or n³, it's better and faster than a Pow()-function to write (n*n) or (n*n*n)

Posted: Thu Sep 20, 2007 12:50 pm
by Dreamland Fantasy
Just do something like the following:

Code: Select all

Procedure.q AbsQ(Value.q)
  If Value < 0
    ProcedureReturn -Value
  Else
    ProcedureReturn Value
  EndIf
EndProcedure

Procedure.q PowQ(Number, Exponent)
  Protected Result.q = 1
  For i = 1 To Exponent
    Result * Number
  Next
  ProcedureReturn Result
EndProcedure

Debug AbsQ(-1234567890123456789)
Debug PowQ(3, 3)
Kind regards,

Francis.

Posted: Thu Sep 20, 2007 1:15 pm
by eesau
What I'd like to have is a ^ -operator for integer Pow().

Posted: Thu Sep 20, 2007 1:29 pm
by Kaeru Gaman
@DF

[edited]
I pimped your Proc a bit...

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number
  If Exponent = 2
    Result * Number
  ElseIf Exponent > 2
    For i = 2 To Exponent
      Result * Number
    Next
  ElseIf Exponent = 0
    Result = 1
  ElseIf Exponent < 0
    Result = -1
  EndIf
  ProcedureReturn Result
EndProcedure

Posted: Thu Sep 20, 2007 3:17 pm
by Dreamland Fantasy
Kaeru Gaman wrote:@DF

[edited]
I pimped your Proc a bit...

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number
  If Exponent = 2
    Result * Number
  ElseIf Exponent > 2
    For i = 2 To Exponent
      Result * Number
    Next
  ElseIf Exponent = 0
    Result = 1
  ElseIf Exponent < 0
    Result = -1
  EndIf
  ProcedureReturn Result
EndProcedure
Nice! :D

The only thing that's really missing is a check in case you get numerical overflow. I've used -2 as the error code.

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number
  If Exponent = 2
    Result * Number
  ElseIf Exponent > 2
    For i = 2 To Exponent
      Result * Number
      If Result < 0                  ; Check for numerical overflow
        ProcedureReturn -2
      EndIf
    Next
  ElseIf Exponent = 0
    Result = 1
  ElseIf Exponent < 0
    Result = -1
  EndIf
  ProcedureReturn Result
EndProcedure
Kind regards,

Francis.

Posted: Thu Sep 20, 2007 3:44 pm
by Kaeru Gaman
a simple <0 check is not sufficent, since a negative Base to an odd Exponent gives a correct negative result.

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number
  Protected Sign.l = 1
  If Exponent = 2
    Result * Number
  ElseIf Exponent > 2
    If Number < 0
      Result = -Result
      Number = -Number
      If Exponent % 2
        Sign = -1
      EndIf
    EndIf
    For i = 2 To Exponent
      Result * Number
      If Result < 0                  ; Check for numerical overflow
        ProcedureReturn -2
      EndIf
    Next
    Result * Sign 
  ElseIf Exponent = 0
    Result = 1
  ElseIf Exponent < 0
    Result = -1
  EndIf
  ProcedureReturn Result
EndProcedure
your check is correct to be performed in every step of the loop,
but it will significantly slow down the calculation.

Posted: Thu Sep 20, 2007 4:27 pm
by Dreamland Fantasy
Kaeru Gaman wrote:a simple <0 check is not sufficent, since a negative Base to an odd Exponent gives a correct negative result.
Very true.

Thinking about it further having negative numbers as error codes in this case would cause confusion if you get these numbers returned as legitimate results (e.g. PowQ(-1, 1)).

Kind regards,

Francis.

Posted: Thu Sep 20, 2007 5:34 pm
by Kaeru Gaman
I thought about it a little more...

I think, #Null would be a practicable result for an Error,
1. it's #False
2. only 0 as Base can cause 0 as Result, that can be easily checked before calling.

also, I tested overflow with <1, because also 0 can be an overflow.

all the rest, including the Sign check, remains the same.

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number ; Buffer Base to use as result for Exp.=1
  Protected Sign.l = 1        ; default sign for Result is +
  If Exponent = 2             ; for Exp.2
    Result * Number           ; spare Loop
  ElseIf Exponent > 2
    If Number < 0             ; Negative Base?
      Result = -Result        ; calculate with
      Number = -Number        ; Abs. Value
      If Exponent % 2         ; for odd Exponents
        Sign = -1             ; Buffer neg. Sign
      EndIf
    EndIf
    For i = 2 To Exponent     ; Loop for Exp.>2
      Result * Number
      If Result < 1           ; Check for numerical overflow
        ProcedureReturn 0   ; #False is Errorcode
      EndIf
    Next
    Result * Sign             ; sign Result
  ElseIf Exponent = 0         ; for Exp.=0
    Result = 1                ; no Calculation needed
  ElseIf Exponent < 0         ; for neg.Exp.
    Result = 0                ; #False is Errorcode
  EndIf
  ProcedureReturn Result
EndProcedure

Posted: Fri Sep 21, 2007 12:19 pm
by Dreamland Fantasy
Kaeru Gaman wrote:I thought about it a little more...

I think, #Null would be a practicable result for an Error,
1. it's #False
2. only 0 as Base can cause 0 as Result, that can be easily checked before calling.

also, I tested overflow with <1, because also 0 can be an overflow.

all the rest, including the Sign check, remains the same.

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number ; Buffer Base to use as result for Exp.=1
  Protected Sign.l = 1        ; default sign for Result is +
  If Exponent = 2             ; for Exp.2
    Result * Number           ; spare Loop
  ElseIf Exponent > 2
    If Number < 0             ; Negative Base?
      Result = -Result        ; calculate with
      Number = -Number        ; Abs. Value
      If Exponent % 2         ; for odd Exponents
        Sign = -1             ; Buffer neg. Sign
      EndIf
    EndIf
    For i = 2 To Exponent     ; Loop for Exp.>2
      Result * Number
      If Result < 1           ; Check for numerical overflow
        ProcedureReturn 0   ; #False is Errorcode
      EndIf
    Next
    Result * Sign             ; sign Result
  ElseIf Exponent = 0         ; for Exp.=0
    Result = 1                ; no Calculation needed
  ElseIf Exponent < 0         ; for neg.Exp.
    Result = 0                ; #False is Errorcode
  EndIf
  ProcedureReturn Result
EndProcedure
Nice! 8)

However, thinking about this even further you would still have problems under the following circumstance:

Code: Select all

Debug PowQ(9223372036854775806, 2)
This doesn't flag up as an overflow since Result is still positive and gives you an answer of 4. I've revised your code and added a check to catch this:

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number         ; Buffer Base to use as result for Exp.=1
  Protected Sign.l = 1                ; default sign for Result is +
  If Number < 0                       ; Negative Base?
    Result = -Result                  ; calculate with
    Number = -Number                  ; Abs. Value
    If Exponent % 2                   ; for odd Exponents
      Sign = -1                       ; Buffer neg. Sign
    EndIf
  EndIf
  For i = 2 To Exponent
    Result * Number
    If Result < 1 Or Result < Number  ; Check for numerical overflow
      ProcedureReturn 0               ; #False is Errorcode
    EndIf
  Next
  Result * Sign                       ; sign Result
  If Exponent = 0                     ; for Exp.=0
    Result = 1                        ; no Calculation needed
  ElseIf Exponent < 0                 ; for neg.Exp.
    Result = 0                        ; #False is Errorcode
  EndIf
  ProcedureReturn Result
EndProcedure
Kind regards,

Francis.

Posted: Fri Sep 21, 2007 12:51 pm
by Kaeru Gaman
Dreamland Fantasy wrote:This doesn't flag up as an overflow since Result is still positive and gives you an answer of 4. I've revised your code and added a check to catch this:
Fine! 8)
maybe now it's finish... good teamwork.

btw:
it would be freakin' easier in ASM, because an overflow sets a CPU-Flag,
so only one cheap branch-command is needed.

I don't know what's the command in x86-ASM, here's pseudocode:

Code: Select all

  For i = 2 To Exponent
    Result * Number
    !BranchOnCarryClear [Label]
      ProcedureReturn 0
    Label:
  Next 

Posted: Fri Sep 21, 2007 2:49 pm
by Dreamland Fantasy
Kaeru Gaman wrote:btw:
it would be freakin' easier in ASM, because an overflow sets a CPU-Flag,
so only one cheap branch-command is needed.
I came up with this code incorporating your suggestion:

Code: Select all

; Make sure Inline ASM is enabled

Procedure.q PowQ(Number.q, Exponent.q)
  Protected Result.q = Number         ; Buffer Base to use as result for Exp.=1
  Protected Sign.l = 1                ; default sign for Result is +
  If Number < 0                       ; Negative Base?
    Result = -Result                  ; calculate with
    Number = -Number                  ; Abs. Value
    If Exponent % 2                   ; for odd Exponents
      Sign = -1                       ; Buffer neg. Sign
    EndIf
  EndIf
  For i = 2 To Exponent
    Result * Number
    !JO l_fail                        ; Jump to fail if overflow flag is set
  Next
  Result * Sign                       ; sign Result
  If Exponent = 0                     ; for Exp.=0
    Result = 1                        ; no Calculation needed
  ElseIf Exponent < 0                 ; for neg.Exp.
    Result = 0                        ; #False is Errorcode
  EndIf
  ProcedureReturn Result
  
  fail:
  ProcedureReturn 0
  
EndProcedure

Debug PowQ(9223372036854775805, 2)
Debug PowQ(1000, 1000)
Both of the example cases should fail, but the first one still gives an answer, which is probably because the overflag hasn't been set since the sign of the number has not changed. But then, I'm not an expert on x86 assembly language so maybe my implementation is flawed.

Kind regards,

Francis.

Posted: Fri Sep 21, 2007 4:13 pm
by Kaeru Gaman
you made me getting my old ASM book from '93 out of the dustchest...

meanwhile I'm that far:

Code: Select all

buff1.l
buff2.l

!PUSHFD
!POP [v_buff1]

Debug Bin(buff1)

Debug 9223372036854775805*9223372036854775805

!PUSHFD
!POP [v_buff2]

Debug Bin(buff2)

End
so, there are obviously Flags set by the multiplication,
but I still have to look up wich flag is wich...

Posted: Sat Sep 22, 2007 12:48 pm
by Dreamland Fantasy
Kaeru Gaman wrote:you made me getting my old ASM book from '93 out of the dustchest...
:D

I've changed it from checking the overflow flag to the carry flag and that seems to work on the examples I've tried:

Code: Select all

Procedure.q PowQ(Number.q, Exponent.q) 
  Protected Result.q = Number         ; Buffer Base to use as result for Exp.=1 
  Protected Sign.l = 1                ; default sign for Result is + 
  If Number < 0                       ; Negative Base? 
    Result = -Result                  ; calculate with 
    Number = -Number                  ; Abs. Value 
    If Exponent % 2                   ; for odd Exponents 
      Sign = -1                       ; Buffer neg. Sign 
    EndIf 
  EndIf 
  For i = 2 To Exponent 
    Result * Number 
    !JC l_fail                        ; Jump to fail if carry flag is set 
  Next 
  Result * Sign                       ; sign Result 
  If Exponent = 0                     ; for Exp.=0 
    Result = 1                        ; no Calculation needed 
  ElseIf Exponent < 0                 ; for neg.Exp. 
    Result = 0                        ; #False is Errorcode 
  EndIf 
  ProcedureReturn Result 
  
  fail: 
  ProcedureReturn 0 
  
EndProcedure 

Debug PowQ(9223372036854775805, 2)    ; Should return 0 (fail)
Debug PowQ(1000, 1000)                ; Should return 0 (fail)
Debug PowQ(3,3)                       ; Should return 27
Debug PowQ(-3, 3)                     ; Should return -27
Kind regards,

Francis.