Jump to content

Convert a decimal number to a fraction function.


Malkey
 Share

Recommended Posts

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.

Results

Decimal = -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.

#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

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

Link to comment
Share on other sites

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 by Mat
Link to comment
Share on other sites

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

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

Link to comment
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...