Uten Posted November 19, 2007 Posted November 19, 2007 (edited) 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.. expandcollapse popupFunc 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.. Edited November 19, 2007 by Uten Please keep your sig. small! Use the help file. Search the forum. Then ask unresolved questions :) Script plugin demo, Simple Trace udf, TrayMenuEx udf, IOChatter demo, freebasic multithreaded dll sample, PostMessage, Aspell, Code profiling
Nahuel Posted November 19, 2007 Posted November 19, 2007 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. expandcollapse popup;============ ;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
Uten Posted November 19, 2007 Author Posted November 19, 2007 @Nahuel. Thanks for the compliment and pointing out the funny stuff in the post. Wonder where that came from? Please keep your sig. small! Use the help file. Search the forum. Then ask unresolved questions :) Script plugin demo, Simple Trace udf, TrayMenuEx udf, IOChatter demo, freebasic multithreaded dll sample, PostMessage, Aspell, Code profiling
Nahuel Posted November 19, 2007 Posted November 19, 2007 It's a forum bug with the auoit tags. You probably edited your post? It has happened to me lots of times.
SkinnyWhiteGuy Posted November 20, 2007 Posted November 20, 2007 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.
Nahuel Posted November 20, 2007 Posted November 20, 2007 expandcollapse popup$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
Uten Posted November 20, 2007 Author Posted November 20, 2007 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! 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 ScriptingUten Please keep your sig. small! Use the help file. Search the forum. Then ask unresolved questions :) Script plugin demo, Simple Trace udf, TrayMenuEx udf, IOChatter demo, freebasic multithreaded dll sample, PostMessage, Aspell, Code profiling
pyv59 Posted November 20, 2007 Posted November 20, 2007 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
Nahuel Posted November 20, 2007 Posted November 20, 2007 Hey Uten! I've been looking for a C compiler just like that! Thanks Now you gave me many ideas, hope I can come up with something
SkinnyWhiteGuy Posted November 20, 2007 Posted November 20, 2007 UtenI 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 ?ThanksPatrickWell, I figured this out with Dev C++ awhile back, here is a link to that post:Understanding dll files, and how to make themI'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.@UtenI 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.
Uten Posted November 20, 2007 Author Posted November 20, 2007 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.cmdc:\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 foldercd c:\devtools\tcc-0.9.23\ tcc -luser32 -shared examples\dll.cCreate the def filetcc\tiny_impdef.exe dll.dllAnd the dll test applicationtcc examples\hello_dll.c dll.defAnd 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 scriptingUten Please keep your sig. small! Use the help file. Search the forum. Then ask unresolved questions :) Script plugin demo, Simple Trace udf, TrayMenuEx udf, IOChatter demo, freebasic multithreaded dll sample, PostMessage, Aspell, Code profiling
Nahuel Posted November 21, 2007 Posted November 21, 2007 (edited) 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]) Edited November 21, 2007 by Nahuel
SkinnyWhiteGuy Posted November 21, 2007 Posted November 21, 2007 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).
Valuater Posted November 21, 2007 Posted November 21, 2007 (edited) JK... you guys are serious! 8) Edited December 29, 2007 by Valuater
Uten Posted November 21, 2007 Author Posted November 21, 2007 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.. (or a LCC based setup)) Please keep your sig. small! Use the help file. Search the forum. Then ask unresolved questions :) Script plugin demo, Simple Trace udf, TrayMenuEx udf, IOChatter demo, freebasic multithreaded dll sample, PostMessage, Aspell, Code profiling
Nahuel Posted November 21, 2007 Posted November 21, 2007 Thanks a lot Uten! I managed to use Notepadd ++ to edit and TCC to compile 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!
SkinnyWhiteGuy Posted November 21, 2007 Posted November 21, 2007 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.
Nahuel Posted November 21, 2007 Posted November 21, 2007 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
SkinnyWhiteGuy Posted November 21, 2007 Posted November 21, 2007 (edited) 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Öî¶'ò¢êÞÞ¶×ë¢hjw¢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 November 21, 2007 by SkinnyWhiteGuy
weaponx Posted November 21, 2007 Posted November 21, 2007 (edited) 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 November 21, 2007 by weaponx
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now