jennico Posted December 10, 2009 Posted December 10, 2009 two further BigNum functions:_BigNum_Pow()_BigNum_n_root()expandcollapse popup#Include <BigNum.au3> ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Pow ; Description ...: Exponentiation $n^$e ; Syntax.........: _BigNum_Pow($n [, $e = 2]) ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $e [optional] - Exponent (must be a positive 64-bit signed integer) ; Default: $e = 2 means result = $n² ; Return values .: Success - Result $n^$e ; Failure - -1, sets @error to 1 if $n not valid StringNumber ; -1, sets @error to 2 if $e is not a positive Integer ; Author ........: jennicoattminusonlinedotde ; Date ..........: 9.12.09 ; Remarks .......: Fractional exponents not allowed - use BigNum_n_root instead. ; _BigNum_Pow() offers a drastically better efficiency than looping _BigNum_Mul() ; Reference .....: http://en.wikipedia.org/wiki/Exponentiation_by_squaring ; ;=============================================================================================== Func _BigNum_Pow($n, $e = 2) $e = Number($e) If IsInt($e) = 0 Or $e < 0 Then Return SetError(2, 0, -1) ;If $e < -2147483648 Or $e > 2147483647 Then Return SetError(-2, 0, -1) If _BigNum_IsValid ($n, $n) Then Return SetError(1, 0, -1) Local $res = 1 While $e ;If BitAND($e, 1) Then ; bitoperation is not faster ! If Mod($e, 2) Then $res = _BigNum_Mul ($res, $n) $e -= 1 EndIf $n = _BigNum_Mul ($n, $n) ;$e = BitShift($e, 1) ; bitoperation is not faster ! $e /= 2 WEnd Return $res EndFunc ;==>_BigNum_Pow ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_n_Root ; Description ...: $e-th Root of $n ; Syntax.........: _n_Root($n [, $e=2]) ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $e - [optional] Multiplicity of root (power, exponent) (must be a positive 64-bit signed integer > 0) ; Default: $e = 2 (=SQRT) ; $p - [optional] Precision (Number of desired Decimalplaces) (must be positive Integer) ; Default: $p = -1 means automatic precision (stringlen of integer part of $n) ; Return values .: Success - Result $e-root($n) ; @extended = Number of Iterations ; Failure - -1 and sets @error to 1 if $n not valid StringNumber ; -1 and sets @error to 2 if $e out of valid range ; -1 and sets @error to 3 if $p out of valid range ; Author ........: jennicoattminusonlinedotde ; Date ..........: 9.12.09 ; References ....: derived from "Newton's Method" ; ;=============================================================================================== Func _BigNum_n_Root($n, $e = 2, $p = -1) If _BigNum_IsValid ($n, $n) Then Return SetError(1, 0, -1) $e = Number($e) If IsInt($e) = 0 Or $e < 1 Then Return SetError(2, 0, -1) $p = Number($p) If IsInt($p) = 0 Or $p < -1 Then Return SetError(3, 0, -1) Local $l = StringInStr($n, ".") - 1 If $l = -1 Then $l = StringLen($n) If $p < 0 Then $p = $l Local $g = 1, $last, $i = 0 For $i = 3 To $l Step 2 $g = _BigNum_Mul ($g, 10) Next While 1 $i += 1 $last = $g $g = _BigNum_Div (_BigNum_Add (_BigNum_Div ($n, _BigNum_Pow($g, $e - 1), $p), _BigNum_Mul ($g, $e - 1)), $e, $p) If $last = $g Then Return SetExtended($i, $g) WEnd EndFunc ;==>_BigNum_n_Root _Example_1() ; calculates 2^5000 within half a second _Example_2() Func _Example_1() Local $timer = TimerInit() MsgBox(0, "BigNum_Pow Example 1: 2 ^5000 =", _BigNum_Pow(2, 5000) & @CRLF & @CRLF & TimerDiff($timer) / 1000) EndFunc ;==>_Example_1 Func _Example_2() While 1 Local $n = InputBox("BigNum nth-root Example 2", "Enter any Number to calculate the nth Root") If @error Then Return Local $e = InputBox("BigNum nth-root Example 2", "Enter 'n' (the multiplicity of the nth Root)") If @error Then Return Local $timer = TimerInit() Local $g = _BigNum_n_Root($n, $e) Local $i = @extended MsgBox(0, "Raw nth-root Example 2 Result:", $e & "th root of " & $n & " = " & $g & @CRLF & @CRLF & "Time: " & Round(TimerDiff($timer) / 1000, 10) & " sec" & @CRLF & "Error: " & _BigNum_Sub (_BigNum_Pow($g, $e), $n) & @CRLF & @TAB & "(" & Round(_BigNum_Div (_BigNum_Mul (_BigNum_Sub (_BigNum_Pow($g, $e), $n), 100), $n, 5), 6) & " %)" & @CRLF & "Iterations: " & $i) WEnd EndFunc ;==>_Example_2i updated the UDF and put it in my first post here.j. Spoiler I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.Don't forget this IP: 213.251.145.96
Mat Posted December 10, 2009 Posted December 10, 2009 Hopefully Eukalyptus will come back so he can update the first post. Does it need to be named _n_Root? Why not take out the "_n"? Mat AutoIt Project Listing
jennico Posted December 10, 2009 Posted December 10, 2009 i'm sure he could optimize my ideas. j. Spoiler I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.Don't forget this IP: 213.251.145.96
Mat Posted December 13, 2009 Posted December 13, 2009 New function: _BigNum_Sum. The name might be a bit misleading, but ah well It seperates a sum into each individual operation, and then uses the BigNum functions to solve it. This is going to very useful to anyone writing a calculator, as it allows BigNums to do the sums. It is also very short for what it does, which usually means I missed something... expandcollapse popup; #FUNCTION# ;==================================================================================== ; Name...........: _BigNum_Sum ; Description ...: Parses a sum using bigNums ; Syntax.........: _BigNum_Sum($sSum) ; Parameters ....: $sSum - A String showing the sum e.g. "2342314-9073458320-4953425342535+432532453245324534*34524532452345" ; Return values .: Success - Result ; Failure - 0, and sets @Error. If @Error = 0xDEAD then there is a function missing. ; Remarks .......: Becouse this uses call, Internal functions are not supported. ; Author ........: Mat ; ;=============================================================================================== Func _BigNum_Sum($sIn) $sIn = StringStripWS($sIn, 8) Local $aReg = StringRegExp($sIn, "(?i)([0x;&H][0-9]*)", 3) If Not @error Then For $i = 0 To UBound($aReg) - 1 $sIn = StringReplace($sIn, $aReg[$i], Dec(StringTrimLeft($aReg[$i], 2))) Next EndIf Local $aMatches = StringRegExp ($sIn, "(\w*\(.*?\))", 3), $aParts, $sRet If Not @Error Then For $i = 0 to UBound ($aMatches) - 1 $aParts = StringSplit (StringRegExpReplace ($aMatches[$i], ".*?\((.*?)\)", "\1"), ",") $aParts[0] = "CallArgArray" $sRet = Call (StringRegExpReplace ($aMatches[$i], "\(.*", ""), $aParts) If @Error Then $sRet = Call ("_BigNum_" & StringRegExpReplace ($aMatches[$i], "\(.*", ""), $aParts) If @Error Then Return SetError (@Error, @extended, $sRet) EndIf $sIn = StringReplace ($sIn, $aMatches[$i], $sRet) Next EndIf ; Brackets Local $sNest, $res While StringInStr($sIn, "(") $sNest = StringRegExpReplace($sIn, ".*?\(([^\(]+?)\).*", "\1") $res = _BigNum_Sum($sNest) If @error Then Return SetError (@Error, @Extended, 0) $sIn = StringReplace($sIn, "(" & $sNest & ")", $res) WEnd Local $aOps[6][2] = [["\^", "_BigNum_Pow"], ["%", "_BigNum_Mod"],["/", "_BigNum_Div"],["\*", "_BigNum_Mul"],["\+", "_BigNum_Add"],["-", "_BigNum_Sub"]] For $i = 0 To 5 $aMatches = StringRegExp($sIn, "(-?\d*" & $aOps[$i][0] & "\d*)", 3) If Not @error Then For $x = 0 To UBound($aMatches) - 1 $aParts = StringSplit($aMatches[$x], StringRight($aOps[$i][0], 1)) $aParts[0] = "CallArgArray" $sRet = Call($aOps[$i][1], $aParts) If @Error Then Return SetError (@Error, @Extended, 0) $sIn = StringReplace($sIn, $aMatches[$x], $sRet) Next EndIf Next Return $sIn EndFunc ;==>_BigNum_Sum and the edited UDF: expandcollapse popup#include-once Global Const $BigNum_Debug = False ; #INDEX# ======================================================================================================================= ; Title .........: BigNum ; AutoIt Version : 3.2.12.1 ; Language ......: English ; Description ...: Perform calculations with big numbers ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ;_BigNum_Sum ;_BigNum_Add ;_BigNum_Sub ;_BigNum_Mul ;_BigNum_Div ;_BigNum_Pow ;_BigNum_SQRT ;_BigNum_n_Root ;_BigNum_Mod ;_BigNum_Round ;_BigNum_Compare ;_BigNum_Swap ; =============================================================================================================================== ; #INTERNAL_USE_ONLY#============================================================================================================ ;_BigNum_CheckNegative ;_BigNum_DivAdd ;_BigNum_DivComp ;_BigNum_DivSub ;_BigNum_Div_DivisorGreater14 ;_BigNum_Div_DivisorMaxLen14 ;_BigNum_InsertDecimalSeparator ;_BigNum_StringIsDecimal ;_BigNum_IsValid ; =============================================================================================================================== ; #FUNCTION# ;==================================================================================== ; Name...........: _BigNum_Sum ; Description ...: Parses a sum using bigNums ; Syntax.........: _BigNum_Sum($sSum) ; Parameters ....: $sSum - A String showing the sum e.g. "2342314-9073458320-4953425342535+432532453245324534*34524532452345" ; Return values .: Success - Result ; Failure - 0, and sets @Error. If @Error = 0xDEAD then there is a function missing. ; Remarks .......: Becouse this uses call, Internal functions are not supported. ; Author ........: Mat ; ;=============================================================================================== Func _BigNum_Sum($sIn) $sIn = StringStripWS($sIn, 8) Local $aReg = StringRegExp($sIn, "(?i)([0x;&H][0-9]*)", 3) If Not @error Then For $i = 0 To UBound($aReg) - 1 $sIn = StringReplace($sIn, $aReg[$i], Dec(StringTrimLeft($aReg[$i], 2))) Next EndIf Local $aMatches = StringRegExp ($sIn, "(\w*\(.*?\))", 3), $aParts, $sRet If Not @Error Then For $i = 0 to UBound ($aMatches) - 1 $aParts = StringSplit (StringRegExpReplace ($aMatches[$i], ".*?\((.*?)\)", "\1"), ",") $aParts[0] = "CallArgArray" $sRet = Call (StringRegExpReplace ($aMatches[$i], "\(.*", ""), $aParts) If @Error Then $sRet = Call ("_BigNum_" & StringRegExpReplace ($aMatches[$i], "\(.*", ""), $aParts) If @Error Then Return SetError (@Error, @extended, $sRet) EndIf $sIn = StringReplace ($sIn, $aMatches[$i], $sRet) Next EndIf ; Brackets Local $sNest, $res While StringInStr($sIn, "(") $sNest = StringRegExpReplace($sIn, ".*?\(([^\(]+?)\).*", "\1") $res = _BigNum_Sum($sNest) If @error Then Return SetError (@Error, @Extended, 0) $sIn = StringReplace($sIn, "(" & $sNest & ")", $res) WEnd Local $aOps[6][2] = [["\^", "_BigNum_Pow"], ["%", "_BigNum_Mod"],["/", "_BigNum_Div"],["\*", "_BigNum_Mul"],["\+", "_BigNum_Add"],["-", "_BigNum_Sub"]] For $i = 0 To 5 $aMatches = StringRegExp($sIn, "(-?\d*" & $aOps[$i][0] & "\d*)", 3) If Not @error Then For $x = 0 To UBound($aMatches) - 1 $aParts = StringSplit($aMatches[$x], StringRight($aOps[$i][0], 1)) $aParts[0] = "CallArgArray" $sRet = Call($aOps[$i][1], $aParts) If @Error Then Return SetError (@Error, @Extended, 0) $sIn = StringReplace($sIn, $aMatches[$x], $sRet) Next EndIf Next Return $sIn EndFunc ;==>_BigNum_Sum ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Add ; Description ...: Addition $sX + $sY ; Syntax.........: _BigNum_Add($sX, $sY) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; Return values .: Success - Result $sX + $sY ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Add($sX, $sY) If _BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0) Local $iNeg = _BigNum_CheckNegative($sX, $sY), $sNeg = "" If $iNeg = 3 Then $sNeg = "-" If $iNeg = 1 Then Return _BigNum_Sub($sY, $sX) If $iNeg = 2 Then Return _BigNum_Sub($sX, $sY) If $BigNum_Debug Then Local $BN_File = FileOpen(@ScriptDir & "\BigNum_Debug.txt", 2) Local $iDec = _BigNum_StringIsDecimal($sX, $sY) Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = "" If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen - $iTmp, "0") & $sX & " + " & @CRLF & " " & _BigNum_DS($iTmp - $iLen, "0") & $sY & @CRLF) If $iLen < $iTmp Then $iLen = $iTmp If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen, "-") & @CRLF) For $i = 1 To $iLen Step 18 $iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar $sX = StringTrimRight($sX, 18) $sY = StringTrimRight($sY, 18) If ($iTmp > 999999999999999999) Then $iTmp = StringRight($iTmp, 18) $sRet = $iTmp & $sRet If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($iLen - $i - StringLen($iTmp) + 2) & $iTmp & _BigNum_DS($i) & "+" & $iCar & @CRLF) $iCar = 1 Else If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($iLen - $i - StringLen($iTmp) + 2) & $iTmp & _BigNum_DS($i) & "+" & $iCar & @CRLF) $iTmp = StringRight("000000000000000000" & $iTmp, 18) $sRet = $iTmp & $sRet $iCar = 0 EndIf Next $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1) If $iDec > 0 Then $sRet = _BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec) If $sRet = "0" Then $sNeg = "" If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen, "-") & @CRLF) FileWrite($BN_File, _BigNum_DS($iLen - StringLen($sRet) + 1) & $sRet) FileClose($BN_File) EndIf Return $sNeg & $sRet EndFunc ;==>_BigNum_Add ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Sub ; Description ...: Subtraction $sX - $sY ; Syntax.........: _BigNum_Sub($sX, $sY) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; Return values .: Success - Result $sX - $sY ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Sub($sX, $sY) If _BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0) Local $iNeg = _BigNum_CheckNegative($sX, $sY), $bNeg = False If $iNeg = 3 Then Return _BigNum_Add("-" & $sX, $sY) If $iNeg = 1 Then Return "-" & _BigNum_Add($sX, $sY) If $iNeg = 2 Then Return _BigNum_Add($sX, $sY) If $BigNum_Debug Then Local $BN_File = FileOpen(@ScriptDir & "\BigNum_Debug.txt", 2) Local $iDec = _BigNum_StringIsDecimal($sX, $sY) If _BigNum_Compare($sX, $sY) = -1 Then $bNeg = _BigNum_Swap($sX, $sY) Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = "" If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen - $iTmp, "0") & $sX & " - " & @CRLF & " " & _BigNum_DS($iTmp - $iLen, "0") & $sY & @CRLF) If $iLen < $iTmp Then $iLen = $iTmp If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen, "-") & @CRLF) For $i = 1 To $iLen Step 18 $iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar $sX = StringTrimRight($sX, 18) $sY = StringTrimRight($sY, 18) If $iTmp < 0 Then $iTmp = 1000000000000000000 + $iTmp If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($iLen - $i - StringLen($iTmp) + 2) & $iTmp & _BigNum_DS($i) & "-" & $iCar & @CRLF) $iCar = 1 Else If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($iLen - $i - StringLen($iTmp) + 2) & $iTmp & _BigNum_DS($i) & "-" & $iCar & @CRLF) $iCar = 0 EndIf $sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet Next $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1) If $iDec > 0 Then $sRet = _BigNum_InsertDecimalSeparator($sRet, $iDec, $iDec) If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($iLen, "-") & @CRLF) FileWrite($BN_File, _BigNum_DS($iLen - StringLen($sRet) + 1) & $sRet) FileClose($BN_File) EndIf If $bNeg = True And $sRet <> "0" Then Return "-" & $sRet Else Return $sRet EndIf EndFunc ;==>_BigNum_Sub ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Mul ; Description ...: Multiplication $sX * $sY ; Syntax.........: _BigNum_Mul($sX, $sY) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; Return values .: Success - Result $sX * $sY ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Mul($sX, $sY) If _BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0) Local $iNeg = _BigNum_CheckNegative($sX, $sY), $sNeg = "" Local $iDec = _BigNum_StringIsDecimal($sX, $sY) If $BigNum_Debug Then Local $BN_File = FileOpen(@ScriptDir & "\BigNum_Debug.txt", 2), $BN_X = StringLen($sX) FileWrite($BN_File, " " & $sX & " * " & $sY & " = " & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + StringLen($sY) + 3, "-") & @CRLF) EndIf Local $aX = StringRegExp($sX, '\A.{' & 6 - (Ceiling(StringLen($sX) / 6) * 6 - StringLen($sX)) & '}|.{6}+', 3) Local $aY = StringRegExp($sY, '\A.{' & 6 - (Ceiling(StringLen($sY) / 6) * 6 - StringLen($sY)) & '}|.{6}+', 3) Local $aRet[UBound($aX) + UBound($aY) - 1] For $j = 0 To UBound($aX) - 1 For $i = 0 To UBound($aY) - 1 If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS(StringLen($aX[0]) + $j * 6 - StringLen($aX[$j])) & $aX[$j] & _BigNum_DS($BN_X - (StringLen($aX[0]) + $j * 6)) & " * " & _BigNum_DS(StringLen($aY[0]) + $i * 6 - StringLen($aY[$i])) & $aY[$i]) FileWrite($BN_File, " " & _BigNum_DS(((UBound($aY) - 1 - $i) * 6) + ($i * 15 + $j * 15)) & $aX[$j] * $aY[$i] & @CRLF) EndIf $aRet[$j + $i] += $aX[$j] * $aY[$i] Next Next If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($BN_X + StringLen($sY) + 3) & _BigNum_DS($i * 15 + $j * 15, "-") & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + StringLen($sY) + 6)) For $i = 0 To UBound($aRet) - 1 FileWrite($BN_File, $aRet[$i] & _BigNum_DS(15 - StringLen($aRet[$i]))) Next FileWrite($BN_File, @CRLF & @CRLF) For $i = 0 To UBound($aRet) - 1 FileWrite($BN_File, _BigNum_DS($BN_X + StringLen($sY)) & _BigNum_DS($i * 6 + 15 - StringLen($aRet[$i])) & $aRet[$i] & @CRLF) Next FileWrite($BN_File, _BigNum_DS($BN_X + StringLen($sY)) & _BigNum_DS(15 - StringLen($aRet[0])) & _BigNum_DS($i * 6, "-") & @CRLF) EndIf Local $sRet = "", $iCar = 0, $iTmp For $i = UBound($aRet) - 1 To 0 Step - 1 $aRet[$i] += $iCar $iCar = Floor($aRet[$i] / 1000000) $iTmp = Mod($aRet[$i], 1000000) If $iTmp <= 1000000 Then $iTmp = StringRight("000000" & $iTmp, 6) $sRet = $iTmp & $sRet Next If $iCar > 0 Then $sRet = $iCar & $sRet $sRet = StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1) If ($iNeg = 1 Or $iNeg = 2) And $sRet <> "0" Then $sNeg = "-" If $iDec > 0 Then $sRet = _BigNum_InsertDecimalSeparator($sRet, $iDec * 2, $iDec * 2) If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($BN_X + StringLen($sY)) & _BigNum_DS(15 - StringLen($aRet[0])) & $sRet) FileClose($BN_File) EndIf Return $sNeg & $sRet EndFunc ;==>_BigNum_Mul ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Div ; Description ...: Division $sX / $sY ; Syntax.........: _BigNum_Div($sX, $sY, [$iD = 0]) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $iD [optional] - Number of Decimalplaces ; Return values .: Success - Result $sX / $sY ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Div($sX, $sY, $iD = 0) If _BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0) Local $iNeg = _BigNum_CheckNegative($sX, $sY), $sNeg = "" Local $iDec = _BigNum_StringIsDecimal($sX, $sY), $sMod If $sX = 0 Or $sY = 0 Then Return "0" If $sY = "1" Then Return $sNeg & $sX While StringLeft($sX, 1) = "0" $sX = StringTrimLeft($sX, 1) $iDec += 1 WEnd While StringLeft($sY, 1) = "0" $sY = StringTrimLeft($sY, 1) $iDec += 1 WEnd Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY), $iTmp, $iCnt, $sTmp, $iDe1 = 0 If $iD > 0 Then $iDe1 += $iD If $iNeg = 1 Or $iNeg = 2 Then $sNeg = "-" $iTmp = _BigNum_Compare($sX, $sY) If $iTmp = -1 Then For $iCnt = $iLnX To $iLnY $sX &= 0 $iDe1 += 1 Next EndIf If $iTmp = 0 Then Return $sNeg & "1" If $iD = -1 Then $iD = $iDec * 2 For $iCnt = 1 To $iD $sX &= "0" Next If $iLnY > 14 Then $sRet = _BigNum_Div_DivisorGreater14($sX, $sY, $sMod) Else $sRet = _BigNum_Div_DivisorMaxLen14($sX, $sY, $sMod) EndIf If $iDe1 > 0 Then $sRet = _BigNum_InsertDecimalSeparator($sRet, $iDe1, $iD) If $sRet = "0" Then Return "0" Else Return $sNeg & $sRet EndIf EndFunc ;==>_BigNum_Div ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Pow ; Description ...: Exponentiation $n^$e ; Syntax.........: _BigNum_Pow($n [, $e = 2]) ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $e [optional] - Exponent (must be a positive 64-bit signed integer) ; Default: $e = 2 means result = $n² ; Return values .: Success - Result $n^$e ; Failure - -1, sets @error to 1 if $n not valid StringNumber ; -1, sets @error to 2 if $e is not a positive Integer ; Author ........: jennicoattminusonlinedotde ; Date ..........: 9.12.09 ; Remarks .......: Fractional exponents not allowed - use BigNum_n_root instead. ; _BigNum_Pow() offers a drastically better efficiency than looping _BigNum_Mul() ; Reference .....: http://en.wikipedia.org/wiki/Exponentiation_by_squaring ; ;=============================================================================================== Func _BigNum_Pow($n, $e = 2) $e = Number($e) If IsInt($e) = 0 Or $e < 0 Then Return SetError(2, 0, -1) ;If $e < -2147483648 Or $e > 2147483647 Then Return SetError(-2, 0, -1) If _BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1) Local $res = 1 While $e ;If BitAND($e, 1) Then ; bitoperation is not faster ! If Mod($e, 2) Then $res = _BigNum_Mul($res, $n) $e -= 1 EndIf $n = _BigNum_Mul($n, $n) ;$e = BitShift($e, 1) ; bitoperation is not faster ! $e /= 2 WEnd Return $res EndFunc ;==>_BigNum_Pow ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_SQRT ; Description ...: Square Root (BigNum) ; Syntax.........: _BigNum_SQRT($n [, $p = -1]) ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $p [optional] - Precision (Number of Decimalplaces) (must be positive Integer) ; Default: $p = -1 means automatic precision (stringlen of integer part of $n) ; Return values .: Success - Result SQRT($n) ; @extended = Precicion of result (if $p set to automatic precision) ; @error = Number of Iterations ; Failure - -1, sets @error to -1 if $n not valid StringNumber ; -1, sets @error to -2 if $p is out of valid range ; -1, sets @error to -3 if time-out (>100 iterations) ; Author ........: jennicoattminusonlinedotde ; Date ..........: 8.12.09 ; Remarks .......: use Precision param when u want to obtain the square root of a small number with the desired decimal places. ; References ....: http://www.merriampark.com/bigsqrt.htm ; "Newton's Method" - before: Heron of Alexandria ; ;=============================================================================================== Func _BigNum_SQRT($n, $p = -1) If _BigNum_IsValid($n, $n) Then Return SetError(-1, 0, -1) $p = Number($p) If IsInt($p) = 0 Or $p < -1 Then Return SetError(-2, 0, -1) Local $l = StringInStr($n, ".") - 1 If $l = -1 Then $l = StringLen($n) If $p < 0 Then $p = $l Local $g = 1, $last For $i = 3 To $l Step 2 $g = _BigNum_Mul($g, 10) Next For $i = 1 To 100 $last = $g $g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, $g, $p), $g), 2, $p) If $last = $g Then Return SetError($i, $p, $g) Next Return SetError(-3, 0, -1) EndFunc ;==>_BigNum_SQRT ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_n_Root ; Description ...: $e-th Root of $n ; Syntax.........: _n_Root($n [, $e=2]) ; Parameters ....: $n - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $e - [optional] Multiplicity of root (power, exponent) (must be a positive 64-bit signed integer > 0) ; Default: $e = 2 (=SQRT) ; $p - [optional] Precision (Number of desired Decimalplaces) (must be positive Integer) ; Default: $p = -1 means automatic precision (stringlen of integer part of $n) ; Return values .: Success - Result $e-root($n) ; @extended = Number of Iterations ; Failure - -1 and sets @error to 1 if $n not valid StringNumber ; -1 and sets @error to 2 if $e out of valid range ; -1 and sets @error to 3 if $p out of valid range ; Author ........: jennicoattminusonlinedotde ; Date ..........: 9.12.09 ; References ....: derived from "Newton's Method" ; ;=============================================================================================== Func _BigNum_n_Root($n, $e = 2, $p = -1) If _BigNum_IsValid($n, $n) Then Return SetError(1, 0, -1) $e = Number($e) If IsInt($e) = 0 Or $e < 1 Then Return SetError(2, 0, -1) $p = Number($p) If IsInt($p) = 0 Or $p < -1 Then Return SetError(3, 0, -1) Local $l = StringInStr($n, ".") - 1 If $l = -1 Then $l = StringLen($n) If $p < 0 Then $p = $l Local $g = 1, $last, $i = 0 For $i = 3 To $l Step 2 $g = _BigNum_Mul($g, 10) Next While 1 $i += 1 $last = $g $g = _BigNum_Div(_BigNum_Add(_BigNum_Div($n, _BigNum_Pow($g, $e - 1), $p), _BigNum_Mul($g, $e - 1)), $e, $p) If $last = $g Then Return SetExtended($i, $g) WEnd EndFunc ;==>_BigNum_n_Root ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Mod ; Description ...: Modulo Mod($sX, $sY) ; Syntax.........: _BigNum_Mod($sX, $sY) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; Return values .: Success - Result Mod($sX, $sY) ; Failure - 0, sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Mod($sX, $sY) If _BigNum_IsValid($sX, $sY) Then Return SetError(1, 0, 0) If $sY = 0 Or $sY = 1 Then Return "0" Local $sRes = $sX Local $iNeg = _BigNum_CheckNegative($sX, $sY) Local $iDec = _BigNum_StringIsDecimal($sX, $sY) If _BigNum_Compare($sX, $sY) < 0 Then Return $sRes Local $sRet = "", $iLnX = StringLen($sX), $iLnY = StringLen($sY) If $iLnY > 14 Then _BigNum_Div_DivisorGreater14($sX, $sY, $sRet) Else _BigNum_Div_DivisorMaxLen14($sX, $sY, $sRet) EndIf $sRet = _BigNum_InsertDecimalSeparator($sRet, $iDec, StringLen($sRet)) If ($iNeg = 3 Or $iNeg = 1) And $sRet <> "0" Then $sRet = "-" & $sRet Return $sRet EndFunc ;==>_BigNum_Mod ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Round ; Description ...: Round $sX to $iD Decimalplaces ; Syntax.........: _BigNum_Round($sX, $iD) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $iD - Number of Decimalplaces ; Return values .: Success - Result Round($sX, $iD) ; Failure - 0, sets @error to 1 if $sX not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Round($sX, $iD) If _BigNum_IsValid($sX, $sX) Then Return SetError(1, 0, 0) Local $sTmp = 0, $sRet, $sRes = $sX Local $iNeg = _BigNum_CheckNegative($sX, $sTmp) Local $iDec = _BigNum_StringIsDecimal($sX, $sTmp) If $iD > $iDec Or $iDec = 0 Then Return $sRes $sTmp = StringLeft(StringRight($sX, $iDec - $iD), 1) $sRet = StringTrimRight($sRes, $iDec - $iD) If $sTmp >= 5 And $iD > 0 Then If $iNeg = 1 Then $sRet = _BigNum_Add($sRet, "-0." & StringFormat("%0" & String($iD) & "u", "1")) Else $sRet = _BigNum_Add($sRet, "0." & StringFormat("%0" & String($iD) & "u", "1")) EndIf ElseIf $sTmp >= 5 And $iD = 0 Then If $iNeg = 1 Then $sRet = _BigNum_Add($sRet, "-1") Else $sRet = _BigNum_Add($sRet, "1") EndIf Else If StringRight($sRet, 1) = "." Then $sRet = StringTrimRight($sRet, 1) EndIf Return $sRet EndFunc ;==>_BigNum_Round ; #FUNCTION# ;==================================================================================== ; ; Name...........: _BigNum_Compare ; Description ...: Compares $sX $sY ; Syntax.........: _BigNum_Compare($sX, $sY) ; Parameters ....: $sX - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; $sY - StringNumber: Minus"-" Digits"0"..."9" Separator"." ("-1234567890.12345") ; Return values .: Success - Return: ; |0 - $sX and $sY are equal ; |1 - $sX is greater than $sY ; |-1 - $sX is less than $sY ; Failure - sets @error to 1 if $sX/$sY not valid StringNumber ; Author ........: Eukalyptus www.autoit.de ; ; ;=============================================================================================== Func _BigNum_Compare($sX, $sY) Local $iNeg = _BigNum_CheckNegative($sX, $sY) If $iNeg = 1 Then Return -1 If $iNeg = 2 Then Return 1 Local $iLnX = StringLen($sX), $iLnY = StringLen($sY) If $iNeg = 3 Then If $iLnX > $iLnY Then Return -1 ElseIf $iLnX < $iLnY Then Return 1 Else If $sX > $sY Then Return -1 ElseIf $sX < $sY Then Return 1 Else Return 0 EndIf EndIf Else If $iLnX > $iLnY Then Return 1 ElseIf $iLnX < $iLnY Then Return -1 Else If $sX > $sY Then Return 1 ElseIf $sX < $sY Then Return -1 Else Return 0 EndIf EndIf EndIf EndFunc ;==>_BigNum_Compare Func _BigNum_Swap(ByRef $sX, ByRef $sY) Local $sSwap = $sX $sX = $sY $sY = $sSwap Return True EndFunc ;==>_BigNum_Swap ; #INTERNAL_USE_ONLY#============================================================================================================ #region Internal Functions Func _BigNum_Div_DivisorGreater14($sX, $sY, ByRef $sM) $sM = "0" If $sY = "1" Then Return $sX If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0" If $BigNum_Debug Then Local $BN_File = FileOpen(@ScriptDir & "\BigNum_Debug.txt", 2), $BN_X = StringLen($sX) FileWrite($BN_File, " " & $sX & " / " & $sY & " = " & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + StringLen($sY) + 3, "-") & @CRLF) EndIf Local $iLnY = StringLen($sY), $bRed = False Local $sRet = "", $sRem = StringLeft($sX, $iLnY), $sTmp = "", $sTm2 = "", $iCnt, $iLen = 1 $sX = StringTrimLeft($sX, $iLnY) Do If _BigNum_DivComp($sRem, $sY) = -1 Then $sTmp = StringLeft($sX, 1) $sRem &= $sTmp $sX = StringTrimLeft($sX, 1) If StringLen($sTmp) > 0 Then $iLen += 1 EndIf $sTmp = $sY $sTm2 = "0" If _BigNum_DivComp($sRem, $sY) >= 0 Then For $iCnt = 1 To 9 $sTm2 = $sTmp $sTmp = _BigNum_DivAdd($sTmp, $sY) If _BigNum_DivComp($sRem, $sTmp) < 0 Then ExitLoop Next Else $iCnt = 0 EndIf If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($BN_X - StringLen($sX) - StringLen($sRem) + 1) & $sRem & _BigNum_DS($BN_X + 10 - $iLen - $iLnY) & StringFormat("%0" & String($iLen) & "u", $iCnt) & @CRLF) If StringLen($sX) = 0 Then $bRed = True $sM = $sRem $sRem = _BigNum_DivSub($sRem, $sTm2) If $iCnt > 0 Then $sM = $sRem $sRet &= StringFormat("%0" & String($iLen) & "u", $iCnt) $iTrm = $iLnY - StringLen($sRem) $sTmp = StringLeft($sX, $iTrm) $sX = StringTrimLeft($sX, $iTrm) $iLen = StringLen($sTmp) $sRem &= $sTmp Until $bRed $sM = StringRegExpReplace($sM, "^0+([^0]|0$)", "\1", 1) If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($BN_X + 9 + StringRegExp($sRet, "^0+([^0]|0$)", "\1", 1)) & _BigNum_DS(StringLen(StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)), "-") & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + 9 + StringRegExp($sRet, "^0+([^0]|0$)", "\1", 1)) & StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)) FileClose($BN_File) EndIf Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1) EndFunc ;==>_BigNum_Div_DivisorGreater14 Func _BigNum_Div_DivisorMaxLen14($sX, $sY, ByRef $sM) $sM = "0" If $sY = "1" Then Return $sX If $sX = "0" Or $sY = "0" Or $sX = "" Or $sY = "" Then Return "0" If $BigNum_Debug Then Local $BN_File = FileOpen(@ScriptDir & "\BigNum_Debug.txt", 2), $BN_X = StringLen($sX) FileWrite($BN_File, " " & $sX & " / " & $sY & " = " & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + StringLen($sY) + 3, "-") & @CRLF) EndIf Local $sRet = "", $iRem = StringLeft($sX, 15), $iTmp = 0, $iTrm = 6, $iLen $sX = StringTrimLeft($sX, 15) $iTmp = Floor($iRem / $sY) $sRet &= $iTmp If $BigNum_Debug Then FileWrite($BN_File, " " & $iRem & _BigNum_DS(StringLen($sX) + 10) & $iTmp & @CRLF) $iRem -= $iTmp * $sY While StringLen($sX) > 0 $iTrm = 15 - StringLen($iRem) $iTmp = StringLeft($sX, $iTrm) $iLen = StringLen($iTmp) $iRem &= $iTmp $sX = StringTrimLeft($sX, $iTrm) $iTmp = Floor($iRem / $sY) $iTmp = StringRight("000000000000000" & $iTmp, $iLen) If $BigNum_Debug Then FileWrite($BN_File, _BigNum_DS($BN_X - StringLen($sX) + 1 - StringLen($iRem)) & $iRem & _BigNum_DS(StringLen($sX) + 10 + StringLen($sRet)) & $iTmp & @CRLF) $sRet &= $iTmp $iRem -= $iTmp * $sY WEnd $sM = String($iRem) If $BigNum_Debug Then FileWrite($BN_File, " " & _BigNum_DS($BN_X + 10) & _BigNum_DS(StringLen(StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)), "-") & @CRLF) FileWrite($BN_File, " " & _BigNum_DS($BN_X + 10) & StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)) FileClose($BN_File) EndIf Return StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1) EndFunc ;==>_BigNum_Div_DivisorMaxLen14 Func _BigNum_DivComp($sX, $sY) $sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1) $sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1) Local $iLnX = StringLen($sX), $iLnY = StringLen($sY) If $iLnX < $iLnY Then Return -1 ElseIf $iLnX > $iLnY Then Return 1 Else If $sX < $sY Then Return -1 ElseIf $sX > $sY Then Return 1 Else Return 0 EndIf EndIf EndFunc ;==>_BigNum_DivComp Func _BigNum_DivAdd($sX, $sY) Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = "" If $iLen < $iTmp Then $iLen = $iTmp For $i = 1 To $iLen Step 18 $iTmp = Int(StringRight($sX, 18)) + Int(StringRight($sY, 18)) + $iCar $sX = StringTrimRight($sX, 18) $sY = StringTrimRight($sY, 18) If ($iTmp > 999999999999999999) Then $sRet = StringRight($iTmp, 18) & $sRet $iCar = 1 Else $iTmp = StringRight("000000000000000000" & $iTmp, 18) $sRet = $iTmp & $sRet $iCar = 0 EndIf Next $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1) Return $sRet EndFunc ;==>_BigNum_DivAdd Func _BigNum_DivSub($sX, $sY) Local $iTmp = StringLen($sX), $iLen = StringLen($sY), $iCar = 0, $sRet = "" If $iLen < $iTmp Then $iLen = $iTmp For $i = 1 To $iLen Step 18 $iTmp = Int(StringRight($sX, 18)) - Int(StringRight($sY, 18)) - $iCar $sX = StringTrimRight($sX, 18) $sY = StringTrimRight($sY, 18) If $iTmp < 0 Then $iTmp = 1000000000000000000 + $iTmp $iCar = 1 Else $iCar = 0 EndIf $sRet = StringRight("0000000000000000000" & $iTmp, 18) & $sRet Next $sRet = StringRegExpReplace($iCar & $sRet, "^0+([^0]|0$)", "\1", 1) Return $sRet EndFunc ;==>_BigNum_DivSub Func _BigNum_IsValid($sX, $sY) If StringRegExp($sX, "[^0-9.-]") <> 0 Or StringRegExp($sY, "[^0-9.-]") <> 0 Then Return True Return False EndFunc ;==>_BigNum_IsValid Func _BigNum_InsertDecimalSeparator($sX, $iDec, $iD = 18) If $iD = 0 And $iDec = 0 Then Return $sX Local $sRet = StringRegExpReplace(StringRight(StringFormat("%0" & String($iDec) & "u", "") & $sX, $iDec), "0+$", "\1", 1) $sX = StringTrimRight($sX, $iDec) If $sX = "" Then $sX = "0" $sRet = StringLeft($sRet, $iD) If $sRet = "" Or $sRet = "0" Then Return $sX Return $sX & "." & $sRet EndFunc ;==>_BigNum_InsertDecimalSeparator Func _BigNum_StringIsDecimal(ByRef $sX, ByRef $sY) If StringLeft($sX, 1) = "." Then $sX = "0" & $sX If StringLeft($sY, 1) = "." Then $sY = "0" & $sY Local $iPsX = StringInStr($sX, ".", 0, 1) - 1, $iPsY = StringInStr($sY, ".", 0, 1) - 1 $sX = StringRegExpReplace($sX, "\D", "") $sY = StringRegExpReplace($sY, "\D", "") Local $iLnX = StringLen($sX), $iLnY = StringLen($sY) If $iPsX <= 0 Then $iPsX = $iLnX If $iPsY <= 0 Then $iPsY = $iLnY If $iLnX - $iPsX > $iLnY - $iPsY Then For $iCnt = $iLnY - $iPsY To $iLnX - $iPsX - 1 $sY &= "0" Next Return $iLnX - $iPsX ElseIf $iLnX - $iPsX < $iLnY - $iPsY Then For $iCnt = $iLnX - $iPsX To $iLnY - $iPsY - 1 $sX &= "0" Next Return $iLnY - $iPsY EndIf Return $iLnX - $iPsX EndFunc ;==>_BigNum_StringIsDecimal Func _BigNum_CheckNegative(ByRef $sX, ByRef $sY) Local $bNgX = False, $bNgY = False While StringLeft($sX, 1) = "-" $bNgX = Not $bNgX $sX = StringTrimLeft($sX, 1) WEnd While StringLeft($sY, 1) = "-" $bNgY = Not $bNgY $sY = StringTrimLeft($sY, 1) WEnd $sX = StringRegExpReplace($sX, "^0+([^0]|0$)", "\1", 1) $sY = StringRegExpReplace($sY, "^0+([^0]|0$)", "\1", 1) If $sX = "" Then $sX = "0" If $sY = "" Then $sY = "0" If $bNgX = True And $bNgY = True Then Return 3 ElseIf $bNgX = True And $bNgY = False Then Return 1 ElseIf $bNgX = False And $bNgY = True Then Return 2 Else Return 0 EndIf EndFunc ;==>_BigNum_CheckNegative Func _BigNum_DS($iC, $sS = " ") Local $sRet = "", $iCnt For $iCnt = 1 To $iC $sRet &= $sS Next Return $sRet EndFunc ;==>_BigNum_DS #endregion Internal Functions Mat AutoIt Project Listing
jennico Posted December 22, 2009 Posted December 22, 2009 (edited) hi mat, i don't want to annoy you, but this _BigNum_Sum does not work. try it with small numbers. it does not respect algebraic rules (e.g. mul & div before add & sub), does not work with leading negative terms and floating points. maybe i misunderstood your udf then you might want to explain it better, or you really have to improve your code. cheers j. edit: okay it works with integers and veery simple oprations, but this is way too weak and not reliable. i think, what you want to do, is really a complicated thing and will be a big project if you want to make it work. Edited December 22, 2009 by jennico Spoiler I actively support Wikileaks | Freedom for Julian Assange ! | Defend freedom of speech ! | Fight censorship ! | I will not silence.Don't forget this IP: 213.251.145.96
Mat Posted December 23, 2009 Posted December 23, 2009 I don't see how it cannot do it in the correct order... I can understand floats though, and thats a pretty simple thing to implement. You are right it is quite something to implement in full, but one day hopefully Mat AutoIt Project Listing
eXirrah Posted February 11, 2010 Posted February 11, 2010 (edited) Very nice UDF eukalyptus. It helped me big time and I'd like to thank you and all the contributors for releasing it. Sorry guys, but seems like I can't give reputation point yet. EDIT: _BigNum_Compare() function is not working properly. Example: _BigNum_Compare("1001.2996","16") = 1 ?? 1 means that 16 > 1001.2996 ??? I didn't have the time to follow the function step by step, but as it seems to me it uses autoit string comparison which is to compare strings and not numbers. Autoit string somparison makes simple mistakes when comparing numbers like that: 1001.2996 ? 16 1 = 1 -> 0 0 < 6 -> return 1 1001.2996 < 16 .... for us not true, but for autoit it is I created another algorithm (shown below) that works. As you can see it is not optimized, I just don't have the time to optimize it right now, so I will paste it and try opitimizing it later. EDIT 2: Added some comments for better understanding of the algorithm. EDIT 3: Fixed return values! NumbersCompare(X,Y) returns -1 - Y>X 1 - X>Y EDIT 4: Added Algorithm No.2 which has slightly better performace. expandcollapse popupFunc NumbersCompareOBS($sX,$sY) ;algorithm No.1 Local $sXSign = NumberGetSign($sX) Local $sYSign = NumberGetSign($sY) If $sXSign == "-" And $sYSign == "" Then Return -1 ElseIf $sXSign == "" And $sYSign == "-" Then Return 1 ElseIf $sXSign == "-" And $sYSign == "-" Then Local $sTemp = $sX $sX = $sY $sY = $sTemp EndIf ;Separates the number in Integer and Fraction parts. Local $sXSplit = StringSplit($sX,".") Local $sYSplit = StringSplit($sY,".") ;Compares the Integer parts Local $iRet = NumbersCompareInt($sXSplit[1],$sYSplit[1]) ; if the Integer parts are not equal returns the result If $iRet <> 0 Then Return $iRet EndIf ; if there are no Fraction parts then StringSplit will return only 1 string. If $sXSplit[0]*$sYSplit[0] == 1 Then Return 0 EndIf ; it is already proved that the Integer parts are equal so the algorithm is ;checking if any of the numbers has fraction part ; if X has fraction part it means it is bigger than Y If $sXSplit[0] > $sYSplit[0] Then Return 1 ;if Y has fraction part then it is bigger than X ElseIf $sXSplit[0] < $sYSplit[0] Then Return -1 EndIf ;Compares the fraction parts Local $iRet = NumbersCompareInt($sXSplit[2],$sYSplit[2],1) ;returns the rezilt Return $iRet EndFunc Func NumbersCompareInt($sX,$sY,$bFracPart=0) ;This funrction compares integer only ;Splits the numbers in digits Local $sXSplit = StringSplit($sX,"") Local $sYSplit = StringSplit($sY,"") ;Compares the length of the Integers ;if $bFracPart is set then it just equalizes them If $sXSplit[0] > $sYSplit[0] Then If Not $bFracPart Then Return 1 ReDim $sYSplit[$sXSplit[0]+1] ElseIf $sXSplit[0] < $sYSplit[0] Then If Not $bFracPart Then Return -1 ReDim $sXSplit[$sYSplit[0]+1] $sXSplit[0] = $sYSplit[0] EndIf Local $i = 1 While $i <= $sXSplit[0] ;Compares the numbers digit by digit starting from ;the most significant one If $sXSplit[$i] > $sYSplit[$i] Then Return 1 ElseIf $sXSplit[$i] < $sYSplit[$i] Then Return -1 EndIf $i+=1 WEnd ;If it gets here the Integers are equal Return 0 EndFunc Func NumberGetSign(ByRef $sNum) Local $sRet = StringLeft($sNum,1) If $sRet == "-" Then $sNum = StringTrimLeft($sNum,1) Return $sRet ElseIf $sRet == "+" Then $sNum = StringTrimLeft($sNum,1) EndIf Return "" EndFunc expandcollapse popupFunc NumbersCompare($sX,$sY) ;Algorithm No.2 Local $sXSign = NumberGetSign($sX) Local $sYSign = NumberGetSign($sY) ;Compare Signs If $sXSign == "-" And $sYSign == "" Then Return -1 ElseIf $sXSign == "" And $sYSign == "-" Then Return 1 ElseIf $sXSign == "-" And $sYSign == "-" Then Local $sTemp = $sX $sX = $sY $sY = $sTemp EndIf NumbersEqualizeLength($sX,$sY) ;~ MsgBox(-1,"",$sX & " " & $sY) Return StringCompare($sX,$sY) EndFunc Func NumberGetSign(ByRef $sNum) Local $sRet = StringLeft($sNum,1) If $sRet == "-" Then $sNum = StringTrimLeft($sNum,1) Return $sRet ElseIf $sRet == "+" Then $sNum = StringTrimLeft($sNum,1) EndIf Return "" EndFunc Func NumbersEqualizeLength(ByRef $sX,ByRef $sY) Local $iXDotPos = StringInStr($sX,".") Local $iYDotPos = StringInStr($sY,".") Local $iXLen = StringLen($sX) Local $iYLen = StringLen($sY) Local $iLeading,$iTrailing ;Calculation leading and trailing zeroes If $iXDotPos == 0 And $iYDotPos <> 0 Then $iLeading = $iXLen - ($iYDotPos-1) $iTrailing = -1*($iYLen - $iYDotPos) $sX &= "." ElseIf $iXDotPos <> 0 And $iYDotPos == 0 Then $iLeading = ($iXDotPos-1) - $iYLen $iTrailing = $iXLen - $iXDotPos $sY &= "." ElseIf $iXDotPos == 0 And $iYDotPos == 0 Then $iLeading = $iXLen - $iYLen Else $iLeading = $iXDotPos - $iYDotPos $iTrailing = ($iXLen - $iXDotPos) - ($iYLen-$iYDotPos) EndIf ;adding leading and trailing zeroes If $iLeading < 0 Then $sX = StringAddZeroes($sX,-1*$iLeading,0,0) ElseIf $iLeading > 0 Then $sY = StringAddZeroes($sY,$iLeading,0,0) EndIf If $iTrailing < 0 Then $sX = StringAddZeroes($sX,-1*$iTrailing,1,0) ElseIf $iTrailing > 0 Then $sY = StringAddZeroes($sY,$iTrailing,1,0) EndIf EndFunc Func StringAddZeroes($sString,$iCount,$bTrailing=0,$bToLength=1) ;$bToLength is set when the user wants to add the nescessary amount ;of zeroes to the string so it is with length $iCount (Default) If $bToLength Then $iCount -= StringLen($sString) EndIf Local $i = 0 Local $s = "" While $i < $iCount $s &= "0" $i+=1 WEnd ;$bTrailing is set when the user wants the zeroes to be added at the ;right side of the string. By defaut zeroes are added at the left side of the string If $bTrailing Then Return $sString & $s EndIf Return $s & $sString EndFunc Edited February 12, 2010 by eXirrah
AZJIO Posted July 29, 2010 Posted July 29, 2010 ; test #include <BigNum.au3> MsgBox(0, '1', _BigNum_Div(0.000000000000000001, 21)) MsgBox(0, '2', _BigNum_Div('0.000000000000000001', '21')) MsgBox(0, '3', _BigNum_Mul(0.000000000000000001, 21)) MsgBox(0, '4', _BigNum_Mul('0.000000000000000001', '21')) MsgBox(0, '5', _BigNum_Div(4564564564564, 21)) MsgBox(0, '6', _BigNum_Div('4564564564564', '21')) 1-3 = Error... =0 4-6 = no problems My other projects or all
Yashied Posted July 29, 2010 Posted July 29, 2010 Use $iD (default is 0) parameter for this function. In the following example I used a value of 40. _BigNum_Div('0.0000000000000001', '21', 40) My UDFs: iKey | FTP Uploader | Battery Checker | Boot Manager | Font Viewer | UDF Keyword Manager | Run Dialog Replacement | USBProtect | 3D Axis | Calculator | Sleep | iSwitcher | TM | NetHelper | File Types Manager | Control Viewer | SynFolders | DLL Helper Animated Tray Icons UDF Library | Hotkeys UDF Library | Hotkeys Input Control UDF Library | Caret Shape UDF Library | Context Help UDF Library | Most Recently Used List UDF Library | Icons UDF Library | FTP UDF Library | Script Communications UDF Library | Color Chooser UDF Library | Color Picker Control UDF Library | IPHelper (Vista/7) UDF Library | WinAPI Extended UDF Library | WinAPIVhd UDF Library | Icon Chooser UDF Library | Copy UDF Library | Restart UDF Library | Event Log UDF Library | NotifyBox UDF Library | Pop-up Windows UDF Library | TVExplorer UDF Library | GuiHotKey UDF Library | GuiSysLink UDF Library | Package UDF Library | Skin UDF Library | AITray UDF Library | RDC UDF Library Appropriate path | Button text color | Gaussian random numbers | Header's styles (Vista/7) | ICON resource enumeration | Menu & INI | Tabbed string size | Tab's skin | Pop-up circular menu | Progress Bar without animation (Vista/7) | Registry export | Registry path jumping | Unique hardware ID | Windows alignment More...
eukalyptus Posted August 15, 2010 Author Posted August 15, 2010 first post updated THX for the additional functions I recreated Mat´s _BigNum_Sum and called it _BigNum_Parse: #include "BigNum.au3" $sLine = "-1-(2-4*3^(2*5))/(-2.5)" ConsoleWrite("!Result BigNum: " & _BigNum_Parse($sLine) & @CRLF & "!Result AutoIt: " & Execute($sLine) & @CRLF) DirectSound UDF Direct2D UDF
AZJIO Posted September 7, 2012 Posted September 7, 2012 I recreated Mat´s _BigNum_Sum and called it _BigNum_Parse: #include <BigNum.au3> MsgBox(0, '???', _BigNum_Parse('-0.05 / (0.125 + 0.05) * 7 / 2'))-0.9999997 #include <BigNum.au3> $sText = _BigNum_Add ( '0.125', '0.05' ) $sText = _BigNum_Div ( '-0.05', $sText, 100 ) $sText = _BigNum_Mul ( $sText, '7' ) $sText = _BigNum_Div ( $sText, '2', 100 ) MsgBox(0, '???', $sText)-0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 Can you specify the precision of calculations for the function _BigNum_Parse!? My other projects or all
GPinzone Posted November 26, 2012 Posted November 26, 2012 I'm porting over something from java, which uses their BugNum functions. I need a way to do a XOR with BigNum variables. AutoIT's BitXOR won't work. Does anyone have any ideas? Gerard J. Pinzonegpinzone AT yahoo.com
funkey Posted November 26, 2012 Posted November 26, 2012 You could use my GMP-UDF: I added a Xor example:http://www.autoit.de/index.php?page=Attachment&attachmentID=16822&h=694d3496bcf2998e0fabc1d4e2b4eb8ae4327517 czardas 1 Programming today is a race between software engineers striving tobuild bigger and better idiot-proof programs, and the Universetrying to produce bigger and better idiots.So far, the Universe is winning.
czardas Posted November 26, 2012 Posted November 26, 2012 I like the above example. Thanks. operator64 ArrayWorkshop
GPinzone Posted November 28, 2012 Posted November 28, 2012 I'll give it a go, but unless I'm missing it, there's no Pow function? Gerard J. Pinzonegpinzone AT yahoo.com
Baraoic Posted April 9, 2013 Posted April 9, 2013 Not sure if anybody uses this, but I have rewritten the Parse function and fixed the order of operations and it runs faster as well. It is in the GMP UDF located that you could easily copy and modify for this UDF.
AZJIO Posted December 14, 2013 Posted December 14, 2013 _BigNum_Mul Local $aX = StringRegExp($sX, '\A.{' & 6 - (Ceiling(StringLen($sX) / 6) * 6 - StringLen($sX)) & '}|.{6}+', 3) Local $aX=StringRegExp($sX, '(\A\d{1,5}(?=(?:\d{6})*\z)|\d{6})', 3) -------- If $iTmp <= 1000000 Then $iTmp = StringRight("000000" & $iTmp, 6) If $iTmp < 100000 Then $iTmp = StringRight("000000" & $iTmp, 6) My other projects or all
konya Posted December 10 Posted December 10 (edited) Very like this UDF. Share some math function. expandcollapse popupFunc _BigNum_EXP($a) $Euler_number = "2.71828182845904523536028747135266249" Return _BigNum_FastPow($Euler_number, $a) EndFunc Func _BigNum_FastPow($a, $b) $check = StringSplit($b,".") if $check[0] = "1" Then Local $ans = 1 While $b > "0" If _BigNum_Mod($b, 2) = "1" Then $ans = _BigNum_Mul($ans, $a) $b = _BigNum_Sub($b, "1") Else $a = _BigNum_Mul($a, $a) $b = _BigNum_Div($b, "2", 0) EndIf WEnd Return StringLeft($ans,32) Else $Denominator = "1"&_StringRepeat("0", StringLen($check[2])) $Numerator = _BigNum_add($check[2] ,_BigNum_mul(String($check[1]),$Denominator)) While 1 $GCD = _BigNum_GCD($Denominator, $Numerator) if $GCD <> 1 Then $Denominator/= $GCD $Numerator/= $GCD Else ExitLoop EndIf WEnd $a = _BigNum_n_Root($a,$Denominator,"35") $b = $Numerator Local $ans = 1 While $b > "0" If _BigNum_Mod($b, 2) = "1" Then $ans = _BigNum_Mul($ans, $a) $b = _BigNum_Sub($b, "1") Else $a = _BigNum_Mul($a, $a) $b = _BigNum_Div($b, "2", 0) EndIf WEnd Return $ans EndIf EndFunc Func _BigNum_LCM($a, $b) Local $result = 0, $c = $a , $d = $b While 1 $result = _BigNum_Mod($a, $b) If $result <> 0 Then $a = $b $b = $result Else ExitLoop EndIf WEnd Return _BigNum_Mul(_BigNum_Div($c, $b), $d) EndFunc Func _BigNum_GCD($a, $b) $result = 0 Local $array[0][2], $cc = 1 While 1 $result = _BigNum_Mod($a, $b) If $result <> 0 Then $a = $b $b = $result Else ExitLoop EndIf WEnd Return $b EndFunc Func _BigNum_PowerMod($n, $e, $k) Local $res = "1" While $e > "0" While _BigNum_Mod($e, 2) = "0" $n = _BigNum_Mod(_BigNum_Mul($n, $n), $k) $e = _BigNum_Div($e, "2", 0) WEnd $res = _BigNum_Mod(_BigNum_Mul($res, $n), $k) $e = _BigNum_Sub($e, "1") WEnd Return $res EndFunc Func _BigHex_ToBase_Fast($sDecimal, $iBase) Local $vDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~" If $iBase > StringLen($vDigits) Then SetError(1, 0, 0) $vDigits = StringSplit($vDigits, '', 2) Local $sResult = 0 For $i = 1 To StringLen($sDecimal) $nn = _ArraySearch($vDigits, StringMid($sDecimal, $i, 1)) $sResult = _BigNum_Add(_BigNum_Mul($iBase, $sResult), $nn) Next Return $sResult EndFunc Func _BigNum_inverse($a, $b) $result = 0 Local $array[0][2], $cc = 1 While 1 If Mod($cc, 2) = 1 Then _ArrayAdd($array, $b & "|" & $a) Else _ArrayAdd($array, $a & "|" & $b) EndIf $cc += 1 $result = _BigNum_Mod($a, $b) If $result <> 0 Then $a = $b $b = $result Else ExitLoop EndIf WEnd $cc = 1 Local $d = "", $k = "" For $i = UBound($array) - 1 To 0 Step -1 If $cc = 1 Then If $array[$i][0] = 1 Then $d = 1 Else $d = 1 $k = $array[$i][0] - 1 EndIf EndIf If $cc <> 1 Then If $k = "" Then $k = _BigNum_Div((_BigNum_Sub(_BigNum_Mul($array[$i][0], $d), 1)), $array[$i][1]) Else $d = _BigNum_Div((_BigNum_Add(_BigNum_Mul($array[$i][1], $k), 1)), $array[$i][0]) $k = "" EndIf EndIf $cc += 1 Next Return $d EndFunc Edited December 10 by konya
konya Posted December 11 Posted December 11 (edited) Share fast power module usage table value. 1._BigNum_Calculate_Last_E($n, $e, $k) get last e value. 2._BigNum_PowerMod_Specified_ciphertext($c, $Last_c, $mod) Func _BigNum_Calculate_Last_E($c, $e, $mod) if $mod = 1 then Return 0 $e = _BigNum_Mod($e,_BigNum_Sub($mod,"1")) $c = _BigNum_Mod($c, $mod) While $e > "0" While _BigNum_Mod($e, 2) = "0" $c = _BigNum_Mod(_BigNum_Mul($c, $c), $mod) $e = _BigNum_Div($e, "2", 0) WEnd $e = _BigNum_Sub($e, "1") WEnd Return $c EndFunc Func _BigNum_PowerMod_Specified_ciphertext($c, $Last_c, $mod) $res = _BigNum_Mod($c, $mod) $res = _BigNum_Mod(_BigNum_Mul($res, $Last_c), $mod) ConsoleWrite("Result = " & $res & @CRLF ) Return $res EndFunc Edited December 11 by konya
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