Leaderboard
Popular Content
Showing content with the highest reputation on 10/23/2015 in all areas
-
Fraction
Earthshine reacted to czardas for a topic
Perform accurate division using real fractions and convert floating point numbers to fractions. Floating point arithmetic often introduces small inaccuracies. Most of the time this is not a problem, but sometimes it can be. As a workaround, many programmers decide to only use whole numbers for specific calculations - ones which need to return exact results. The fraction 1/3 cannot be represented using a float. You would need a decimal (or floating point variant) of infinite length to give an accurate representation of 1/3. Working with fractions is not entirely straight forward, and at times this can be a little frustrating. With the functions in this library, there is potential for internal calculations to produce numbers which are out of range. Not withstanding oversights: both input numbers should be less than 16 digits and the difference between the denominator and the divisor should be an order of magnitude less than 10^16, otherwise the function will return an error. With the exception of Fraction(), all included functions take array parameters. All return values are either arrays or boolean values. Documentation and examples pending. NEW VERSION requires operator64.au3 found here: https://www.autoitscript.com/forum/topic/176620-operator64/ This is an alpha release -see post 33. #include-once #include 'operator64.au3' ; #INDEX# ====================================================================================================================== ; Title .........: Fraction ; AutoIt Version : 3.3.14.0 ; Language ......: English ; Description ...: Maths functions intended to be used with vulgar fractions. ; Notes .........: In this library, a fraction is defined as two integers stored in a two element array. ; Several functions use approximation when internal calculations go out of range. ; When an approximation occurs, @extended is set to 1. This return value should be checked in most instances. ; ----------------------------------------------------------------------------------------------------------- ; Input Size Limits for _Fraction() ; Unlimited within the confines of AutoIt (approximately) between -1e+308 and +1e+308 ; Smallest value (approximately) 1e-323 ; -------------------------------------------------------------------- ; Negative Output Size Limits for All Functions That Return a Fraction ; 9223372036854775807 /-1 To -1/ 9223372036854775807 negative range ; - 2^63 /1 Out of range ; tiny negative values are either rounded down to -1/ 9223372036854775807 or rounded up to 0/-1 ; ---------------------------------------------------------------- ; Positive Output Size Limits for Functions That Return a Fraction ; 1/ 9223372036854775807 To 9223372036854775807 /1 positive range ; 2^63 /1 Out of range ; tiny positive values are either rounded up to 1/ 9223372036854775807 or rounded down to 0/1 ; Author(s) .....: czardas, Pheonix XL ; ============================================================================================================================== ; #CURRENT# ==================================================================================================================== ; _Fraction ; _FractionAbs ; _FractionAdd ; _FractionApproximate ; _FractionCeiling ; _FractionDivide ; _FractionFloor ; _FractionMod ; _FractionMultiply ; _FractionPower ; _FractionRoot ; _FractionSubtract ; _IsFraction ; _IsFractionNegative ; _Reciprocal ; ============================================================================================================================== ; #INTERNAL_USE_ONLY#=========================================================================================================== ; __GCD ; __FloatRatio ; __FloatToDigits ; __Quotient ; __Simplify ; ============================================================================================================================== ; #FUNCTION# =================================================================================================================== ; Name...........: _Fraction ; Description ...: Conversion from float to fraction and whole number division. ; Syntax.........: _Fraction($nDividend [, $nDivisor = 1]) ; Parameters.....; $iDividend - Top fractional part ; $iDivisor - [Optional] Lower fractional part. The default value is 1. ; Return Values ; Success - Returns an array of two elements. The first element is the dividend, and the second is the divisor. ; Sets @Extended to 1 if rounding or approximation occurs, or if one of the input parameters is a float. ; Failure sets @error as follows ; |@error = 1 Input contains non-numeric or undefined data. ; |@error = 2 The divisor cannot be zero. ; |@error = 3 Out of range. ; Author ........: czardas ; Comments ......; Accepts Int32, Int64 and floats. Output ranges are shown in the main header. ; ============================================================================================================================== Func _Fraction($nDividend, $nDivisor = 1) If Not IsNumber($nDividend) Or StringInStr($nDividend, '#') Or _ Not IsNumber($nDivisor) Or StringInStr($nDivisor, '#') Then Return SetError(1) ; non-numeric input or undefined value If $nDivisor = 0 Then Return SetError(2) ; division by zero produces meaningless results Local $iExtended = 0 ; will be set to 1 if rounding or approximation occurs, or if one of the input parameters is a float $nDividend = __Integer64($nDividend) If @error Or $nDividend = 0x8000000000000000 Then $iExtended = 1 $nDivisor = __Integer64($nDivisor) If @error Or $nDivisor = 0x8000000000000000 Then $iExtended = 1 Local $aFraction[2] ; if both the dividend and divisor are negative, then both output values will be positive $aFraction[0] = ($nDividend < 0 And $nDivisor > 0) ? -1 : 1 $aFraction[1] = ($nDivisor < 0 And $nDividend > 0) ? -1 : 1 If $iExtended Then ; float parameters require preprocessing $nDividend = Number($nDividend, 3) $nDivisor = Number($nDivisor, 3) __FloatRatio($nDividend, $nDivisor) If @error Then Return SetError(3) ; out of range EndIf If $nDividend = 0 Then $aFraction[0] = 0 $aFraction[1] = $nDivisor > 0 ? 1 : -1 ; a fraction may have a value of negative zero (purpose unknown) Return $aFraction EndIf $nDividend = _Abs64($nDividend) $nDivisor = _Abs64($nDivisor) If $nDividend <> 0 Then __Simplify($nDividend, $nDivisor) ; division by the greatest common divisor $aFraction[0] *= $nDividend ; return values may be negative $aFraction[1] *= $nDivisor ; as above. Return SetExtended($iExtended, $aFraction) EndFunc ;==> _Fraction ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionAbs ; Description ...: Calculates the absolute value of a fraction. ; Syntax.........: _FractionAbs($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing the absolute values of both dividend and divisor. ; Failure sets @error to 1 if the input is not a valid array containing both a dividend and a divisor. ; Author ........: czardas ; ============================================================================================================================== Func _FractionAbs($aFraction) If Not _IsFraction($aFraction) Then Return SetError(1) $aFraction[0] = _Abs64($aFraction[0]) $aFraction[1] = _Abs64($aFraction[1]) Return $aFraction EndFunc ;==> _FractionAbs ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionAdd ; Description ...: Calculates the sum of two fractions. ; Syntax.........: _FractionAdd($aFraction1, $aFraction2) ; Parameters.....; $aFraction1 - The first two element array containing a dividend and a divisor. ; $aFraction2 - The second two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing the sum of the two fractions. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error = 2 The divisor cannot become zero. ; |@error = 3 Out of range. ; Author ........: czardas ; ============================================================================================================================== Func _FractionAdd($aFraction1, $aFraction2) If Not (_IsFraction($aFraction1) And _IsFraction($aFraction2)) Then Return SetError(1) Local $iValue_1, $iValue_2, $iDividend, $iDivisor, $iExtended = 0 If __OverflowDetect('*', $aFraction1[0], $aFraction2[1], $iValue_1) Then $iExtended = 1 If __OverflowDetect('*', $aFraction1[1], $aFraction2[0], $iValue_2) Then $iExtended = 1 If __OverflowDetect('+', $iValue_1, $iValue_2, $iDividend) Then $iExtended = 1 If __OverflowDetect('*', $aFraction1[1], $aFraction2[1], $iDivisor) Then $iExtended = 1 Local $aAddition = _Fraction($iDividend, $iDivisor) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aAddition) EndFunc ;==> _FractionAdd ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionApproximate ; Description ...: Approximates the value of a fraction according to limits imposed on the size of the divisor. ; Syntax.........: _FractionApproximate($aFraction, $iMaxDivisor) ; Parameters.....; $aFraction - A two element array containing a valid dividend and divisor. ; $iMaxDivisor - The maximum numeric limit for the divisor. ; Return values .: Success - Returns a two element array containing the approximated fraction. ; Failure sets @error as follows ; |@error = 1 Invalid input for $aFraction. ; |@error = 2 Invalid input for $iMaxDivisor. ; Author ........: czardas ; Comments ......; Approximates fractions using the method of continued fractions. ; ============================================================================================================================== Func _FractionApproximate($aFraction, $iMaxDivisor) If Not _IsFraction($aFraction) Then Return SetError(1) Local $bNegative = @extended $iMaxDivisor = _Abs64($iMaxDivisor) If @extended Then Return SetError(2, 0, $aFraction) Local $aCurrentFraction = _FractionAbs($aFraction) If $iMaxDivisor < 1 Or $iMaxDivisor >= $aCurrentFraction[1] Or $aCurrentFraction[1] <= 1 Then Return SetError(2, 0, $aFraction) ; determine the terms of the continued fraction Local $sFractionOfFraction = '' Do $sFractionOfFraction &= __Quotient($aCurrentFraction[0], $aCurrentFraction[1]) & ',' $aCurrentFraction[0] = Mod($aCurrentFraction[0], $aCurrentFraction[1]) $aCurrentFraction = _Reciprocal($aCurrentFraction) Until @error Local $aContinued = StringSplit(StringTrimRight($sFractionOfFraction, 1), ',', 2) Local $iTry, $iRange, $iMin = 0, $iMax = Ubound($aContinued) -1, $aConvergence[2] ; binary search algorithm Do $aConvergence[0] = 0 $aConvergence[1] = 1 $iRange = $iMax - $iMin +1 $iTry = $iMin + Floor($iRange/2) If $iTry > $iMax Then $iTry = $iMax ; added patch ; evaluate the significant first few terms of the continued fraction If $iTry > 0 Then For $i = $iTry To 1 Step -1 $aConvergence = _FractionAdd($aConvergence, _Fraction(Number($aContinued[$i]))) $aConvergence = _Reciprocal($aConvergence) Next EndIf $aConvergence = _FractionAdd($aConvergence, _Fraction(Number($aContinued[0]))) If $aConvergence[1] > $iMaxDivisor Then ; aim was too high - target is lower $iMax = $iTry -1 Else ; aim was too low - target may be higher ; log low entry $aCurrentFraction = $aConvergence $iMin = $iTry +1 EndIf Until $iRange <= 1 If $bNegative Then $aCurrentFraction[(($aFraction[0] < 0) ? 0 : 1)] *= -1 Return $aCurrentFraction EndFunc ;==> _FractionApproximate ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionCeiling ; Description ...: Calculates the ceiling value of a fraction. ; Syntax.........: _FractionCeiling($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array ==> The first element is the ceiling value, and the divisor is always 1. ; Failure sets @error as follows ; |@error = 1 The input is not a valid array containing a dividend and a divisor. ; Author ........: czardas ; Comments ......; If the fraction is negative, then its ceiling value represents the integer part of the fraction. ; ============================================================================================================================== Func _FractionCeiling($aFraction) If Not _IsFraction($aFraction) Then Return SetError(1) Local $bNegative = @extended If $aFraction[0] = 0 Then Return $aFraction ; for this to work we need to simplify the fraction $aFraction = _FractionAbs($aFraction) Local $iDividend = $aFraction[0], $iDivisor = $aFraction[1] __Simplify($iDividend, $iDivisor) If $iDivisor = 1 Then Return _Fraction($iDividend * ($bNegative = 0 ? 1 : -1)) Local $iCeiling = __Quotient($iDividend, $iDivisor) If $bNegative Then Return _Fraction($iCeiling * -1) Return _Fraction($iCeiling + 1) EndFunc ;==> _FractionCeiling ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionDivide ; Description ...: Divides the first fraction by the second. ; Syntax.........: _FractionDivide($aDividend, $aDivisor) ; Parameters.....; $aDividend - The first two element array containing a dividend and a divisor. ; $aDivisor - The second two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing the result after division. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error = 2 The divisor cannot become zero. ; |@error = 3 Out of range. ; Author ........: czardas ; ============================================================================================================================== Func _FractionDivide($aDividend, $aDivisor) If Not (_IsFraction($aDividend) And _IsFraction($aDivisor)) Then Return SetError(1) Local $iValue_1, $iValue_2, $iExtended = 0 If __OverflowDetect('*', $aDividend[0], $aDivisor[1], $iValue_1) Then $iExtended = 1 If __OverflowDetect('*', $aDividend[1], $aDivisor[0], $iValue_2) Then $iExtended = 1 If $aDivisor[0] = 0 Then Return SetError(2) Local $aDivision = _Fraction($iValue_1, $iValue_2) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aDivision) EndFunc ;==> _FractionDivide ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionFloor ; Description ...: Calculates the floor value of a fraction. ; Syntax.........: _FractionFloor($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array ==> The first element is the floor value, and the divisor is always 1. ; Failure sets @error as follows ; |@error = 1 The input is not a valid array containing a dividend and a divisor. ; Author ........: czardas ; Comments ......; If the fraction is positive, then its floor value represents the integer part of the fraction. ; ============================================================================================================================== Func _FractionFloor($aFraction) If Not _IsFraction($aFraction) Then Return SetError(1) Local $bNegative = @extended If $aFraction[0] = 0 Then Return $aFraction ; for this to work we need to simplify the fraction $aFraction = _FractionAbs($aFraction) Local $iDividend = $aFraction[0], $iDivisor = $aFraction[1] __Simplify($iDividend, $iDivisor) If $iDivisor = 1 Then Return _Fraction($iDividend * ($bNegative = 0 ? 1 : -1)) Local $iFloor = __Quotient($iDividend, $iDivisor) If Not $bNegative Then Return _Fraction($iFloor) Return _Fraction($iFloor * -1 - 1) EndFunc ;==> _FractionFloor ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionMod ; Description ...: Performs the modulus operation with two fractions. ; Syntax.........: _FractionMod($aDividend, $aDivisor) ; Parameters.....; $aDividend - The first fraction is the dividend array. ; $aDivisor - The second fraction is the divisor array. ; Return values .: Success - Returns a two element array containing the modulus of $aDividend and $aDivisor. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error to: ; |@error = 1 Out of bounds - Fraction division failure. ; |@error = 2 Out of bounds - Fraction multiplication failure. ; |@error = 3 Out of bounds - Fraction subtraction failure. ; Author ........: czardas ; ============================================================================================================================== Func _FractionMod($aDividend, $aDivisor) Local $iExtended = 0, $aDivision = _FractionDivide($aDividend, $aDivisor) If @error Then Return SetError(1) If @extended Then $iExtended = @extended Local $aModulus[2] If $aDividend[0] = 0 Then $aModulus[0] = 0 $aModulus[1] = ($aDividend[0] < 0) ? -1 : 1 Return $aModulus EndIf Local $aMultiple = _FractionMultiply(_FractionAbs($aDivisor), _FractionFloor(_FractionAbs($aDivision))) If @error Then Return SetError(2) If @extended Then $iExtended = @extended $aModulus = _FractionSubtract(_FractionAbs($aDividend), $aMultiple) If @error Then Return SetError(3) If @extended Then $iExtended = @extended If _IsFractionNegative($aDividend) Then If $aDividend[0] < 0 Then $aModulus[0] *= -1 Else $aModulus[1] *= -1 EndIf EndIf Return SetExtended($iExtended, $aModulus) EndFunc ;==> _FractionMod ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionMultiply ; Description ...: Calculates the product of two fractions. ; Syntax.........: _FractionMultiply($aFraction1, $aFraction2) ; Parameters.....; $aFraction1 - The first two element array containing a dividend and a divisor. ; $aFraction2 - The second two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing the product of the two fractions. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error > 1 Internal calculations went out of range. ; Author ........: czardas ; ============================================================================================================================== Func _FractionMultiply($aFraction1, $aFraction2) If Not (_IsFraction($aFraction1) And _IsFraction($aFraction2)) Then Return SetError(1) Local $iValue_1, $iValue_2, $iExtended = 0 If __OverflowDetect('*', $aFraction1[0], $aFraction2[0], $iValue_1) Then $iExtended = 1 If __OverflowDetect('*', $aFraction1[1], $aFraction2[1], $iValue_2) Then $iExtended = 1 Local $aProduct = _Fraction($iValue_1, $iValue_2) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aProduct) EndFunc ;==> _FractionMultiply ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionPower ; Description ...: Raises a fraction to the power of a fraction. ; Syntax.........: _FractionPower($aFraction, $aPower) ; Parameters.....; $aFraction - The first two element array containing a dividend and a divisor. ; $aPower - The second two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing $aFraction to the power of $aPower. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error = 3 Out of range. ; |@error = 5 Imaginary fraction detected. ; Author ........: czardas ; Comments ......; Calculating fractional powers of approximated negative fractions leads to ambiguity. ; ============================================================================================================================== Func _FractionPower($aFraction, $aPower) If Not _IsFraction($aPower) Then Return SetError(1) Local $bNegative = _IsFractionNegative($aFraction) If @error Then Return SetError(1) If $bNegative And Mod($aPower[1], 2) = 0 Then Return SetError(5) Local $iSign = ($bNegative And Mod($aPower[0], 2) <> 0) ? -1 : 1 $aFraction = _FractionAbs($aFraction) Local $iExtended, $iPower = __WholeNumberDivision($aPower[0], $aPower[1]) If @extended Then $iExtended = 1 Local $iDividend If $iExtended Then $iDividend = $aFraction[0] ^ $iPower Else $iDividend = _Power64($aFraction[0], $iPower) If @extended Then $iExtended = 1 EndIf Local $iDivisor If $iExtended Then $iDivisor = $aFraction[1] ^ $iPower Else $iDivisor = _Power64($aFraction[1], $iPower) If @extended Then $iExtended = 1 EndIf $aPower = _Fraction($iSign * $iDividend, $iDivisor) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aPower) EndFunc ;==> FractionPower ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionRoot ; Description ...: Calculates the fractional root of a fraction. ; Syntax.........: _FractionRoot($aFraction, $aRoot) ; Parameters.....; $aFraction - The first two element array containing a dividend and a divisor. ; $aRoot - The second two element array containing a dividend and a divisor. ; Return values .: Success - Returns a two element array containing $aFraction to the power of the reciprocal of $aRoot. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error = 3 Out of range. ; |@error = 5 Imaginary fraction detected. ; Author ........: czardas ; Comments ......; Calculating fractional roots of approximated negative fractions leads to ambiguity. ; ============================================================================================================================== Func _FractionRoot($aFraction, $aRoot) If Not _IsFraction($aRoot) Then Return SetError(1) Local $bNegative = _IsFractionNegative($aFraction) If @error Then Return SetError(1) If $bNegative And Mod($aRoot[0], 2) = 0 Then Return SetError(5) Local $iSign = ($bNegative And Mod($aRoot[1], 2) <> 0) ? -1 : 1 $aFraction = _FractionAbs($aFraction) Local $iExtended, $iRoot = __WholeNumberDivision($aRoot[0], $aRoot[1]) If @extended Then $iExtended = 1 Local $iDividend If $iExtended Then $iDividend = $aFraction[0] ^ (1 / $iRoot) Else $iDividend = _Root64($aFraction[0], $iRoot) If @extended Then $iExtended = 1 EndIf Local $iDivisor If $iExtended Then $iDivisor = $aFraction[1] ^ (1 / $iRoot) Else $iDivisor = _Root64($aFraction[1], $iRoot) If @extended Then $iExtended = 1 EndIf $aRoot = _Fraction($iSign * $iDividend, $iDivisor) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aRoot) EndFunc ;==> FractionRoot ; #FUNCTION# =================================================================================================================== ; Name...........: _FractionSubtract ; Description ...: Subtracts the second fraction from the first. ; Syntax.........: _FractionSubtract($aFraction1, $aFraction2) ; Parameters.....; $aFraction1 - The first two element array containing a dividend and a divisor. ; $aFraction2 - The second two element array containing a dividend and a divisor (subtracted from $aFraction1). ; Return values .: Success - Returns a two element array containing the resulting fraction. ; Sets @Extended to 1 if rounding or approximation occurs. ; Failure sets @error as follows ; |@error = 1 Invalid input. ; |@error = 2 The divisor cannot become zero. ; |@error = 3 Out of range. ; Author ........: czardas ; ============================================================================================================================== Func _FractionSubtract($aFraction1, $aFraction2) If Not (_IsFraction($aFraction1) And _IsFraction($aFraction2)) Then Return SetError(1) Local $iValue_1, $iValue_2, $iDividend, $iDivisor, $iExtended = 0 If __OverflowDetect('*', $aFraction1[0], $aFraction2[1], $iValue_1) Then $iExtended = 1 If __OverflowDetect('*', $aFraction1[1], $aFraction2[0], $iValue_2) Then $iExtended = 1 If __OverflowDetect('-', $iValue_1, $iValue_2, $iDividend) Then $iExtended = 1 If __OverflowDetect('*', $aFraction1[1], $aFraction2[1], $iDivisor) Then $iExtended = 1 Local $aSubtraction = _Fraction($iDividend, $iDivisor) If @extended Then $iExtended = 1 Return SetError(@error, $iExtended, $aSubtraction) EndFunc ;==> _FractionSubtract ; #FUNCTION# =================================================================================================================== ; Name...........: _IsFraction ; Description ...: Checks if the input is an array containing two valid integers ==> representing dividend and divisor. ; Syntax.........: _IsFraction($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Returns True if the input matches the criteria, otherwise returns False. ; Author.........: czardas ; Comments ......; Sets @extended to 1 if the fraction is negative. ; ============================================================================================================================== Func _IsFraction($aFraction) If Not IsArray($aFraction) Then Return False If Ubound($aFraction,0) <> 1 Or Ubound($aFraction) <> 2 Then Return False If Not StringInStr(VarGetType($aFraction[0]), 'Int') Or $aFraction[0] = 0x8000000000000000 Then Return False If Not StringInStr(VarGetType($aFraction[1]), 'Int') Or $aFraction[1] = 0x8000000000000000 Then Return False Return SetExtended((($aFraction[0] < 0 And $aFraction[1] > 0) Or ($aFraction[0] >= 0 And $aFraction[1] < 0)) ? 1 : 0, True) EndFunc ;==> _IsFraction ; #FUNCTION# =================================================================================================================== ; Name...........: _IsFractionNegative ; Description ...: Checks if the input array is a negative fraction. ; Syntax.........: _IsFractionNegative($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Returns True if the dividend and the divisor are of the opposite sign, othewise returns False. ; Failure sets @error to 1 if the input is not a valid array containing a dividend and a divisor. ; Author.........: czardas ; ============================================================================================================================== Func _IsFractionNegative($aFraction) Local $bNegative, $bIsFraction = _IsFraction($aFraction) $bNegative = @extended Return SetError(1 - $bIsFraction, 0, ($bNegative = 1)) EndFunc ;==> _IsFractionNegative ; #FUNCTION# =================================================================================================================== ; Name...........: _Reciprocal ; Description ...: Inverts a fraction by swapping the dividend and the divisor. ; Syntax.........: _Reciprocal($aFraction) ; Parameters.....; $aFraction - A two element array containing a dividend and a divisor. ; Return values .: Returns the reciprocal of the fraction. ; Failure sets @error as follows ; |@error = 1 The input is not a valid array containing a dividend and a divisor. ; |@error = 2 The divisor cannot become zero. ; Author.........: czardas ; ============================================================================================================================== Func _Reciprocal($aFraction) If Not _IsFraction($aFraction) Then Return SetError(1) Local $iDivisor = $aFraction[0] If $iDivisor = 0 Then Return SetError(2) $aFraction[0] = $aFraction[1] $aFraction[1] = $iDivisor Return $aFraction EndFunc ;==> _Reciprocal ; #INTERNAL_USE_ONLY# ========================================================================================================== ; Name...........: __FloatRatio ; Description ...: Helper function for Fraction() - preprocessing of float parameters to generate two proportional integers. ; Syntax.........: __FloatRatio([ByRef] $nDividend, [ByRef] $nDivisor) ; Parameters.....; $iDividend - Top fractional part ; $iDivisor - Lower fractional part ; Return values .: Success - Integer values are returned ByRef. ; Failure sets @error as follows ; |@error = 1 Out of bounds. ; Author ........: czardas ; Comments ......; No attempt has been made to accomodate for any double precision limitations. ; Small innacuracies can affect the 17th and (sometimes) the 16th digit in double precision. ; Using floats can easily be avoided by only passing integers to the function _Fraction(). ; Input positive floats only ; ============================================================================================================================== Func __FloatRatio(ByRef $nDividend, ByRef $nDivisor) If $nDivisor < 0 Then $nDividend *= -1 $nDivisor *= -1 EndIf If $nDivisor <> 1 Then $nDividend /= $nDivisor Local $nSignificand, $iExponent, $iDigits = 16 ; might as well grab as many digits as are available $nSignificand = __FloatToDigits($nDividend, $iDigits) $iExponent = @extended $nSignificand = Number($nSignificand, 2) ; Int-64 While $iExponent < - 18 ; divide the significand by powers of 10 $iDigits -= 1 If $iDigits < 0 Then ; too small If $nDividend < 1 / (2 * 10 ^ 18) Then ; round down to 0 / 1 $nSignificand = 0 $iExponent = 0 Else ; round up to 1 / 1000000000000000000 $nSignificand = 1 $iExponent = 18 EndIf ExitLoop EndIf $nSignificand = __FloatToDigits($nDividend, $iDigits) $iExponent = @extended ; adjust the exponent to accomodate division of the significand $nSignificand = Number($nSignificand, 2) ; Int-64 WEnd While $iExponent > 0 ; multiply the significand by powers of 10 If __OverflowDetect('*', $nSignificand, 10, $nSignificand) Then Return SetError(1) ; too large ~ out of bounds $iExponent -= 1 ; adjust the exponent to accomodate multiplication of the significand If $iExponent = 0 Then ExitLoop WEnd $nDividend = $nSignificand ; range 0 to 1000000000000000000 $nDivisor = _Power64(10, Abs($iExponent)) ; range 10 ^ (0 to 18) ==> powers of 10 only EndFunc ;==> __FloatRatio ; #INTERNAL_USE_ONLY# ========================================================================================================== ; Name...........: __FloatToDigits ; Description ...: Extracts a specified number of digits from a float. ; Syntax.........: __FloatToDigits($fFloat, $iDigits) ; Parameters.....; $fFloat - The float to extract the digits from. ; $iDigits - The number of digits to extract after the floating point (exponential representation). ; Return values .: Success - Returns a 32-bit or 64-bit signed integer. ; Sets @extended to the decimal exponent. ==> $fFloat = return value * 10 ^ exponent ; Failure sets @error to 1 if the input is not a float or undefined. ; Author ........: czardas ; ============================================================================================================================== Func __FloatToDigits($fFloat, $iDigits = 14) If VarGetType($fFloat) <> 'Double' Or StringInStr($fFloat, '#') Then Return SetError(1) Local $iSign = ($fFloat < 0) ? -1 : 1 ; machine epsilon = 5 × 10^-15, so the final two digits (16 and 17) could be highly innacurate $fFloat = StringFormat('%.' & $iDigits & 'e', $fFloat) ; rounds to the specified number of decimal places Local $aFloat = StringSplit($fFloat, "e", 2) ; zero-based array If $iSign < 0 Then $aFloat[0] = StringTrimLeft($aFloat[0], 1) ; remove the minus sign ; remove the decimal point and trailing zeros $aFloat[0] = StringLeft($aFloat[0], 1) & StringRegExpReplace(StringRight($aFloat[0], $iDigits), '(0+\z)', '') $aFloat[1] += 1 - StringLen($aFloat[0]) ; adjust the exponent to accommodate changes Return SetExtended($aFloat[1], Int($aFloat[0]) * $iSign) ; add back the minus sign EndFunc ;==> __FloatToDigits ; #INTERNAL_USE_ONLY# ========================================================================================================== ; Name...........: __GCD ; Description ...: Calculates the greatest common divisor of two integers. Original function name ==> _Greatest_Common_Factor() ; Syntax.........: __GCD($iValue1, $iValue2) ; Parameters.....; $iValue1 - First Integer. ; $iValue2 - Second Integer. ; Return values .: Success - Returns the greatest common divisor of $iValue1 and $iValue2. ; Author.........: Pheonix XL ; Modified.......; czardas ; Comments ......; IMPORTANT - Error checks have been removed. You must run the checks if you use this function yourself. ; ============================================================================================================================== Func __GCD($iValue1, $iValue2) ; Only accepts positive integers greater than zero. ; If Not (IsInt($iValue1) And IsInt($iValue2)) Or $iValue1 < 1 Or $iValue2 < 1 Then Return SetError(1) Local $iToggle If $iValue1 < $iValue2 Then ; Switch values. $iToggle = $iValue1 $iValue1 = $iValue2 $iValue2 = $iToggle EndIf Local $iModulus While 1 ; Method of Euclid. $iModulus = Mod($iValue1, $iValue2) If $iModulus = 0 Then ExitLoop $iValue1 = $iValue2 $iValue2 = $iModulus WEnd Return $iValue2 EndFunc ;==> __GCD ; #INTERNAL_USE_ONLY# ========================================================================================================== ; Name...........: __Quotient ; Description ...: Returns the quotient after division ~(the whole number part of a fraction). ; Syntax.........: __Quotient($nDividend, $nDivisor) ; Parameters.....; $iDividend - The integer to divide ; $iDivisor - The integer to divide by ; Return values .: Returns the quotient. ; Author ........: czardas ; Comments ......; Uses the same correction method as __WholeNumberDivision() in operator64.au3. ; ============================================================================================================================== Func __Quotient($nDividend, $nDivisor) Local $iQuotient = Floor($nDividend / $nDivisor), $iDifference, $iIntegral While $iQuotient * $nDivisor > $nDividend ; division is overstated $iDifference = ($nDivisor * $iQuotient) - $nDividend $iIntegral = Floor($iDifference / $nDivisor) ; avoid shooting beyond the target If $iIntegral = 0 Then $iIntegral = 1 ; prevents hanging in an infinite loop $iQuotient -= $iIntegral WEnd While $iQuotient * $nDivisor < $nDividend ; division is understated $iDifference = $nDividend - ($nDivisor * $iQuotient) $iIntegral = Floor($iDifference / $nDivisor) ; as above If $iIntegral = 0 Then ExitLoop ; we have found the floor already $iQuotient += $iIntegral WEnd Return $iQuotient EndFunc ;==> __Quotient ; #INTERNAL_USE_ONLY# ========================================================================================================== ; Name...........: __Simplify ; Description ...: Simplification by division. ; Syntax.........: __Simplify($iDividend, $iDivisor) ; Parameters.....; $iDividend - Top fractional part. ; $iDivisor - Lower fractional part. ; Author ........: czardas ; ============================================================================================================================== Func __Simplify(ByRef $iDividend, ByRef $iDivisor) Local $iGCD = __GCD($iDividend, $iDivisor) If $iGCD > 1 Then $iDividend = __WholeNumberDivision($iDividend, $iGCD) $iDivisor = __WholeNumberDivision($iDivisor, $iGCD) EndIf EndFunc ;==> __SimplifyExamples - currently testing for accuracy and possible bugs. #include 'Fraction.au3' Local $aFraction = _Fraction(3.1416) If @error Then Exit ; ==> Error handling. ConsoleWrite("3.1416 = " & $aFraction[0] & " / " & $aFraction[1] & @LF) $aFraction = _Fraction(0.125 , 2) ConsoleWrite("0.125 / 2 = " & $aFraction[0] & " / " & $aFraction[1] & @LF) $aFraction = _Fraction(0.00125, -0.32) ConsoleWrite("0.00125 / -0.32 = " & $aFraction[0] & " / " & $aFraction[1] & @LF) $aFraction = _Fraction(86418753, 2977963408767) ConsoleWrite("86418753 / 2977963408767 = " & $aFraction[0] & " / " & $aFraction[1] & @LF) ; Multiply two fractions (27 / 28 x 374 / 555) using whole number arithmetic: Local $aProduct = _FractionMultiply(_Fraction(27, 28), _Fraction(374, 555)) ConsoleWrite("27 / 28 x 374 / 555 = " & $aProduct[0] & " / " & $aProduct[1] & @LF) ; The modulus of two fractions: Local $aMod = _FractionMod(_Fraction(-1, 2), _Fraction(1, 3)) ConsoleWrite("Mod(-1/2, 1/3) = " & $aMod[0] & "/" & $aMod[1] & @LF) ; Represent pi (as accurately as possible) using a fraction with denominator of no more than thirteen digits. Local $aPi = _FractionApproximate(_Fraction(3.14159265358979), 1e+013 -1) ConsoleWrite($aPi[0] & " / " & $aPi[1] & " = " & $aPi[0] / $aPi[1] & " ~ Pi" & @LF) Local $aR2 = _FractionApproximate(_Fraction(2^.5), 1.0e+13 -1) ConsoleWrite($aR2[0] & " / " & $aR2[1] & " = " & $aR2[0] / $aR2[1] & " ~ 2^(1/2)" & @LF) Local $aLarge = _Fraction(1.23456789e+017,100000000000000100) If @error Then MsgBox(0, "", @error) ConsoleWrite(@extended & @LF) ConsoleWrite($aLarge[0] & " / " & $aLarge[1] & " = " & $aLarge[0] / $aLarge[1] & " = " & 1.23456789e+017 / 100000000000001000 & @LF) Local $aSmall = _Fraction(1.23456789e-200,8.64197523e-192) If @error Then MsgBox(0, "", @error) ConsoleWrite(@extended & @LF) ConsoleWrite($aSmall[0] & " / " & $aSmall[1] & " = " & $aSmall[0] / $aSmall[1] & " = " & 1.23456789e-200 / 8.64197523e-192 & @LF) Local $aTooSmall = _Fraction(1.23456789e-200,100000000000000100) If @error Then MsgBox(0, "", @error) ConsoleWrite("@extended = " & @extended & @LF) ConsoleWrite($aTooSmall[0] & " / " & $aTooSmall[1] & " = " & $aTooSmall[0] / $aTooSmall[1] & " = " & 1.23456789e-200 / 100000000000001000 & @LF) Local $aTooLarge = _Fraction(100000000000000100, 1.23456789e-200) ConsoleWrite("@error = " & @error & @LF) Local $aAddApprox = _FractionAdd(_Fraction(134567890000, 999999999999), _Fraction(987654321000, 777777777777777)) ConsoleWrite("@extended = " & @extended & @LF) ConsoleWrite($aAddApprox[0] & " / " & $aAddApprox[1] & " = " & $aAddApprox[0] / $aAddApprox[1] & " = " & (134567890000/999999999999 + 987654321000/777777777777777) ; See post 33 for information on the latest update.1 point -
Use an array for the control handles so you can use a For..Next loop, Jos1 point
-
Not quite, the opposite really, COM errors are not fatal in themselves but will obviously affect your script and could cause them to fail. But yes error handlers must be used by any sane person. In the past AutoIt was handling them when one was not present.1 point
-
Error Excel RangeRead (Solved)
Danyfirex reacted to JLogan3o13 for a topic
Can you share exactly what the error is? Might help us a bit. The code runs fine for me, as long as I change the path: #include <Array.au3> #include <Excel.au3> #include <MsgBoxConstants.au3> Local $oExcel = _Excel_Open() Local $oWorkbook = _Excel_BookOpen($oExcel, @ScriptDir & "\Test.xlsx", Default, Default, 2) Local $aResult = _Excel_RangeRead($oWorkbook) _ArrayDisplay($aResult, "Excel UDF: _Excel_RangeRead Example 2 - Cells A1:C1 of sheet 2")Edit: I should specify, I put in 2 because you stated you're trying to read the formulas of a cell range. Also, your text in the _Arraydisplay does not match your call to _Excel_RangeRead, you're reading in the whole sheet, not A1:C1. Wasn't sure which you were truly after.1 point -
ObjEvent (COM error handling) - AutoIt 3.3.14.2
trancexx reacted to francoiste for a topic
interesting. in the changelog i found for version "3.3.10.0" so it seems this was now rolled-back by version "3.3.14.2"? conclusion: from now on i'll put custom COM error handlers all over the place. because otherwise it breaks my scripts.1 point -
I hope you don't mind but I modified one of your functions. Func _Process_GetPIDsuperEX($sProcess) Return ProcessExists($sProcess) EndFunc1 point
-
Thanks. I'm happy that some wants to do it. mLipok1 point
-
Imagesearch ? CCleaner
feistcomputers reacted to JohnOne for a topic
Well for a start you have no error checking or debugging lines such as ConsoleWrite or MsgBox to indicate where you are in your script and what is failing. You could add this to top of script to begin with. Opt("TrayIconDebug", 1) ;0=no info, 1=debug line info Then when you hover mouse over tray Icon, it will show in a tooltip what file and code line your script is at.1 point -
Do not read the file line by line but either as a whole or by reading bigger chunks into an array and then process the array.1 point
-
[Solved] Auto-resizing RichEdit control
pixelsearch reacted to Mat for a topic
You have to handle the WM_SIZE message yourself unfortunately, and then use ControlMove (Or MoveWindow as I have). This means doing all the maths yourself as well, as you don't get the easy to use resizing flags. This is a simple case with a 2px border on all sides, so the maths wasn't hard. #include<GUIRichEdit.au3> #include<WindowsConstants.au3> #include<EditConstants.au3> #include<WinAPI.au3> Global $hGUI = GUICreate("Testing WM_SIZE", 350, 250, -1, -1, BitOR($WS_THICKFRAME, $WS_POPUP, $WS_CAPTION, $WS_SYSMENU)) Global $hRichEdit = _GUICtrlRichEdit_Create($hGUI, "This is a test.", 2, 2, 346, 246, BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL)) GUIRegisterMsg($WM_SIZE, "WM_SIZE") GUISetState() While True $iMsg = GUIGetMsg() Select Case $iMsg = -3 _GUICtrlRichEdit_Destroy($hRichEdit) GUIDelete() Exit EndSelect WEnd Func WM_SIZE($hWnd, $iMsg, $wParam, $lParam) Local $iWidth = _WinAPI_LoWord($lParam) Local $iHeight = _WinAPI_HiWord($lParam) _WinAPI_MoveWindow($hRichEdit, 2, 2, $iWidth - 4, $iHeight - 4) Return 0 EndFunc ;==>WM_SIZE1 point