Jump to content
Sign in to follow this  
Uten

Some math udf's

Recommended Posts

Uten

Autoit is rather lame (slow) for this kind of algorithms. And my implementation is probably (certainly) not optimized. The C versions are like 1000 times faster, so now you are warned..;)

Func GetProperPositiveDivisors($num)
    Local $a[10]
    $a[0] = 0
    For $i = 1 to Floor($num/2)
        If mod($num, $i) = 0 Then 
            $a[0] += 1
            If $a[0] > Ubound($a) -1 Then ReDim $a[$a[0] + 10]
            $a[$a[0]] = $i
        EndIf
    next
    $a[0] += 1
    If $a[0] > Ubound($a) -1 Then ReDim $a[$a[0] + 10]
    $a[$a[0]] = $num
    ReDim $a[$a[0] + 1]
    Return $a
EndFunc
Func IsPerfectNumber($num)
    Local $res
    Local $a = GetProperPositiveDivisors($num)
    For $i = 1 to $a[0]
        If $a[$i] < $num Then $res += $a[$i]
    next
    ;ConsoleWrite("IsPerfectNumber[$num:=" & $num & ", $res:=" & $res & "]:=" & ($num = $res) & @crlf)
    return ($num = $res)
EndFunc
func factorsDump(ByRef $a, $head="", $tail= "")
    if $head = "" Then 
        ConsoleWrite("Factors( count:=" & $a[0] & ") : ")
    Else
        ConsoleWrite($head)
    EndIf
    for $i = 1 to $a[0]
        ConsoleWrite($a[$i] & ", ")
    Next
    ConsoleWrite(@CRLF)
EndFunc

func GetFactors($num)
    ; Return an array with all factors of a given number.
    ; NOTE: This function will fail (not return the smallest factors) for 
    ; numbers that is dividable by primes bigger than 997.
    ; To solve that we could increase the prime table or let the function 
    ; calculate the primes needed if it reache a undetermined situation
    ;SOURCE PRIMES: http://en.wikipedia.org/wiki/List_of_prime_numbers#The_first_500_prime_numbers
    Local $primes = "2 ,3 ,5, 7 ,11 ,13 ,17 ,19 ,23 ,29 ," & _
    "31 ,37 ,41 ,43 ,47 ,53 ,59 ,61 ,67 ,71 ," & _
    "73 ,79 ,83 ,89 ,97 ,101 ,103 ,107 ,109 ,113 ," & _
    "127 ,131 ,137 ,139 ,149 ,151 ,157 ,163 ,167 ,173 ," & _
    "179 ,181 ,191 ,193 ,197 ,199 ,211 ,223 ,227 ,229 ," & _
    "233 ,239 ,241 ,251 ,257 ,263 ,269 ,271 ,277 ,281 ," & _
    "283 ,293 ,307 ,311 ,313 ,317 ,331 ,337 ,347 ,349 ," & _
    "353 ,359 ,367 ,373 ,379 ,383 ,389 ,397 ,401 ,409 ," & _
    "419 ,421 ,431 ,433 ,439 ,443 ,449 ,457 ,461 ,463 ," & _
    "467 ,479 ,487 ,491 ,499 ,503 ,509 ,521 ,523 ,541 ," & _
    "547 ,557 ,563 ,569 ,571 ,577 ,587 ,593 ,599 ,601 ," & _
    "607 ,613 ,617 ,619 ,631 ,641 ,643 ,647 ,653 ,659 ," & _
    "661 ,673 ,677 ,683 ,691 ,701 ,709 ,719 ,727 ,733 ," & _
    "739 ,743 ,751 ,757 ,761 ,769 ,773 ,787 ,797 ,809 ," & _
    "811 ,821 ,823 ,827 ,829 ,839 ,853 ,857 ,859 ,863 ," & _
    "877 ,881 ,883 ,887 ,907 ,911 ,919 ,929 ,937 ,941 ," & _
    "947 ,953 ,967 ,971 ,977 ,983 ,991 ,997"
    $primes = StringSplit($primes, " ,")

    ;Local $primes = StringSplit("2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113",",")
    ; Calculate the factors in $num
    Local $size = 10
    Local $factors[$size]
    $factors[0] = 0
    Local $pos = 1

    While $pos <=$primes[0] AND $num > 1
        If mod($num, $primes[$pos]) = 0 Then 
            $factors[0] += 1
            If $size -1 < $factors[0] Then ReDim $factors[$factors[0] + 10]
            $factors[$factors[0]] = $primes[$pos]
            $num = $num/$primes[$pos]
            ; Do not change $pos as we might want the same prime again!
        Else
            $pos += 1
        EndIf
    WEnd
    If $num > 1 then 
            $factors[0] += 1
            If $size -1 < $factors[0] Then ReDim $factors[$factors[0] + 10]
            $factors[$factors[0]] = $num
    EndIf
    Return $factors
endfunc

EDIT: Something funny was inserted at the bottom of my code. Looked like binary stuff? Thanks to nahuel for pointing it out..:P

Edited by Uten

Share this post


Link to post
Share on other sites
Nahuel

Cool, but the forum messed up your post :P

I made some math UDF's too. I never shared because I think they are not really useful. Still, fun making.

;============
;Returns the n-th Fibonacci number
;Author: Nahuel
;============
Func Fibonacci($n)
    If Not IsInt($n) Then Return -1
    If $n < 0 Then Return -1
    If $n < 2 Then
        Return $n
    Else
        Return (Fibonacci($n-1) + Fibonacci($n-2))
    EndIf
EndFunc

;=============
;Returns the n-th triangular number
;Author: Nahuel
;=============
Func Triangular($n)
    If Not IsInt($n) Then Return -1
    If $n < 0 Then Return -1
    If $n > 0 then
       $tri = Triangular( $n- 1) + $n
    else
       $tri=0
   EndIf
   Return $tri
EndFunc

;=============
;Returns the factorial of a non-negative integer (up to 170)
;Author: Nahuel
;=============
Func Factorial($n)
    ;Check parameters
    If Not IsInt($n) Then Return -1
    If $n < 0 Then Return -1
    If $n >170 Then Return -1
    ;Do the math
    If $n <=20 Then
        Local $a=1
        For $i=1 To $n
            $a = $a*$i
        Next
    Else
        Local $a=0.1e1
        For $i=0.1e1 To $n
            $a = $a*$i
        Next
    EndIf
    Return $a
EndFunc

Share this post


Link to post
Share on other sites
Uten

@Nahuel. Thanks for the compliment and pointing out the funny stuff in the post. Wonder where that came from?

Share this post


Link to post
Share on other sites
Nahuel

It's a forum bug with the auoit tags. You probably edited your post? It has happened to me lots of times.

Share this post


Link to post
Share on other sites
SkinnyWhiteGuy

Cool, but the forum messed up your post ;)

I made some math UDF's too. I never shared because I think they are not really useful. Still, fun making.

*snip*oÝ÷ Ûú®¢×­çÚrÚ+yÛazÇ­ê-êÝk&Ú±çhÊ&yÊxÂÚòx-¢·¹Ç­æ}ç-¶­­ç.®È¯yÆ¥Ì(ºWaj÷¨«2²×¦jw_¢éݶ¬yû§rبËhÂäªè­{¥.­:âjx.ªÚÑbnÚqȲ©eË
.Û%£hÂ|"¶î·«±¦è½ë˹ëhjYmêÞrêì÷jYlÜ(ºWaj÷­¢f¤xm­é·«¶Ø«z¶§¶ØZ´ÞiÜ"¶azaz·(uæî¶+pjËܨ¹Ê.Ö¥-jÊÊÞ}§-¢·(uëhgyçm¡Ú"µ©ÝÂ+a¶¬yû§rب«yÚ.¶0b«§-¢¸¬";¬¶ëu§b}÷«z{lÊ{ZÆØZ¶+,(!¶jË^­»­²Ø¥è¾'^²Ø^rëyËkzË¥¶Æ®¶­sdgVæ2f&öæ66b33c¶â¢FÒb33c¶'&³5ÒÒ³ÃÃТbæ÷B4çBb33c¶âFVâ&WGW&âÓ¢bb33c¶âfÇC²FVâ&WGW&âÓ¢bb33c¶âfÇC²"FVâ&WGW&âb33c¶à¢f÷"b33c¶ÒFòb33c¶à b33c¶'&³ÒÒb33c¶'&³Ò²b33c¶'&³%Ð b33c¶'&³%ÒÒb33c¶'&³Ð b33c¶'&³ÒÒb33c¶'&³Ð¢æW@¢&WGW&âb33c¶'&³Ð¤VæDgVæ0 ¤gVæ2G&æwVÆ"b33c¶â¢FÒb33c·G&Ò¢bæ÷B4çBb33c¶âFVâ&WGW&âÓ¢bb33c¶âfÇC²FVâ&WGW&âÓ¢bb33c¶âÒFVâ&WGW&â¢f÷"b33c¶ÒFòb33c¶à b33c·G&³Òb33c¶¢æW@¢&WGW&âb33c·G&¤VæDgVæ0 ¤gVæ2f7F÷&Âb33c¶â¢´6V6²&ÖWFW'0¢bæ÷B4çBb33c¶âFVâ&WGW&âÓ¢bb33c¶âfÇC²FVâ&WGW&âÓ¢bb33c¶âfwC³sFVâ&WGW&âÓ¢´FòFRÖF¢bb33c¶âfÇC³Ó#FVà Æö6Âb33c¶Ó f÷"b33c¶ÓFòb33c¶à b33c¶£Òb33c¶ æW@¢VÇ6P Æö6Âb33c¶ÓãS f÷"b33c¶ÓãSFòb33c¶à b33c¶£Òb33c¶ æW@¢VæD`¢&WGW&âb33c¶¤VæDgVæ

I might have a go at the other stuff I've seen, I like doing stuff like this. :P

Share this post


Link to post
Share on other sites
Nahuel

$Timer=TimerInit()
Fibonacci(150)
$Diff=TimerDiff($Timer)
ConsoleWrite("Skinny's Fibonacci(): " & $Diff & @CR)

$Timer=TimerInit()
_Fibonacci(150)
$Diff=TimerDiff($Timer)
ConsoleWrite("Nahuel's Fibonacci(): " & $Diff & @CR)

$Timer=TimerInit()
Triangular(150)
$Diff=TimerDiff($Timer)
ConsoleWrite("Skinny's Triangular(): " & $Diff & @CR)

$Timer=TimerInit()
_Triangular(150)
$Diff=TimerDiff($Timer)
ConsoleWrite("Nahuel's Triangular(): " & $Diff & @CR)

Func Fibonacci($n)
   Dim $array[3] = [0,0,1]
   If Not IsInt($n) Then Return -1
   If $n < 0 Then Return -1
   If $n < 2 Then Return $n
   For $i = 1 To $n
      $array[0] = $array[1] + $array[2]
      $array[2] = $array[1]
      $array[1] = $array[0]
   Next
   Return $array[0]
EndFunc

Func _Fibonacci($n)
    If Not IsInt($n) Then Return -1
    If $n < 0 Then Return -1
    If $n < 2 Then
        Return $n
    Else
        Return (Fibonacci($n-1) + Fibonacci($n-2))
    EndIf
EndFunc

Func _Triangular($n)
    If Not IsInt($n) Then Return -1
    If $n < 0 Then Return -1
    If $n > 0 then
       $tri = Triangular( $n- 1) + $n
    else
       $tri=0
   EndIf
   Return $tri
EndFunc

Func Triangular($n)
   Dim $tri = 0
   If Not IsInt($n) Then Return -1
   If $n < 0 Then Return -1
   If $n = 0 Then Return 0
   For $i = 1 To $n
      $tri += $i
   Next
   Return $tri
EndFunc

Wow, there sure is a big difference! Specially with the Fibonacci one. I don't know if it's my slow computer or what, but the both triangular udf's seem to be pretty even...

Thanks for the corrections :P

Share this post


Link to post
Share on other sites
Uten

Looking for refactoring possibilities is a really good habit @SkinyWhiteGuy. You get cookie points for that...;)

Recursion can be cool, but should be avoided if possible. But as in @Nahuel's Fibonacci sample, recursive code makes readable and good looking code.

Now, about speed. AutoIt is not a good language for algorithms. It is, probably the best, Windows "glue" language. But it really sucks when it comes down to lengthy computations. I did a profiling test with AutoIt, thinbasic, freebasic, EBasic, hotBasic, Aurora, gcc and lcc. The math test was based on 500.000 iterations of a routine doing trigonometric calculations. In this test the AutoIt executable was so slow that I could not let it finish the task! :P

In my string comparing test (also 500.000 iterations) AutoIt came out 100 times slower than the fastest solution.

So lesson learned. Use Autoit as a front end to a dll created with something else. lcc came out fastest in my test. After I did the test I became aware of tcc (tiny c compiler) by Fabrice Bellard. Now there you have a perfect AutoIt C companion. The installation is only a few MB, and you get all the raw power of C. Only be aware that you have to specify the Include and lib path on the commandline when you use the compiler on Windows.

Thanks for the contributions so fare..:)

Happy Scripting

Uten

Share this post


Link to post
Share on other sites
pyv59

Uten

I would like to dive into your idea of tcc as AutoIt C companion but I don't succed in making a dll.

Could you, please, provide further explanations for this step an the following next : how to call the dll ?

Thanks

Patrick

Share this post


Link to post
Share on other sites
Nahuel

Hey Uten! I've been looking for a C compiler just like that! Thanks :P Now you gave me many ideas, hope I can come up with something ;)

Share this post


Link to post
Share on other sites
SkinnyWhiteGuy

Uten

I would like to dive into your idea of tcc as AutoIt C companion but I don't succed in making a dll.

Could you, please, provide further explanations for this step an the following next : how to call the dll ?

Thanks

Patrick

Well, I figured this out with Dev C++ awhile back, here is a link to that post:

Understanding dll files, and how to make them

I'm trying to see how tcc might be integrated into Dev-C++, but since gcc is provided with it, I'm not in that big a hurry.

@Uten

I tend to use AutoIt as a profiling language for different algorithms and testing to see how fast I can get things. I can comfortably code things in AutoIt and not worry about variable types or a lot of other things that tend to slow me down in terms of making a program.

Oh, and I'll take those cookie points, too. :P

Share this post


Link to post
Share on other sites
Uten

To compile the tcc samples I have made a cmd file in my path (this is the on called later when I call tcc).

tcc.cmd

c:\devtools\tcc-0.9.23\tcc\tcc.exe -Ic:\devtools\tcc-0.9.23\include -Ic:\devtools\tcc-0.9.23\include\winapi -Lc:\devtools\tcc-0.9.23\lib %*

Observe that the paths are absolute and without spaces in them.

To compile the dll sample in tcc's examples folder

cd c:\devtools\tcc-0.9.23\
tcc -luser32 -shared examples\dll.c

Create the def file

tcc\tiny_impdef.exe dll.dll

And the dll test application

tcc examples\hello_dll.c dll.def

And finally the a AutoIt test script.

DllCall("dll.dll","none", "HelloWorld")

the au3 file must be in the same folder as the dll.dll. In my case that is c:\devtools\tcc-0.9.23. Or dll.dll must be in a folder defined in the PATH environment variable.

Happy scripting

Uten

Share this post


Link to post
Share on other sites
Nahuel

Thanks a lot Uten! I'm gonna try that ;) Although I'm having some trouble with the cmd lines ¬¬

So, I'm using Dev-C++ at the moment. I wrote the Fibonacci function in a DLL, here's the code:

#define EXPORT extern "C" __declspec(dllexport) __stdcall

// DLL initialization
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
        return TRUE;
}

// Defined Functions to be available to other processes

EXPORT int Fibonacci(int n)
{
       if (n < 0) {
            return 0;
            }
       if (n < 2) {
            return n;
            }
       else {
            return (Fibonacci(n-1) + Fibonacci(n-2));
            }
}

I compiled it and it works pretty well

$answer = DllCall ( "math.dll", "int", "Fibonacci", "int", 10)
MsgBox(0, @error, $answer[0])oÝ÷ Ø­×hzÉ÷öÜ(®F޶׫¶§JH§!®Ël&è§)ÀºÚ´¢jezץʧÌ"¶î·«±¸ êí©÷Ð'£­ßÛyÆ®±âyÉZ­çbø±¸§·öÁºØ"ëජjbêìk+q©÷ö×(«y©ÈÜ"¶¥¢xØbem²Øb²X§z([vþ$¨"Ë©¦#e¯zÚ ¡©Ýæ«'Ð%²!ÉÚ²+kzÛ«©Ú®¶²jëh×6MsgBox(0, @error, $answer[0])

:P

Edited by Nahuel

Share this post


Link to post
Share on other sites
SkinnyWhiteGuy

DllCall() returns an array (see here).

As to the C problem, try declaring a temp1 variable as a long and set it equal to 2, and use that to compare (just to get you by that part).

Share this post


Link to post
Share on other sites
Valuater

JK... you guys are serious!

8)

Edited by Valuater

NEWHeader1.png

Share this post


Link to post
Share on other sites
Uten

Looking forward to see all the creative spinnoffs (hmm, don't you say that. At least not in ASpell?) this will trigger..;)

@Nahuel: Some of the stuff you have done, when your bored, are grate. So, yes you should definitely spend some time learning basic C. And make the commandline your friend. Take a look in my blog. And search for "cmd here".

NOTE: Do not think C++ supports C anymore (as of C99). Try to make a distinction between your C and your C++ code (A really good reason to use tcc..:P (or a LCC based setup))

Share this post


Link to post
Share on other sites
Nahuel

Thanks a lot Uten! I managed to use Notepadd ++ to edit and TCC to compile :P It works, but it's extremely slow. I guess I'll try to avoid using recursive calls... I've never programed in C before, so this is hard as hell ;)

@SkinnyGuy: I replaced int by long and it works. But it's like 10000 slower than the one you did!

Share this post


Link to post
Share on other sites
SkinnyWhiteGuy

Lol, well, the Fibonacci sequence is hard on a computer when done like that. Just to look up 1 number, it has to recall the same function 2 times, and if that number isn't one of our other default cases, it also has to run 2 more function calls. Kinda the you tell 2 friends who tell 2 friends each, who then tell 2 friends each, etc... thing. Add to that, that it ends up recalculating numbers it already knew from before (Fib(8) = Fib(7) + Fib(6), Fib(7) = Fib(6) + Fib(5), etc...) and it's not very efficient at all.

Share this post


Link to post
Share on other sites
Nahuel

Yes, so true ;) I don't think it's worth it trying to build a DLL for functions like this one, when the one you did in AutoIt works just great. It should make a difference with Uten's udf's though :)

Since you seem to know the Fibonacci serie pretty well, I can't figure out how to make a function recognize if a given number is in the Fibonacci serie.. there is an equation, but it's kinda hard to make it with AutoIt :P

Share this post


Link to post
Share on other sites
SkinnyWhiteGuy

You mean this equation:

Func _Fib($num)
    Return Int((((1+Sqrt(5))^$num) - ((1-Sqrt(5))^$num)) / ((2^$num)*Sqrt(5)))
EndFuncoÝ÷ ØdwZël¡÷çyªíç§uÛ¶^r)Ƨu©e¶­"¯z}ýµÚ'yéèºpØb¶Ú$!£hrëyË_¢»ajÖî¶'ò¢êÞÞ¶×ë¢h­jw¢jZ­è­Â+a¶¨¶«ëa¡Û-+¢¹®¬"WË¥j×­ábnÚqȧºfÞ®Þ¶ÜqË«j×¥Èj¶¬r)àj{¦mêí¢Çø­ßÛ"Ø^±êâzÂ7õ×hÜ"¶¥¢l¢g­)à)jëh×6While $number_to_test < Fibonacci($n)
    $n+=1
Wend
If $number_to_test <> Fibonacci($n) Then Return False
Return True

Of course, that's just off the top of my head.

Edit: Just checked, the _Fib function above starts getting off for values above 70, and I couldn't think of a way to make it stop doing whatever it's doing, so I'd suggest either not using it, or limiting the input to values below 70.

Edited by SkinnyWhiteGuy

Share this post


Link to post
Share on other sites
weaponx

Here is my spinoff of the GetFactors function.

This will return a 2 dimensional array with ALL factors in column 1, and true in column 2 if its prime.

No preset group of primes is required. I am comparing my results to this page: http://www.apples4theteacher.com/prime-factors.html

#include <array.au3>
_ArrayDisplay(GetFactorsX(12345))

Func GetFactorsX($num)
    Local $factorArray[1][2]
    $count = 1
    
    ;Loop through every number from 1 to requested number
    For $X = 1 to $num
        If Mod($num, $X) = 0 Then
            Redim $factorArray[$count][2]
            $factorArray[$count-1][0] = $X
            $factorArray[$count-1][1] = true
            
            ;Check if prime
            For $Y = 2 to $X - 1
                ;If the number can be divided by anything other than 1 or itself
                If Mod($X, $Y) = 0 AND $X > 1 Then
                    $factorArray[$count-1][1] = false
                    ExitLoop
                EndIf
            Next

            $count += 1
        EndIf
    Next
    
    Return $factorArray
EndFunc
Edited by weaponx

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×