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