Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
831 views

C# - Algorithm For Simplifying Decimal To Fractions - Stack Overflow

The document discusses writing an algorithm to convert a decimal number to a fraction. It begins by explaining that the asker tried writing their own algorithm but found existing online solutions were too complex or did not work for recurring decimals. Responses from other users provide algorithms and code examples for converting decimals to fractions in languages like Python, C#, and Pascal. The algorithms use techniques like continued fractions and walking the Stern-Brocot tree to find the closest fraction approximation within a given error tolerance.

Uploaded by

sonystd
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
831 views

C# - Algorithm For Simplifying Decimal To Fractions - Stack Overflow

The document discusses writing an algorithm to convert a decimal number to a fraction. It begins by explaining that the asker tried writing their own algorithm but found existing online solutions were too complex or did not work for recurring decimals. Responses from other users provide algorithms and code examples for converting decimals to fractions in languages like Python, C#, and Pascal. The algorithms use techniques like continued fractions and walking the Stern-Brocot tree to find the closest fraction approximation within a given error tolerance.

Uploaded by

sonystd
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 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

You might also like