Malkey Posted December 8, 2009 Share Posted December 8, 2009 This DecToFraction() function converts a decimal number to an equivalent fraction. Here is the results of this example script using the DecToFraction() function. The last three results all use Pi, but use increasing accuracy to establish the fraction. ResultsDecimal = -1.2____________ Fraction = -6/5________ = -1 1/5 Decimal = 1.2 _____________Fraction = 6/5 _________= 1 1/5 Decimal = 0.1313__________ Fraction = 13/99 _______= 13/99 Decimal = -2.8571_________ Fraction = -20/7_______ = -2 6/7 Decimal = 0.06667_________ Fraction = 1/15________ = 1/15 Decimal = 3.14 ___________ Fraction = 22/7_________ = 3 1/7 Decimal = 3.14159265358979 Fraction = 333/106_____ = 3 15/106 Decimal = 3.14159265358979 Fraction = 103993/33102 = 3 4687/33102 This appears to work well. Testing will tell. expandcollapse popup#include <Misc.au3> ; Modified method from http://mathforum.org/library/drmath/view/51886.html Local $aDec[8][2] = [[-1.2, 2],[1.2, 9],[Round(13 / 99, 4), 4],[Round(-20 / 7, 4), 4],[0.06667, 5], _ [Round(4 * ATan(1), 2), 2],[4 * ATan(1), 3],[4 * ATan(1), 9]] Local $sRes For $i = 0 To UBound($aDec) - 1 $FracArray = DecToFraction($aDec[$i][0], $aDec[$i][1]) $sRes &= "Decimal = " & $aDec[$i][0] & @TAB & _ " Fraction = " & @TAB & $FracArray[0] * ($FracArray[1] * $FracArray[3] + $FracArray[2]) & "/" & $FracArray[3] & @TAB & _ " = " & _Iif($FracArray[1] <> 0, $FracArray[0] * $FracArray[1], "") & " " & $FracArray[2] & "/" & $FracArray[3] & @CRLF Next MsgBox(0, "Decimals to Fractions", $sRes) ;ConsoleWrite($sRes & @CRLF) ;$iAcc - Accuracy - an integer - The number of decimal places for an equality check to establish the fraction. ;Return an array[4] ; array[0] = Indicates if number is plus or minus, -1 for negative, or, 1 for positive ; array[1] = Integer part of decimal number. ; array[2] = Numerator of fraction ; array[3] = Denominatot of fraction. ; Func DecToFraction($frDec, $iAcc = 2) Local $aAns[4] If $frDec < 0 Then ; Sign +/- $aAns[0] = -1 Else $aAns[0] = 1 EndIf If StringInStr($frDec, ".") > 0 Then Local $aDec = StringSplit(Abs($frDec), ".", 2) $aAns[1] = $aDec[0] ; Integer part of decimal number $fr = Abs(Number("0." & $aDec[1])) Local $a = Floor($fr), $b = Ceiling($fr), $c = $b, $d = $b, $x, $low, $high, $a1, $b1, $c1, $d1 Do $x = Round(($b * $fr - $a) / ($c - $d * $fr), 12) $low = Floor($x) $high = Ceiling($x) $a1 = ($a + $low * $c) $b1 = ($b + $low * $d) $c1 = ($a + $high * $c) $d1 = ($b + $high * $d) $a = $a1 $b = $b1 $c = $c1 $d = $d1 If Abs($a / $b - $fr) < 10.0 ^ (-$iAcc) Then ; 10.0 ^ (-$iAcc) $aAns[2] = $a $aAns[3] = $b ExitLoop ; EndIf If Abs($c / $d - $fr) < 10.0 ^ (-$iAcc) Then ;10.0 ^ (-$iAcc) $aAns[2] = $c $aAns[3] = $d ExitLoop ; EndIf Until 0 Else $aAns[1] = Abs($frDec) EndIf Return $aAns EndFunc ;==>DecToFraction Link to comment Share on other sites More sharing options...
Mat Posted December 8, 2009 Share Posted December 8, 2009 Any how... A few changes. No longer uses string functions, and is slightly shorter (no idea about speed, although it shouldn't change too much) Also, now returns 0/0 if an integer is returned, rather than just blank. Func DecToFraction($frDec, $iAcc= 2) Local $aDec = Int(Abs($frDec)), $aAns[4] = [1, $aDec, 0, 0] If $frDec < 0 Then $aAns[0] = -1 If Mod($frDec, 1) Then $fr = Abs ($frDec - $aDec) Local $a = Floor($fr), $b = Ceiling($fr), $c = $b, $d = $b, $x, $low, $high, $a1, $b1, $c1, $d1 Do $x = Round(($b * $fr - $a) / ($c - $d * $fr), 12) $low = Floor($x) $high = Ceiling($x) $a1 = ($a + $low * $c) $b1 = ($b + $low * $d) $c1 = ($a + $high * $c) $d1 = ($b + $high * $d) $a = $a1 $b = $b1 $c = $c1 $d = $d1 If Abs($a / $b - $fr) < 10.0 ^ (-$iAcc) Then ; 10.0 ^ (-$iAcc) $aAns[2] = $a $aAns[3] = $b ExitLoop EndIf If Abs($c / $d - $fr) < 10.0 ^ (-$iAcc) Then ;10.0 ^ (-$iAcc) $aAns[2] = $c $aAns[3] = $d ExitLoop EndIf Until 0 EndIf Return $aAns EndFunc ;==>DecToFraction I did some work on the integer and fraction parts of a number... This explains those two functions (as well as a few other rounding functions too) http://homepage.smc.edu/kennedy_john/GALLERYROUND.PDF Mat AutoIt Project Listing Link to comment Share on other sites More sharing options...
dantay9 Posted December 8, 2009 Share Posted December 8, 2009 Nice work! I love your math udf's. Link to comment Share on other sites More sharing options...
Mat Posted December 8, 2009 Share Posted December 8, 2009 (edited) Which reminds me. Here is a list of everything maths related on the forums that I could find. I don't think its everything, since its restricted to only a few authors... http://code.google.com/p/m-a-t/wiki/Maths Pm me if you want something added Mat Edit: I completely missed out on Primes.au3 Edited December 8, 2009 by Mat AutoIt Project Listing Link to comment Share on other sites More sharing options...
Malkey Posted December 8, 2009 Author Share Posted December 8, 2009 Any how... A few changes. No longer uses string functions, and is slightly shorter (no idea about speed, although it shouldn't change too much) Also, now returns 0/0 if an integer is returned, rather than just blank. Func DecToFraction($frDec, $iAcc= 2) Local $aDec = Int(Abs($frDec)), $aAns[4] = [1, $aDec, 0, 0] If $frDec < 0 Then $aAns[0] = -1 If Mod($frDec, 1) Then $fr = Abs ($frDec - $aDec) Local $a = Floor($fr), $b = Ceiling($fr), $c = $b, $d = $b, $x, $low, $high, $a1, $b1, $c1, $d1 Do $x = Round(($b * $fr - $a) / ($c - $d * $fr), 12) $low = Floor($x) $high = Ceiling($x) $a1 = ($a + $low * $c) $b1 = ($b + $low * $d) $c1 = ($a + $high * $c) $d1 = ($b + $high * $d) $a = $a1 $b = $b1 $c = $c1 $d = $d1 If Abs($a / $b - $fr) < 10.0 ^ (-$iAcc) Then ; 10.0 ^ (-$iAcc) $aAns[2] = $a $aAns[3] = $b ExitLoop EndIf If Abs($c / $d - $fr) < 10.0 ^ (-$iAcc) Then ;10.0 ^ (-$iAcc) $aAns[2] = $c $aAns[3] = $d ExitLoop EndIf Until 0 EndIf Return $aAns EndFunc ;==>DecToFraction I did some work on the integer and fraction parts of a number... This explains those two functions (as well as a few other rounding functions too) http://homepage.smc.edu/kennedy_john/GALLERYROUND.PDF Mat I found out why your script does not work with negative values. $fr = Abs ($frDec - $aDec) Change to, $fr = Abs ($frDec - int($frDec)) Because $aDec has already be absoluted. So if $frDec is negative, then Abs ($frDec - $aDec) would actually add $frDec and $aDec. Which is happening in your script. Apart from the mistake in logic, I like your alterations/improvements in principle. I don't know if there is an improvement in performance. Link to comment Share on other sites More sharing options...
Mat Posted December 8, 2009 Share Posted December 8, 2009 I found out why your script does not work with negative values.Because $aDec has already be absoluted.So if $frDec is negative, then Abs ($frDec - $aDec) would actually add $frDec and $aDec. Which is happening in your script.Apart from the mistake in logic, I like your alterations/improvements in principle. I don't know if there is an improvement in performance.Ah right... Never noticed that! I don't know if there is an improvement to performance, but I think that its always nice to have *pure* maths solutions.Mat AutoIt Project Listing Link to comment Share on other sites More sharing options...
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