Sie sind auf Seite 1von 12

Algorithmforsimplifyingdecimaltofractions

31

Itriedwritinganalgorithmtosimplifyadecimaltoafractionandrealizeditwasn'ttoosimple.
SurprisinglyIlookedonlineandallthecodesIfoundwhereeithertoolong,orwouldn'tworkinsome
cases.Whatwasevenmoreannoyingwasthattheydidn'tworkforrecurringdecimals.Iwas
wonderinghoweverwhethertherewouldbeamathematician/programmerherewhounderstandsall
theinvolvedprocessesinsimplifyingadecimaltoafraction.Anyone?
c# .net algorithm math

10

share improvethisquestion

askedFeb26'11at2:55

ChibuezeOpata
5,091

23

48

Youaretryingtowrite 0.333333... as 1/3 forexample?EelvexFeb26'11at2:58


yep!1.666666666667as1/6andsoon.. ChibuezeOpata Feb26'11at3:04
3 @Jerry,Ithinkheprobablymeant0.1666667,whichis1/6.HaldeanBrownFeb26'11at3:30
@haldean:yeahthanks..@jerry:itwasatypo... ChibuezeOpata Feb26'11at4:05
IhadsomethingsimilarbutIwasonlydoingasubsetoffractions.1/16through15/16.Ididn'tallow1/324or
anythingthatwouldgenerate5+decimalplaces.IsimplymadeaDictionary<string,decimal>andadded
eachpossibletractionasakeyandit'sdecimalequivalent.Thenusedlinqtosearchthedictionaryforthe
keywho'sdecimalvaluewasclosesttotheinputdecimalvalue.Againitonlyworksforasmallsubsetof
fractions.Whenyougettothehundrethsplace,itlosesaccuracy.Rafiki14hoursago
addacomment

16Answers

31

active

oldest

votes

ThealgorithmthattheotherpeoplehavegivenyougetstheanswerbycalculatingtheContinued
Fractionofthenumber.Thisgivesafractionalsequencewhichisguaranteedtoconvergevery,very
rapidly.Howeveritisnotguaranteedtogiveyouthesmallestfractionthatiswithinadistanceepsilon
ofarealnumber.TofindthatyouhavetowalktheSternBrocottree.
Todothatyousubtractoffthefloortogetthenumberintherange[0,1),thenyourlowerestimateis0,
andyourupperestimateis1.Nowdoabinarysearchuntilyouarecloseenough.Ateachiterationif
yourlowerisa/bandyourupperisc/dyourmiddleis(a+c)/(b+d).Testyourmiddleagainstx,and
eithermakethemiddletheupper,thelower,orreturnyourfinalanswer.
Hereissomeverynonidiomatic(andhence,hopefully,readableevenifyoudon'tknowthelanguage)
Pythonthatimplementsthisalgorithm.
deffloat_to_fraction(x,error=0.000001):
n=int(math.floor(x))
x=n
ifx<error:
return(n,1)
elif1error<x:
return(n+1,1)
#Thelowerfractionis0/1
lower_n=0
lower_d=1
#Theupperfractionis1/1
upper_n=1
upper_d=1
whileTrue:
#Themiddlefractionis(lower_n+upper_n)/(lower_d+upper_d)
middle_n=lower_n+upper_n
middle_d=lower_d+upper_d
#Ifx+error<middle
ifmiddle_d*(x+error)<middle_n:
#middleisournewupper
upper_n=middle_n
upper_d=middle_d
#ElseIfmiddle<xerror
elifmiddle_n<(xerror)*middle_d:
#middleisournewlower
lower_n=middle_n
lower_d=middle_d
#Elsemiddleisourbestfraction
else:
return(n*middle_d+middle_n,middle_d)
share improvethisanswer

editedFeb26'11at18:13

answeredFeb26'11at17:36

btilly
20.1k

29

46

+1thisisagreatsolutionforfindingsmooth,humanfriendlyfractions.TimMedoraNov19'12at6:59
3 TranslatedthistoC#andaddedtestresultsforthisalgorithmseemyanswerKayZedOct2'15at9:01
Icameupwithanother,apparentlyfaster,solutionPinkFloydJun1at16:03
addacomment

Iknowyousaidyousearchedonline,butifyoumissedthefollowingpaperitmightbeofsomehelp.It
includesacodeexampleinPascal.

13

AlgorithmToConvertADecimalToAFraction*
Alternatively,aspartofit'sstandardlibrary,Rubyhascodethatdealswithrationalnumbers.Itcan
convertfromfloatstorationalsandviceversa.Ibelieveyoucanlookthroughthecodeaswell.The
documentationisfoundhere.Iknowyou'renotusingRuby,butitmighthelptolookatthealgorithms.
Additionally,youcancallRubycodefromC#(orevenwriteRubycodeinsideaC#codefile)ifyou
useIronRuby,whichrunsontopofthe.netframework.
*Updatedtoanewlinkusinghttp://www.docstoc.com/asitappearstheoriginalURLisnobroken
(http://homepage.smc.edu/kennedy_john/DEC2FRAC.pdf)

share improvethisanswer

editedFeb26'13at20:59

answeredFeb26'11at3:04

Matt
9,053

31

55

Thisisreallyagreatarticle,andIthinkthat'swhatmostareusing,butithappensthepersonwhoI
downloadedhiscode(translatedthecodetoc#)didn'ttoitwell.I'lltestitnow,:) ChibuezeOpata Feb26
'11at3:31
Thelinkleadstoanerrorpage.DanielFeb26'13at10:28
@Daniel:Tryitnow.MattFeb26'13at20:59
@MattItworks,thanks!DanielFeb26'13at22:13
addacomment

IfoundthesamepaperthatMattreferenced,andItookasecondandimplementeditinPython.
Maybeseeingthesameideaincodewillmakeitclearer.Granted,yourequestedananswerinC#
andI'mgivingittoyouinPython,butit'safairlytrivialprogram,andI'msureitwouldbeeasyto
translate.Theparametersare num (thedecimalnumberyou'dliketoconverttoarational)
and epsilon (themaximumalloweddifferencebetween num andthecalculatedrational).Some
quicktestrunsfindthatitusuallyonlytakestwoorthreeiterationstoconvergewhen epsilon is
around1e4.
defdec2frac(num,epsilon,max_iter=20):
d=[0,1]+([0]*max_iter)
z=num
n=1
t=1
whilenumandt<max_iterandabs(n/d[t]num)>epsilon:
t+=1
z=1/(zint(z))
d[t]=d[t1]*int(z)+d[t2]
#int(x+0.5)isequivalenttoroundingx.
n=int(num*d[t]+0.5)
returnn,d[t]

Edit:Ijustnoticedyournoteaboutwantingthemtoworkwithrecurringdecimals.Idon'tknowany
languagesthathavesyntaxtosupportrecurringdecimals,soI'mnotsurehowonewouldgoabout
handlingthem,butrunning0.6666666and0.166666throughthismethodreturnthecorrectresults(2/3
and1/6,respectively).
AnotherEdit(Ididn'tthinkthiswouldbesointeresting!):Ifyouwanttoknowmoreaboutthetheory
behindthisalgorithm,WikipediahasanexcellentpageontheEuclidianalgorithm
share improvethisanswer

editedFeb26'11at3:29

answeredFeb26'11at3:24

HaldeanBrown
5,122

20

40

2 Youdon'tneedanarray,btwIpostedananswersomewhereonSOonceexpressingthesamealgorithmas
aPythongenerator(whichavoidstheneedforepsilonandmax_iterinthecorelogicaswell).
DariusBaconFeb26'11at20:31
Ah,here:stackoverflow.com/questions/445113/DariusBaconFeb26'11at20:48
Yeah,initiallyIjustdidwithwithd0andd1,butwaslessreadablesoIwentwiththelistinstead.Also,
max_iterandepsilonjustgetmovedelsewhereifyoutakethemout,andIthinkitwouldbemoreconvenient

foranAPIusertodothewholethinginasinglefunctioncall,ratherthanrequirethecallertodotheiteration
themselves.HaldeanBrownMar1'11at4:50
addacomment

Iimplementedbtilly'sanswerinC#and...

addedsupportfornegativenumbers
changed error tobethemax.relativeerror,notthemax.absoluteerror
Double.NaN and Double.Infinity arenotsupportedyoumightwanttohandlethosetoo

(example).
publicstaticFractionRealToFraction(doublevalue,doubleerror)
{
if(error<=0.0||error>=1.0)
{
thrownewArgumentOutOfRangeException("error","Mustbebetween0and1(exclusive)."
}
intsign=Math.Sign(value);
if(sign==1)
{
value=Math.Abs(value);
}
if(sign!=0)
{
//erroristhemaximumrelativeerror;converttoabsolute
error*=value;
}
intn=(int)Math.Floor(value);
value=n;
if(value<error)
{
returnnewFraction(sign*n,1);
}
if(1error<value)
{
returnnewFraction(sign*(n+1),1);
}
//Thelowerfractionis0/1
intlower_n=0;
intlower_d=1;

The Fraction typeisjustasimplestruct.Ofcourse,useyourownpreferredtype...(Ilikethisoneby


RickDavin.)
publicstructFraction
{
publicFraction(intn,intd)
{
N=n;
D=d;
}
publicintN{get;privateset;}
publicintD{get;privateset;}
}

Itested RealToFraction() withthefollowingresults:

//error=0.001
0>0/1(zero)0.00(0iterations)
0.1>1/100.00%(9iterations)
0.2>1/50.00%(4iterations)
0.3>3/100.00%(5iterations)
0.4>2/50.00%(3iterations)
0.5>1/20.00%(1iterations)
0.6>3/50.00%(3iterations)
0.7>7/100.00%(5iterations)
0.8>4/50.00%(4iterations)
0.9>9/100.00%(9iterations)
0.01>1/1000.00%(99iterations)
0.001>1/10000.00%(999iterations)
0.0001>1/99910.09%(9990iterations)
0.00001>1/999010.10%(99900iterations)
0.33333333333>1/30.00%(2iterations)
0.3>3/100.00%(5iterations)
0.33>30/910.10%(32iterations)
0.333>167/5020.10%(169iterations)
0.7777>7/90.01%(5iterations)
0.101>10/990.01%(18iterations)
0.10001>1/100.01%(9iterations)
0.100000001>1/100.00%(9iterations)
0.001001>1/9990.00%(998iterations)
0.0010000001>1/10000.00%(999iterations)
0.11>10/910.10%(18iterations)
0.1111>1/90.01%(8iterations)
0.111111111111>1/90.00%(8iterations)
1>1/10.00%(0iterations)
1>1/10.00%(0iterations)
0.5>1/20.00%(1iterations)
3.14>22/70.09%(6iterations)
3.1416>22/70.04%(6iterations)
3.14159265358979>22/70.04%(6iterations)
0.14>7/500.00%(13iterations)
0.1416>15/1060.06%(21iterations)
0.141592653589793>15/1060.06%(21iterations)

Asyoucansee,valuesnear 1en ( 0.1 , 0.01 , 0.001 ,etc.)alwaysresultinextremenumbersof


iterations.Somerandomlyenterednumberslikethe 0.01024801004 too(88iterationseven
while error=0.1 ,i.e.notrequiringahighprecision).Stoppingatacertainmaximumiteration
numberdoesnotsolvethis:theerror%wouldbehigh.Ithinkifyouencounterthisoftenintimecritical
codeyoucouldaddcachingwithadictionary.Well,onlyiftheseexactsamevaluesreturnoften,of
course.
Anothersolutionwouldbeto,assoonasthenumberofiterationsreachesacertainamount,like10or
20,abortandcallanotheralgorithm.Actuallythealgorithminmyotheranswerisalotfaster.
Bytheway,ifyourfractionscangetlarge,changethe int sto long .
share improvethisanswer

editedJan6at8:15

answeredOct2'15at8:57

KayZed
486

20

Thereasonwhythenumberofiterationsgetslargeisbecausetogetto1/100youaretrying1/2,1/3,1/4,...
Insteadonceyoustartgoingdownonesideofthetreeyoucandoabinarysearchthroughnotchangingthat
side.Thiswillgiveyou1/2,1/4,1/8,1/16,1/32,1/64,1/128,1/96,1/112,1/104,1/100.MUCHbetter.Ididn't
implementthattrickinmyanswerbecauseIwastryingtoexplain,notoptimize.btillyJan6at18:48
@btillyIknowyouansweredthisquestionalongtimeagobutIwouldliketoknowIyoucanpointwhereI
canfindinformationofthisoptimization.Idon'tunderstandwhatyoumeanandIcan'tfindinformation.Maybe
ifyoucouldupdateyouranswerwithalinkoramoredetaileddescriptionPinkFloydJun1at13:50
addacomment

Here'saC#versionofWillBrown'spythonexample.I'vealsochangedittohandleseparatewhole
numbers(e.g."21/8"insteadof"17/8").

publicstaticstringDoubleToFraction(doublenum,doubleepsilon=0.0001,intmaxIterations
{
double[]d=newdouble[maxIterations+2];
d[1]=1;
doublez=num;
doublen=1;
intt=1;
intwholeNumberPart=(int)num;
doubledecimalNumberPart=numConvert.ToDouble(wholeNumberPart);
while(t<maxIterations&&Math.Abs(n/d[t]num)>epsilon)
{
t++;
z=1/(z(int)z);
d[t]=d[t1]*(int)z+d[t2];
n=(int)(decimalNumberPart*d[t]+0.5);
}
returnstring.Format((wholeNumberPart>0?wholeNumberPart.ToString()+"":"")+
n.ToString(),
d[t].ToString()
);
}

share improvethisanswer

answeredJun10'13at6:46

JeremyHerrman
335

14

addacomment

Youcan'trepresentarecurringdecimalin.netsoI'llignorethatpartofyourquestion.

Youcanonlyrepresentafiniteandrelativelysmallnumberofdigits.
There'sanextremelysimplealgorithm:
takedecimal x
countthenumberofdigitsafterthedecimalpointcallthis n
createafraction (10^n*x)/10^n
removecommonfactorsfromthenumeratoranddenominator.
soifyouhave0.44,youwouldcount2placesarethedecimalpointn=2,andthenwrite
(0.44*10^2)/10^2

= 44/100
factorising(removingcommonfactorof4)gives 11/25
share improvethisanswer

answeredFeb26'11at3:10

KirkBroadhurst
15.8k

48

101

nice,butyoucandetectifadecimalisrecurringin.netright?Ihavealreadytriedsomethinglikethisandthis
isnotwhatIwant.Also,doyouknowthebestwaytofindandremovethecommonfactors?
ChibuezeOpata Feb26'11at3:17
It'sirrelevantwhetheryoucandetectifadecimalisrecurring,becauseyoucannothaverecurringdecimals.
Itissimplynotpossiblefora decimal typetoberecurring.KirkBroadhurstFeb26'11at3:41
hmm.seemsIwillbeneedingmoremasstuts:owhatexactlyareyoutryingtotellme??
ChibuezeOpata Feb26'11at4:07
2 You'reusing.net,inwhichthedecimaltypecanhavelessthan30digits.Itcannothaveinfinitedigits.Ithas
nowaytorepresent'recurring'patterns.Youcanhave0.333333333333333333butyoucannothave0.3*
(recurring)andtheyarenotthesamething.0.3*is1/3,buttheformeris33333333(etc)/1000000slightly
lessthan1/3.KirkBroadhurstFeb26'11at4:57
2 Themachinecanonlyknowwhatyoutellitsoifyouwanttodefinesomerulesto'round'clumsy20digit
fractiontoanicefractionyoucould:iftherearemorethan10digits,andthere'sa1or2digitfractionthatis
within0.1%orsomeothermarginthenrounditoff.Butit'suptoyoutodeterminethoserules.Thefact
remainsthat0.33333333333333333333isnotthesameas1/3.KirkBroadhurstFeb28'11at0:41
show5morecomments

IwroteaquickclassthatrunsfairlyquickandgivestheresultsIwouldexpect.Youcanchooseyour
Precisionaswell.ItismuchsimplerfromanycodeIseenandrunsquickaswell.

//WrittenByBrianDobony
publicstaticclassFraction
{
publicstaticstringConvertDecimal(DoubleNumberToConvert,intDenominatorPercision=
{
intWholeNumber=(int)NumberToConvert;
doubleDecimalValue=NumberToConvertWholeNumber;
doubledifference=1;
intnumerator=1;
intdenominator=1;
//findclosestvaluethatmatchespercision
//AutomaticallyfindsFractioninsimplifiedform
for(inty=2;y<DenominatorPercision+1;y++)
{
for(intx=1;x<y;x++)
{
doubletempdif=Math.Abs(DecimalValue(double)x/(double)y);
if(tempdif<difference)
{
numerator=x;
denominator=y;
difference=tempdif;
//ifexactmatchisfoundreturnit
if(difference==0)
{
returnFractionBuilder(WholeNumber,numerator,denominator);
}
}
}
}
returnFractionBuilder(WholeNumber,numerator,denominator);
}
privatestaticstringFractionBuilder(intWholeNumber,intNumerator,intDenominator)
{
share improvethisanswer

answeredMay21'15at21:41

BrianDobony
31

Itriedtheprogram,itisgoodfor'seamingly'repeatingdecimals,butitdidnotworkasIexpectedforsome
fractions,forexample:whenIusedthevalue:0.068376968,with32precision,theresultwas2/29
=.068965517,whichisgoodforonly4digitsbehindthedecimal.However,itisOKforme.NoChanceApr
11at19:36
addacomment

ThisalgorithmbyDavidEppstein,UCIrvine,basedonthetheoryofcontinuedfractionsandoriginally
inC,wastranslatedtoC#byme.Thefractionsitgeneratessatisfytheerrormarginbutmostlydonot
lookasgoodasthesolutioninmyotheranswer.E.g. 0.5 becomes 999/1999 while 1/2 wouldbe
preferredwhendisplayedtoauser(ifyouneedthat,seemyotheranswer).
Itisdefinitelyfastthough.
Thereisanoverloadtospecifytheerrormarginasadouble(relativetothevalue,nottheabsolute
error).Forthe Fraction type,seemyotheranswer.
Bytheway,ifyourfractionscangetlarge,changethe int sto long .

publicstaticFractionRealToFraction(doublevalue,intmaxDenominator)
{
//http://www.ics.uci.edu/~eppstein/numth/frap.c
//Findrationalapproximationtogivenrealnumber
//DavidEppstein/UCIrvine/8Aug1993
//WithcorrectionsfromArnoFormella,May2008
if(value==0.0)
{
returnnewFraction(0,1);
}
intsign=Math.Sign(value);
if(sign==1)
{
value=Math.Abs(value);
}
int[,]m={{1,0},{0,1}};
intai=(int)value;
//Findtermsuntildenominatorgetstoobig
while(m[1,0]*ai+m[1,1]<=maxDenominator)
{
intt=m[0,0]*ai+m[0,1];
m[0,1]=m[0,0];
m[0,0]=t;
t=m[1,0]*ai+m[1,1];
m[1,1]=m[1,0];
m[1,0]=t;
value=1.0/(valueai);
//0x7FFFFFFF=Assumes32bitfloatingpointjustlikeintheCimplementation.
//ThischeckincludesDouble.IsInfinity().EventhoughC#doubleis64bits,
//thealgorithmsometimesfailswhentryingtoincreasethisvaluetoomuch.So

Testresults:
//error=0.001
0>0/1(zero)0(0iterations)
0.1>999/99910.01%(2iterations)
0.2>999/49960.02%(2iterations)
0.3>998/33270.01%(4iterations)
0.4>999/24970.02%(3iterations)
0.5>999/19990.05%(2iterations)
0.6>1000/16670.02%(4iterations)
0.7>996/14230.01%(4iterations)
0.8>997/12460.02%(3iterations)
0.9>998/11090.01%(4iterations)
0.01>999/999010.00%(2iterations)
0.001>999/9990010.00%(2iterations)
0.0001>999/99900010.00%(2iterations)
0.00001>1000/999999990.00%(3iterations)
0.33333333333>1000/30010.03%(2iterations)
0.3>998/33270.01%(4iterations)
0.33>991/30030.00%(3iterations)
0.333>1000/30030.00%(3iterations)
0.7777>997/12820.00%(4iterations)
0.101>919/90990.00%(5iterations)
0.10001>1/100.01%(4iterations)
0.100000001>1000/99990.01%(3iterations)
0.001001>1/9990.00%(3iterations)
0.0010000001>1000/9999990.00%(3iterations)
0.11>1000/90910.00%(4iterations)
0.1111>1000/90010.00%(2iterations)
0.111111111111>1000/90010.01%(2iterations)
1>1001/10000.10%(1iterations)
1>1001/10000.10%(1iterations)
0.5>999/19990.05%(2iterations)
3.14>964/3070.00%(3iterations)
3.1416>732/2330.00%(3iterations)
3.14159265358979>688/2190.00%(4iterations)
0.14>995/71070.00%(3iterations)
0.1416>869/61370.00%(5iterations)
0.141592653589793>991/69990.00%(4iterations)
share improvethisanswer

editedJan6at7:54

answeredOct2'15at11:16

KayZed
486

20

addacomment

Arecurringdecimalcanberepresentedbytwofinitedecimals:theleftwardpartbeforetherepeat,and
therepeatingpart.E.g. 1.6181818...=1.6+0.1*(0.18...) .Thinkofthisas a+b*sum(c*
10**(d*k)forkinrange(1,infinity)) (inPythonnotationhere).Inmy
example, a=1.6 , b=0.1 , c=18 , d=2 (thenumberofdigitsin c ).Theinfinitesumcanbesimplified
( sum(r**kforrinrange(1,infinity))==r/(1r) ifIrecallrightly),yielding a+b*(c*
10**d)/(1c*10**d)) ,afiniteratio.Thatis,startwith a , b , c ,and d asrationalnumbers,
andyouendupwithanother.

(ThiselaboratesKirkBroadhurst'sanswer,whichisrightasfarasitgoes,butdoesn'tcoverrepeating
decimals.Idon'tpromiseImadenomistakesabove,thoughI'mconfidentthegeneralapproach
works.)
share improvethisanswer

editedFeb26'11at21:37

answeredFeb26'11at21:19

DariusBacon
11.3k

36

48

addacomment

IrecentlyhadtoperformthisverytaskofworkingwithaDecimalDataTypewhichisstoredinour
SQLServerdatabase.AtthePresentationLayerthisvaluewaseditedasafractionalvalueina
TextBox.ThecomplexityherewasworkingwiththeDecimalDataTypewhichholdssomeprettylarge
valuesincomparisontointorlong.Sotoreducetheopportunityfordataoverrun,Istuckwiththe
DecimalDataTypethroughouttheconversion.
BeforeIbegin,IwanttocommentonKirk'spreviousanswer.Heisabsolutelycorrectaslongasthere
arenoassumptionsmade.However,ifthedeveloperonlylooksforrepeatingpatternswithinthe
confinesoftheDecimalDataType.3333333...canberepresentedas1/3.Anexampleofthe
algorithmcanbefoundatbasicmathematics.com.Again,thismeansyouhavetomakeassumptions
basedontheinformationavailableandusingthismethodonlycapturesaverysmallsubsetof
repeatingdecimals.Howeverforsmallnumbersshouldbeokay.
Movingforward,letmegiveyouasnapshotofmysolution.Ifyouwanttoreadacompleteexample
withadditionalcodeIcreatedablogpostwithmuchmoredetail.
ConvertDecimalDataTypetoaStringFraction
publicstaticvoidDecimalToFraction(decimalvalue,refdecimalsign,refdecimalnumerator,
{
constdecimalmaxValue=decimal.MaxValue/10.0M;
//e.g..25/1=(.25*100)/(1*100)=25/100=1/4
vartmpSign=value<decimal.Zero?1:1;
vartmpNumerator=Math.Abs(value);
vartmpDenominator=decimal.One;
//Whilenumeratorhasadecimalvalue
while((tmpNumeratorMath.Truncate(tmpNumerator))>0&&
tmpNumerator<maxValue&&tmpDenominator<maxValue)
{
tmpNumerator=tmpNumerator*10;
tmpDenominator=tmpDenominator*10;
}
tmpNumerator=Math.Truncate(tmpNumerator);//JustincasemaxValueboundarywasreached.
ReduceFraction(reftmpNumerator,reftmpDenominator);
sign=tmpSign;
numerator=tmpNumerator;
denominator=tmpDenominator;
}
publicstaticstringDecimalToFraction(decimalvalue)
{
varsign=decimal.One;
varnumerator=decimal.One;
vardenominator=decimal.One;
DecimalToFraction(value,refsign,refnumerator,refdenominator);
returnstring.Format("{0}/{1}",(sign*numerator).ToString().TruncateDecimal(),
denominator.ToString().TruncateDecimal());
}

ThisisprettystraightforwardwheretheDecimalToFraction(decimalvalue)isnothingmorethana
simplifiedentrypointforthefirstmethodwhichprovidesaccesstoallthecomponentswhichcompose
afraction.Ifyouhaveadecimalof.325thendivideitby10tothepowerofnumberofdecimalplaces.
Lastlyreducethefraction.And,inthisexample.325=325/10^3=325/1000=13/40.
Next,goingtheotherdirection.
ConvertStringFractiontoDecimalDataType
staticreadonlyRegexFractionalExpression=newRegex(@"^(?<sign>[])?(?<numerator>\d+)(/(?<denominator>\d+))?$"
publicstaticdecimal?FractionToDecimal(stringfraction)
{
varmatch=FractionalExpression.Match(fraction);
if(match.Success)
{
//varsign=Int32.Parse(match.Groups["sign"].Value+"1");
varnumerator=Int32.Parse(match.Groups["sign"].Value+match.Groups["numerator"].Value
intdenominator;
if(Int32.TryParse(match.Groups["denominator"].Value,outdenominator))
returndenominator==0?(decimal?)null:(decimal)numerator/denominator;
if(numerator==0||numerator==1)
returnnumerator;
}
returnnull;
}

Convertingbacktoadecimalisquitesimpleaswell.Hereweparseoutthefractionalcomponents,
storetheminsomethingwecanworkwith(heredecimalvalues)andperformourdivision.
share improvethisanswer

editedMar1'12at20:01

answeredMar1'12at19:49

JeffWillener
629

addacomment

My2cents.Here'sVB.NETversionofbtilly'sexcellentalgorithm:

PublicSharedSubfloat_to_fraction(xAsDecimal,ByRefNumeratorAsLong,ByRefDenomAs
DimnAsLong=Int(Math.Floor(x))
x=n
Ifx<ErrMarginThen
Numerator=n
Denom=1
Return
ElseIfx>=1ErrMarginThen
Numerator=n+1
Denom=1
Return
EndIf
'Thelowerfractionis0/1
Dimlower_nAsInteger=0
Dimlower_dAsInteger=1
'Theupperfractionis1/1
Dimupper_nAsInteger=1
Dimupper_dAsInteger=1
Dimmiddle_n,middle_dAsDecimal
WhileTrue
'Themiddlefractionis(lower_n+upper_n)/(lower_d+upper_d)
middle_n=lower_n+upper_n
middle_d=lower_d+upper_d
'Ifx+error<middle
Ifmiddle_d*(x+ErrMargin)<middle_nThen
'middleisournewupper
upper_n=middle_n
upper_d=middle_d
'ElseIfmiddle<xerror
ElseIfmiddle_n<(xErrMargin)*middle_dThen
'middleisournewlower
lower_n=middle_n
lower_d=middle_d
'Elsemiddleisourbestfraction
share improvethisanswer

answeredDec6'12at15:32

dotNET
10.6k

41

84

addacomment

Well,seemsIfinallyhadtodoitmyself.IjusthadtocreateaprogramsimulatingthenaturalwayI
wouldsolveitmyself.Ijustsubmittedthecodetocodeprojectaswritingoutthewholecodeherewon't
besuitable.YoucandownloadtheprojectfromhereFraction_Conversion,orlookatthecodeproject
pagehere.
Here'showitworks:
1.Findoutwhethergivendecimalisnegative
2.Convertdecimaltoabsolutevalue
3.Getintegerpartofgivendecimal
4.Getthedecimalpart
5.Checkwhetherdecimalisrecurring.Ifdecimalisrecurring,wethenreturntheexactrecurring
decimal
6.Ifdecimalisnotrecurring,startreductionbychangingnumeratorto10^no.ofdecimal,elsewe
subtract1fromnumerator
7.Thenreducefraction
CodePreview:

privatestaticstringdec2frac(doubledbl)
{
charneg='';
doubledblDecimal=dbl;
if(dblDecimal==(int)dblDecimal)returndblDecimal.ToString();//returnnoifit'snotadecimal
if(dblDecimal<0)
{
dblDecimal=Math.Abs(dblDecimal);
neg='';
}
varwhole=(int)Math.Truncate(dblDecimal);
stringdecpart=dblDecimal.ToString().Replace(Math.Truncate(dblDecimal)+".","");
doublerN=Convert.ToDouble(decpart);
doublerD=Math.Pow(10,decpart.Length);
stringrd=recur(decpart);
intrel=Convert.ToInt32(rd);
if(rel!=0)
{
rN=rel;
rD=(int)Math.Pow(10,rd.Length)1;
}
//justafewprimefactorsfortestingpurposes
varprimes=new[]{41,43,37,31,29,23,19,17,13,11,7,5,3,2};
foreach(intiinprimes)reduceNo(i,refrD,refrN);
rN=rN+(whole*rD);
returnstring.Format("{0}{1}/{2}",neg,rN,rD);
}

Thanks@Dariusforgivenmeanideaofhowtosolvetherecurringdecimals:)
share improvethisanswer

editedJul16'15at22:41

Mike
1,278

answeredMar6'11at12:18

ChibuezeOpata
9

26

5,091

23

48

Whatwillyoudowithfractionsthathaverecurringdecimalsthatdonotrecurwithinaperiodthatfitsin
floatingpoint?Thathappensevenwithfairlymodestfractions.btillyJun13'13at19:42
@btilly:Thiswasalongtimeago,andwasjustafairlysimpleapproachtotheissueaswellasthebest
acceptablesolutionthen.AbettersolutionwouldbetousetheBigIntegerclass.ItworkedwithallfractionsI
testedwiththough,maybeyoucouldtryitoutyourselfwithsuchfractionsasyousuggest.
ChibuezeOpata Jun13'13at20:32
Idisagreeabout"bestacceptablesolution"whenmysolutionwaspostedbeforeyours,isshorter,was
upvotedmore,handlesfractionsthatyoursdoesnot,andprovablycomesupwiththebestpossiblefractionin
allcaseswhileyoursdoesnot.I'mnotsurewhatdefinitionof"best"you'reusing.btillyJun13'13at22:02
Ididappreciateyoursolution,butitwasnotinC#,neitherwasanyother.IfJeremy'ssolutionwasavailable
then,Iwouldhaveacceptedit. ChibuezeOpata Jun13'13at22:23
addacomment

Icomeupwithaverylateanswer.ThecodeistakenfromanarticlefromRichardspublishedin
1981andwrittenin c .

inlineunsignedintrichards_solution(doubleconst&x0,unsignedlonglong&num,unsignedlong
sign=my::sign(x0);
doubleg(std::abs(x0));
unsignedlonglonga(0);
unsignedlonglongb(1);
unsignedlonglongc(1);
unsignedlonglongd(0);
unsignedlonglongs;
unsignedintiter(0);
do{
s=std::floor(g);
num=a+s*c;
den=b+s*d;
a=c;
b=d;
c=num;
d=den;
g=1.0/(gs);
if(err>std::abs(sign*num/denx0)){returniter;}
}while(iter++<1e6);
std::cerr<<__PRETTY_FUNCTION__<<":failedtofindafractionfor"<<x0<<std::endl;
return0;
}

Irewriteheremyimplementationofbtilly_solution:

inlineunsignedintbtilly_solution(doublex,unsignedlonglong&num,unsignedlonglong&den
sign=my::sign(x);
num=std::floor(std::abs(x));
x=std::abs(x)num;
unsignedlonglonglower_n(0);
unsignedlonglonglower_d(1);
unsignedlonglongupper_n(1);
unsignedlonglongupper_d(1);
unsignedlonglongmiddle_n;
unsignedlonglongmiddle_d;
unsignedintiter(0);
do{
middle_n=lower_n+upper_n;
middle_d=lower_d+upper_d;
if(middle_d*(x+err)<middle_n){
upper_n=middle_n;
upper_d=middle_d;
}elseif(middle_d*(xerr)>middle_n){
lower_n=middle_n;
lower_d=middle_d;
}else{
num=num*middle_d+middle_n;
den=middle_d;
returniter;
}
}while(iter++<1e6);
den=1;
std::cerr<<__PRETTY_FUNCTION__<<":failedtofindafractionfor"<<x+num<<std::endl;
return0;
}

AndhereIproposesometestswithanerrorof 1e10 :
|
btilly0.1666670.166667=1/6in5iterations|1/6
richard0.1666670.166667=1/6in1iterations|
|
btilly0.3333330.333333=1/3in2iterations|1/3
richard0.3333330.333333=1/3in1iterations|
|
btilly0.1428570.142857=1/7in6iterations|1/7
richard0.1428570.142857=1/7in1iterations|
|
btilly0.7142860.714286=5/7in4iterations|5/7
richard0.7142860.714286=5/7in4iterations|
|
btilly1e071.001e07=1/9990010in9990009iteration|0.0000001
richard1e071e07=1/10000000in1iterations|
|
btilly3.666673.66667=11/3in2iterations|11/3
richard3.666673.66667=11/3in3iterations|
|
btilly1.414211.41421=114243/80782in25iterations|sqrt(2)
richard1.414211.41421=114243/80782in13iterations|
|
btilly3.141593.14159=312689/99532in317iterations|pi
richard3.141593.14159=312689/99532in7iterations|
|
btilly2.718282.71828=419314/154257in36iterations|e
richard2.718282.71828=517656/190435in14iterations|
|
btilly0.3908850.390885=38236/97819in60iterations|random
richard0.3908850.390885=38236/97819in13iterations|

Asyoucansee,thetwomethodsgivemoreorlessthesameresultsbuttherichards'oneisway
moreefficientandeasiertoimplement.

Edit
Tocompilemycodeyouneedadifinitionfor my::sign whichissimplyafunctionthatreturnsthesign
ofavariable.Hereismyimplementation
namespacemy{
template<typenameType>inlineconstexpr
intsign_unsigned(Typex){returnType(0)<x;}
template<typenameType>inlineconstexpr
intsign_signed(Typex){return(Type(0)<x)(x<Type(0));}
template<typenameType>inlineconstexpr
intsign(Typex){returnstd::is_signed<Type>()?sign_signed(x):sign_unsigned(x);}
}

Sorry
Iguessthisanswerreferstothesamealgorithm.Ididn'tseethatbefore...
share improvethisanswer

editedJun1at16:06

answeredJun1at15:57

PinkFloyd
537

addacomment

17

addacomment

Here'sanalgorithmimplementedinVBthatconvertsFloatingPointDecimaltoIntegerFractionthatI
wrotemanyyearsago.

Basicallyyoustartwithanumerator=0andadenominator=1,thenifthequotientislessthanthe
decimalinput,add1tothenumeratorandifthequotientisgreaterthanthedecimalinput,add1tothe
denominator.Repeatuntilyougetwithinyourdesiredprecision.
share improvethisanswer

answeredFeb26'11at10:20

oosterwal
1,238

16

addacomment

IfIwereyouI'dhandlethe"norepeatingdecimalsin.NET"problembyhavingitconvertstringswith
therecurrencemarkedsomehow.

E.g.1/3couldberepresented"0.R3"1/60couldberepresented"0.01R6"
I'drequireanexplicitcastfromdoubleordecimalbecausesuchvaluescouldonlybeconvertedintoa
fractionthatwasclose.Implicitcastfromintisok.
Youcoulduseastructandstoreyourfraction(f)intwolongspandqsuchthatf=p/q,q!=0,and
gcd(p,q)==1.
share improvethisanswer

answeredJun24'13at16:29

ChrisSusie
19

addacomment

Here,youcanhavethemethodforconvertingDecimalintoFractions:

///<summary>
///ConvertsDecimalsintoFractions.
///</summary>
///<paramname="value">Decimalvalue</param>
///<returns>Fractioninstringtype</returns>
publicstringDecimalToFraction(doublevalue)
{
stringresult;
doublenumerator,realValue=value;
intnum,den,decimals,length;
num=(int)value;
value=valuenum;
value=Math.Round(value,5);
length=value.ToString().Length;
decimals=length2;
numerator=value;
for(inti=0;i<decimals;i++)
{
if(realValue<1)
{
numerator=numerator*10;
}
else
{
realValue=realValue*10;
numerator=realValue;
}
}
den=length2;
stringten="1";
for(inti=0;i<den;i++)
{
ten=ten+"0";
}
den=int.Parse(ten);
num=(int)numerator;
result=SimplifiedFractions(num,den);
returnresult;
share improvethisanswer

answeredJan21at14:21

SyedFaizanAli
11