Movatterモバイル変換


[0]ホーム

URL:


Jump to content
Rosetta Code
Search

Convert decimal number to rational

From Rosetta Code
Task
Convert decimal number to rational
You are encouraged tosolve this task according to the task description, using any language you may know.
This task has been flagged forclarification. Code on this page in its current state may be flagged incorrect once this task has been clarified. See this page'sTalk page for discussion.


The task is to write a program to transform a decimal number into a fraction in lowest terms.

It is not always possible to do this exactly. For instance, while rational numbers can be converted to decimal representation, some of them need an infinite number of digits to be represented exactly in decimal form. Namely,repeating decimals such as 1/3 = 0.333...

Because of this, the following fractions cannot be obtained (reliably) unless the language has some way of representing repeating decimals:

  • 67 / 74 = 0.9(054) = 0.9054054...
  • 14 / 27 = 0.(518) = 0.518518...


Acceptable output:

  • 0.9054054 → 4527027 / 5000000
  • 0.518518 → 259259 / 500000


Finite decimals are of course no problem:

  • 0.75 → 3 / 4



11l

Translation of:Nim
T Rational((Int numerator, Int denominator))   F String()      I .denominator == 1         R String(.numerator)      E         R .numerator‘//’(.denominator)F rationalize(x, tol = 1e-12)   V xx = x   V flagNeg = xx < 0.0   I flagNeg      xx = -xx   I xx < 1e-10      R Rational(0, 1)   I abs(xx - round(xx)) < tol      R Rational(Int(xx), 1)   V a = 0   V b = 1   V c = Int(ceil(xx))   V d = 1   V aux1 = 7FFF'FFFF I/ 2   L c < aux1 & d < aux1      V aux2 = (Float(a) + Float(c)) / (Float(b) + Float(d))      I abs(xx - aux2) < tol         L.break      I xx > aux2         a += c         b += d      E         c += a         d += b   V g = gcd(a + c, b + d)   I flagNeg      R Rational(-(a + c) I/ g, (b + d) I/ g)   E      R Rational((a + c) I/ g, (b + d) I/ g)print(rationalize(0.9054054054))print(rationalize(0.9054054054, 0.0001))print(rationalize(0.5185185185))print(rationalize(0.5185185185, 0.0001))print(rationalize(0.75))print(rationalize(0.1428571428, 0.001))print(rationalize(35.000))print(rationalize(35.001))print(rationalize(0.9))print(rationalize(0.99))print(rationalize(0.909))print(rationalize(0.909, 0.001))
Output:
1910136854//210970339167//74983902907//189752703514//273//41//73535001//10009//1099//100909//100010//11

Ada

Specification of a procedure Real_To_Rational, which is searching for the best approximation of a real number. The procedure is generic. I.e., you can instantiate it by your favorite "Real" type (Float, Long_Float, ...).

generictypeRealisdigits<>;procedureReal_To_Rational(R:Real;Bound:Positive;Nominator:outInteger;Denominator:outPositive);

The implementation (just brute-force search for the best approximation with Denominator less or equal Bound):

procedureReal_To_Rational(R:Real;Bound:Positive;Nominator:outInteger;Denominator:outPositive)isError:Real;Best:Positive:=1;Best_Error:Real:=Real'Last;beginifR=0.0thenNominator:=0;Denominator:=1;return;elsifR<0.0thenReal_To_Rational(-R,Bound,Nominator,Denominator);Nominator:=-Nominator;return;elseforIin1..BoundloopError:=abs(Real(I)*R-Real'Rounding(Real(I)*R));ifError<Best_ErrorthenBest:=I;Best_Error:=Error;endif;endloop;endif;Denominator:=Best;Nominator:=Integer(Real'Rounding(Real(Denominator)*R));endReal_To_Rational;

The main program, called "Convert_Decimal_To_Rational", reads reals from the standard input until 0.0. It outputs progressively better rational approximations of the reals, where "progressively better" means a larger Bound for the Denominator:

withAda.Text_IO;WithReal_To_Rational;procedureConvert_Decimal_To_RationalistypeMy_RealisnewLong_Float;-- change this for another "Real" typepackageFIOis newAda.Text_IO.Float_IO(My_Real);procedureR2RisnewReal_To_Rational(My_Real);Nom,Denom:Integer;R:My_Real;beginloopAda.Text_IO.New_Line;FIO.Get(R);FIO.Put(R,Fore=>2,Aft=>9,Exp=>0);exitwhenR=0.0;forIin0..4loopR2R(R,10**I,Nom,Denom);Ada.Text_IO.Put("  "&Integer'Image(Nom)&" /"&Integer'Image(Denom));endloop;endloop;endConvert_Decimal_To_Rational;

Finally, the output (reading the input from a file):

> ./convert_decimal_to_rational < input.txt 0.750000000   1 / 1   3 / 4   3 / 4   3 / 4   3 / 4 0.518518000   1 / 1   1 / 2   14 / 27   14 / 27   14 / 27 0.905405400   1 / 1   9 / 10   67 / 74   67 / 74   67 / 74 0.142857143   0 / 1   1 / 7   1 / 7   1 / 7   1 / 7 3.141592654   3 / 1   22 / 7   22 / 7   355 / 113   355 / 113 2.718281828   3 / 1   19 / 7   193 / 71   1457 / 536   25946 / 9545-0.423310825   0 / 1  -3 / 7  -11 / 26  -69 / 163  -1253 / 296031.415926536   31 / 1   157 / 5   377 / 12   3550 / 113   208696 / 6643 0.000000000

AppleScript

--------- RATIONAL APPROXIMATION TO DECIMAL NUMBER --------- approxRatio :: Real -> Real -> RatioonapproxRatio(epsilon,n)if{real,integer}contains(classofepsilon)and0<epsilonthen-- Givensetetoepsilonelse-- Defaultseteto1/10000endifscriptgcdeon|λ|(e,x,y)script_gcdon|λ|(a,b)ifb<ethenaelse|λ|(b,amodb)endifend|λ|endscript|λ|(abs(x),abs(y))of_gcdend|λ|endscriptsetcto|λ|(e,1,n)ofgcdeRatio((ndivc),(1divc))endapproxRatio-- Ratio :: Int -> Int -> RatioonRatio(n,d){type:"Ratio",n:n,d:d}endRatio-- showRatio :: Ratio -> StringonshowRatio(r)(nofrasstring)&"/"&(dofrasstring)endshowRatio--------------------------- TEST -------------------------onrunscriptratioString-- Using a tolerance epsilon of 1/10000on|λ|(x)(xasstring)&" -> "&showRatio(approxRatio(1.0E-4,x))end|λ|endscriptunlines(map(ratioString,¬{0.9054054,0.518518,0.75}))-- 0.9054054 -> 67/74-- 0.518518 -> 14/27-- 0.75 -> 3/4endrun-------------------- GENERIC FUNCTIONS --------------------- abs :: Num -> Numonabs(x)if0>xthen-xelsexendifendabs-- Lift 2nd class handler function into 1st class script wrapper-- mReturn :: First-class m => (a -> b) -> m (a -> b)onmReturn(f)ifclassoffisscriptthenfelsescriptproperty|λ|:fendscriptendifendmReturn-- map :: (a -> b) -> [a] -> [b]onmap(f,xs)tellmReturn(f)setlngtolengthofxssetlstto{}repeatwithifrom1tolngsetendoflstto|λ|(itemiofxs,i,xs)endrepeatreturnlstendtellendmap-- unlines :: [String] -> Stringonunlines(xs)-- A single string formed by the intercalation-- of a list of strings with the newline character.set{dlm,mytext item delimiters}to¬{mytext item delimiters,linefeed}setstoxsastextsetmytext item delimiterstodlmsendunlines
Output:
0.9054054 -> 67/740.518518 -> 14/270.75 -> 3/4

AutoHotkey

Array:=[]inputbox,string,EnterNumberstringsplit,string,string,.if(string1=0)string1=loop,parse,string,.ifA_index=2loop,parse,A_loopfieldArray[A_index]:=A_loopfield,k:=A_indexif(k=1){numerator:=Array[1]Denominator:=10gotolabel}Original1:=KTo_rn:=floor(k/2)M_M:=k-To_rnOriginal2:=k-To_rnloop{loop,%To_rn{Check1.=Array[k]Check2.=Array[M_M]k--m_M--}if(check1=check2){            ;~ process beginsTO check;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;loop,%To_rnnines.=9loop,%k-TO_rnZeroes.=0loop%k-TO_rnMinus.=Array[A_index]loop%kPlus.=Array[A_index]if(minus="")minus:=0Numerator:=Plus-minusDenominator:=Nines.Zeroes    ;;;;;;;;;;;;;HCFgoto,label}Check1=check2=k:=Original1m_M:=original2+A_indexTO_rn--if(to_rn=0){zeroes=loop%original1zeroes.=0Denominator:=1.zeroesnumerator:=string2goto,label}}esc::Exitapplabel:Index:=2loop{if(mod(denominator,numerator)=0)HCF:=numeratorif(index=floor(numerator/2))breakif(mod(numerator,index)=0)&&(mod(denominator,index)=0){HCF=%index%index++}elseindex++}if(HCF="")Ans:=numerator"/"DenominatorelseAns:=floor(numerator/HCF)"/"floor(Denominator/HCF)MsgBox%String."  ->  ".String1." ".Ansreload
0.9054054 -> 67/740.518518 -> 14/270.75 -> 3/4

Bracmat

( ( exact  =   integerPart decimalPart z    .     @(!arg:?integerPart "." ?decimalPart)        &   !integerPart          + (   @( !decimalPart                 : (? ((%@:~0) ?:?decimalPart)) [?z                 )              & !decimalPart*10^(-1*!z)            | 0            )      | !arg  )& ( approximation  =     integerPart firstDecimals repeatingDecimals      , x y z z-y x-y numerator denominator    .   @( !arg         :   ?integerPart             "."             [?x             ?firstDecimals             ?repeatingDecimals             [?y             !repeatingDecimals             [?z         )      & !z+-1*!y:?z-y      & !x+-1*!y:?x-y      & 10:?numerator:?denominator      & ( !z-y:0&0:?repeatingDecimals        |   9:?denominator          &   whl            ' ( !z+-1:>!y:?z              & !numerator*10:?numerator              & !denominator*10+9:?denominator              )          & @(!repeatingDecimals:? #?repeatingDecimals)        )      & ( @(!firstDecimals:? #?firstDecimals)        | 0:?firstDecimals        )      &   !integerPart        + !firstDecimals*10^(!x-y+!z-y)        + !numerator*!denominator^-1*!repeatingDecimals*10^!x-y  )&     "0.9054054054"      "0.5185185185"      "0.75"      "0.905405400"      "0.1428571428"      "35.000"      "35.001"      "0.00000000001"      "0.000001000001"      "0.9"      "0.99"      "0.909"      "0.9090"      "0.90909"  : ?decs&   whl  ' ( !decs:%?dec ?decs    & approximation$!dec:?approx    &   out      $ ( !dec          "="          (exact$!dec:?precise)          ( !approx:!precise&          | str$("(approx. " !approx ")")          )        )    ));

Output:

0.9054054054 = 4527027027/5000000000 (approx. 67/74)0.5185185185 = 1037037037/2000000000 (approx. 14/27)0.75 = 3/40.905405400 = 4527027/50000000.1428571428 = 357142857/250000000035.000 = 3535.001 = 35001/10000.00000000001 = 1/1000000000000.000001000001 = 1000001/1000000000000 (approx. 1/999999)0.9 = 9/100.99 = 99/100 (approx. 1)0.909 = 909/10000.9090 = 909/1000 (approx. 10/11)0.90909 = 90909/100000 (approx. 10/11)

C

Since the intention of the task giver is entirely unclear, here's another version of best rational approximation of a floating point number. It's somewhat more rigorous than the Perl version below, but is still not quite complete.

#include<stdio.h>#include<stdlib.h>#include<math.h>#include<stdint.h>/* f : number to convert. * num, denom: returned parts of the rational. * md: max denominator value.  Note that machine floating point number *     has a finite resolution (10e-16 ish for 64 bit double), so specifying *     a "best match with minimal error" is often wrong, because one can *     always just retrieve the significand and return that divided by *     2**52, which is in a sense accurate, but generally not very useful: *     1.0/7.0 would be "2573485501354569/18014398509481984", for example. */voidrat_approx(doublef,int64_tmd,int64_t*num,int64_t*denom){/*  a: continued fraction coefficients. */int64_ta,h[3]={0,1,0},k[3]={1,0,0};int64_tx,d,n=1;inti,neg=0;if(md<=1){*denom=1;*num=(int64_t)f;return;}if(f<0){neg=1;f=-f;}while(f!=floor(f)){n<<=1;f*=2;}d=f;/* continued fraction and check denominator each step */for(i=0;i<64;i++){a=n?d/n:0;if(i&&!a)break;x=d;d=n;n=x%n;x=a;if(k[1]*a+k[0]>=md){x=(md-k[0])/k[1];if(x*2>=a||k[1]>=md)i=65;elsebreak;}h[2]=x*h[1]+h[0];h[0]=h[1];h[1]=h[2];k[2]=x*k[1]+k[0];k[0]=k[1];k[1]=k[2];}*denom=k[1];*num=neg?-h[1]:h[1];}intmain(){inti;int64_td,n;doublef;printf("f = %16.14f\n",f=1.0/7);for(i=1;i<=20000000;i*=16){printf("denom <= %d: ",i);rat_approx(f,i,&n,&d);printf("%lld/%lld\n",n,d);}printf("\nf = %16.14f\n",f=atan2(1,1)*4);for(i=1;i<=20000000;i*=16){printf("denom <= %d: ",i);rat_approx(f,i,&n,&d);printf("%lld/%lld\n",n,d);}return0;}

Output:

f = 0.14285714285714denom <= 1: 0/1denom <= 16: 1/7denom <= 256: 1/7denom <= 4096: 1/7denom <= 65536: 1/7denom <= 1048576: 1/7denom <= 16777216: 1/7f = 3.14159265358979denom <= 1: 3/1denom <= 16: 22/7denom <= 256: 355/113denom <= 4096: 355/113denom <= 65536: 104348/33215denom <= 1048576: 3126535/995207denom <= 16777216: 47627751/15160384

C#

Translation of:C
usingSystem;usingSystem.Text;namespaceRosettaDecimalToFraction{publicclassFraction{publicInt64Numerator;publicInt64Denominator;publicFraction(doublef,Int64MaximumDenominator=4096){/* Translated from the C version. *//*  a: continued fraction coefficients. */Int64a;varh=newInt64[3]{0,1,0};vark=newInt64[3]{1,0,0};Int64x,d,n=1;inti,neg=0;if(MaximumDenominator<=1){Denominator=1;Numerator=(Int64)f;return;}if(f<0){neg=1;f=-f;}while(f!=Math.Floor(f)){n<<=1;f*=2;}d=(Int64)f;/* continued fraction and check denominator each step */for(i=0;i<64;i++){a=(n!=0)?d/n:0;if((i!=0)&&(a==0))break;x=d;d=n;n=x%n;x=a;if(k[1]*a+k[0]>=MaximumDenominator){x=(MaximumDenominator-k[0])/k[1];if(x*2>=a||k[1]>=MaximumDenominator)i=65;elsebreak;}h[2]=x*h[1]+h[0];h[0]=h[1];h[1]=h[2];k[2]=x*k[1]+k[0];k[0]=k[1];k[1]=k[2];}Denominator=k[1];Numerator=neg!=0?-h[1]:h[1];}publicoverridestringToString(){returnstring.Format("{0} / {1}",Numerator,Denominator);}}classProgram{staticvoidMain(string[]args){Console.OutputEncoding=UTF8Encoding.UTF8;foreach(doubledinnewdouble[]{0.9054054,0.518518,0.75,0.4285714,0.833333,0.90909,3.14159265358979,2.7182818284590451}){varf=newFraction(d,d>=2?65536:4096);Console.WriteLine("{0,20} → {1}",d,f);}}}}
Output:
           0.9054054 → 67 / 74            0.518518 → 14 / 27                0.75 → 3 / 4           0.4285714 → 3 / 7            0.833333 → 5 / 6             0.90909 → 10 / 11    3.14159265358979 → 104348 / 33215    2.71828182845905 → 49171 / 18089

C++

#include<cmath>#include<cstdint>#include<iostream>#include<limits>#include<numeric>#include<vector>classRational{public:Rational(constint64_t&numer,constuint64_t&denom):numerator(numer),denominator(denom){}Rationalnegate(){returnRational(-numerator,denominator);}std::stringto_string(){returnstd::to_string(numerator)+" / "+std::to_string(denominator);}private:int64_tnumerator;uint64_tdenominator;};/** * Return a Rational such that its numerator / denominator = 'decimal', correct to dp decimal places, * where dp is minimum of 'decimal_places' and the number of decimal places in 'decimal'. */Rationaldecimal_to_rational(doubledecimal,constuint32_t&decimal_places){constdoubleepsilon=1.0/std::pow(10,decimal_places);constboolnegative=(decimal<0.0);if(negative){decimal=-decimal;}if(decimal<std::numeric_limits<double>::min()){returnRational(0,1);}if(std::abs(decimal-std::round(decimal))<epsilon){returnRational(std::round(decimal),1);}uint64_ta=0;uint64_tb=1;uint64_tc=static_cast<uint64_t>(std::ceil(decimal));uint64_td=1;constuint64_tauxiliary_1=std::numeric_limits<uint64_t>::max()/2;while(c<auxiliary_1&&d<auxiliary_1){constdoubleauxiliary_2=static_cast<double>(a+c)/(b+d);if(std::abs(decimal-auxiliary_2)<epsilon){break;}if(decimal>auxiliary_2){a=a+c;b=b+d;}else{c=a+c;d=b+d;}}constuint64_tdivisor=std::gcd((a+c),(b+d));Rationalresult((a+c)/divisor,(b+d)/divisor);return(negative)?result.negate():result;}intmain(){for(constdouble&decimal:{3.1415926535,0.518518,-0.75,0.518518518518,-0.9054054054054,-0.0,2.0}){std::cout<<decimal_to_rational(decimal,9).to_string()<<std::endl;}}
Output:
104348 / 3321536975 / 71309-3 / 414 / 27-67 / 740 / 12 / 1

Clojure

user=> (rationalize 0.1)1/10user=> (rationalize 0.9054054)4527027/5000000user=> (rationalize 0.518518)259259/500000user=> (rationalize Math/PI)3141592653589793/1000000000000000

Common Lisp

There are two functions for converting decimals to rationals:rational returns a rational that is mathematically equal in value to the decimal andrationalize returns a rational that approximates the decimal to the accuracy of the underlying floating-point representation.

> (rational 0.9054054)7595091/8388608> (rationalize 0.9054054)67/74> (= (rational 0.9054054) 0.9054054)T> (= (rationalize 0.9054054) 0.9054054)NIL> (rational .518518)1087411/2097152> (rationalize .518518)33279/64181> (rational .5185185)8699297/16777216> (rationalize .5185185)14/27> (rational .75)3/4> (rationalize .75)3/4

D

Translation of:Ada
importstd.stdio,std.math,std.string,std.typecons;aliasFraction=Tuple!(int,"nominator",uint,"denominator");Fractionreal2Rational(inrealr,inuintbound)/*pure*/nothrow{if(r==0.0){returnFraction(0,1);}elseif(r<0.0){autoresult=real2Rational(-r,bound);result.nominator=-result.nominator;returnresult;}else{uintbest=1;realbestError=real.max;foreach(i;1..bound+1){// round is not pure.immutablerealerror=abs(i*r-round(i*r));if(error<bestError){best=i;bestError=error;}}returnFraction(cast(int)round(best*r),best);}}voidmain(){immutabletests=[0.750000000,0.518518000,0.905405400,0.142857143,3.141592654,2.718281828,-0.423310825,31.415926536];foreach(r;tests){writef("%8.9f  ",r);foreach(i;0..5)writef("  %d/%d",real2Rational(r,10^^i).tupleof);writeln();}}
Output:
0.750000000    1/1  3/4  3/4  3/4  3/4  3/40.518518000    1/1  1/2  14/27  14/27  14/27  37031/714170.905405400    1/1  9/10  67/74  67/74  67/74  67/740.142857143    0/1  1/7  1/7  1/7  1/7  1/73.141592654    3/1  22/7  22/7  355/113  355/113  104348/332152.718281828    3/1  19/7  193/71  1457/536  25946/9545  222630/81901-0.423310825    0/1  -3/7  -11/26  -69/163  -1253/2960  -10093/2384331.415926536    31/1  157/5  377/12  3550/113  208696/6643  2918194/92889

Delphi

Library: Velthuis.BigRationals
Library: Velthuis.BigDecimals

Thanks Rudy Velthuis for Velthuis.BigRationals and Velthuis.BigDecimals library[1].

Translation of:Go
programConvert_decimal_number_to_rational;{$APPTYPE CONSOLE}usesVelthuis.BigRationals,Velthuis.BigDecimals;constTests:TArray<string>=['0.9054054','0.518518','0.75'];varRational:BigRational;Decimal:BigDecimal;beginforvartestinTestsdobeginDecimal:=test;Rational:=Decimal;Writeln(test,' = ',Rational.ToString);end;Readln;end.

EasyLang

Translation of:C
maxd = 10000000#func$ rataprox f .   if f < 0      neg = 1      f = -f   .   n = 1   while f <> floor f      n = n * 2      f = f * 2   .   d = f   h1 = 1   k0 = 1   for i = 0 to 63      a = 0      if n <> 0 : a = d div n      if i > 0 and a = 0 : break 1      x = d      d = n      n = x mod n      x = a      if k1 * a + k0 >= maxd         x = (maxd - k0) div k1         if x * 2 >= a or k1 >= maxd            i = 65         else            break 1         .      .      h2 = x * h1 + h0      h0 = h1      h1 = h2      k2 = x * k1 + k0      k0 = k1      k1 = k2   .   num = h1   denom = k1   if neg = 1 : num = -num   return num & "/" & denom.print rataprox 0.9054054054print rataprox 0.5185185185print rataprox 0.75print rataprox 0.33333333333print rataprox 0.88888888888
Output:
67/7414/273/41/38/9


EchoLisp

Therationalize function uses a Stern-Brocot tree[2] to find the best rational approximation of an inexact (floating point) number, for a given precision. Theinexact->exact function returns a rational approximation for the default precision 0.0001 .

(exact->inexact67/74)0.9054054054054054(inexact->exact0.9054054054054054)67/74(rationalize0.7978723404255319)75/94;; finding rational approximations of PI(for((ε(in-range-1-15-1)))(writeln(format"precision:10^%d %t PI = %d"ε(rationalizePI(expt10e)))))"precision:10^-1                   PI = 16/5""precision:10^-2                   PI = 22/7";;🎩"precision:10^-3                   PI = 201/64""precision:10^-4                   PI = 333/106""precision:10^-5                   PI = 355/113";; 🎩 🎩"precision:10^-6                   PI = 355/113""precision:10^-7                   PI = 75948/24175""precision:10^-8                   PI = 100798/32085""precision:10^-9                   PI = 103993/33102""precision:10^-10                  PI = 312689/99532""precision:10^-11                  PI = 833719/265381""precision:10^-12                  PI = 4272943/1360120""precision:10^-13                  PI = 5419351/1725033""precision:10^-14                  PI = 58466453/18610450"

Factor

USING:kernelmath.floating-pointprettyprint;0.9054054 0.518518 0.75[double>ratio.]tri@
Output:
4077583422059235/45035996273704962335197471584895/45035996273704963/4

Fermat

Fermat does this automatically.

Output:
>3.14 157 / 50;  or  3.1400000000000000000000000000000000000000>10.00000       10>77.7777 777777 / 10000;  or  77.7777000000000000000000000000000000000000>-5.5 -11 / 2;  or  -5.5000000000000000000000000000000000000000

Forth

\ Brute force search, optimized to search only within integer bounds surrounding target\ Forth 200x compliant:RealToRational( float_target int_denominator_limit -- numerator denominator ){:f:therealdenlimit|realscalenumtordenomneg?f:besterrorf:temperror:}0tonumtor0todenom9999999etobesterror\ very large error that will surely be improved upontherealF0<toneg?\ save sign for latertherealFABStotherealtherealFTRUNCf>s1+torealscale\ realscale helps set integer bounds around targetdenlimit1+1?DO\ search through possible denominators ( 1 to denlimit)Irealscale*Irealscale1-*?DO\ search within integer limits bounding the realIs>fJs>fF/\ e.g. for 3.1419e search only between 3 and 4therealF-FABStotemperrortemperrorbesterrorF<IFtemperrortobesterrorItonumtorJtodenomTHENLOOPLOOPneg?IFnumtorNEGATEtonumtorTHENnumtordenom;(run)1.618033988e100RealToRationalswap..144893.14159e1000RealToRationalswap..3551132.71828e1000RealToRationalswap..12644650.9054054e100RealToRationalswap..6774

This version doesn't require local variables, since it uses the data stack and a (separate) floating point stack.MAX-N represents the largest (positive) integer.

:RealToRational( f n1 -- n2 n3)0duprotmax-ns>ffswapfdupf0<>rfabsfdupftruncf>s1+swap( den num lim real R: neg F: best real)\ helps set integer bounds around target1+1?do\ search through possible denominatorsdupi*over1-i*?do\ search within integer limits bounding the realfoverfoveris>fjs>ff/f-fabsfdupfrotf<ifnipnipjirotfswapfrotthenfdroploop\ e.g. for 3.1419e search only between 3 and 4loopfdropfdropdropr>ifnegatethenswap;

Fortran

This sort of calculation works best in base ten and with an input scheme that recognises a protocol for specifying that the decimal value has a recurring sequence, whereupon the methods taught in school could be employed. Such a protocol often conflicts with presenting a digit sequence with the last digit correctly rounded. Although many early computers worked in base ten, these days a binary base is usual, be it 2, 4, 8, or 16. Alas, five is not a factor of two nor any of its powers, and many decimal fractions, even a brief one such as 0·1, convert to a recurring sequence in binary so for example, 10·15 is in binary 1010·0010011001100110011... However, 203/20 when evaluated in binary floating-point will generate the same binary sequence as 10·15, granted that the compiler does its arithmetic correctly. Nevertheless, such a decimal value isnot the value that a binary computer will work with, except for restricted fractions such as 0·5, 0·25, 0·75, and so forth up to the precision of the arithmetic.

Rather than engage in fancy schemes, here are two "brute force" methods. The first simply multiplies the value by a large power of ten, then casts out common factors in P/Q = x*1000000000/100000000. But if the best value for Q involves factors other than two and five, this won't work well. The second method is to jiggle either P or Q upwards depending on whether P/Q is smaller or larger than X, reporting improvements as it goes. Once beyond small numbers there are many small improvements to be found, so only those much better than the previous best are reported. Loosely speaking, the number of digits correct in good values of P/Q should be the sum of the number of digits in P and Q, and more still for happy fits, but a factor of eight suffices to suppress the rabble. Thus for Pi, the famous 22/7 and 355/113 appear as desired. Later pairs use lots more digits without a surprise hit, except for the short decimal sequence which comes out as 314159/100000 that reconstitutes the given decimal fraction exactly. Which is not a good approximation for Pi, and its pairs diverge from those of the more accurate value. In other words, one must assess the precision of the given value and not be distracted by the spurious precision offered by the larger P/Q pairs, so for 3·14159 with six digits, there is little point in going further than 355/113 - with their six digits. Contrariwise, if a P/Q with few digits matches many more digits of the given number, then a source rational number can be suspected. But if given just a few digits, such as 0·518 (or 0·519, when rounded), 13/25 could be just as likely a source number as 14/27 which is further away.

The source uses the MODULE facility of F90 merely to avoid the annoyance of having to declare the type of integer function GCD. The T ("tab") format code is employed to facilitate the alignment of output, given that P/Q is presented with I0 format so that there are no spaces (as in " 22/ 7" for example), the latter being standard in F90 but an extension in earlier Fortrans.

MODULEPQ!Plays with some integer arithmetic.INTEGERMSG!Output unit number.CONTAINS!One good routine.INTEGERFUNCTIONGCD(I,J)!Greatest common divisor.INTEGERI,J!Of these two integers.INTEGERN,M,R!Workers.N=MAX(I,J)!Since I don't want to damage I or J,M=MIN(I,J)!These copies might as well be the right way around.1R=MOD(N,M)!Divide N by M to get the remainder R.IF(R.GT.0)THEN!Remainder zero?N=M!No. Descend a level.M=R!M-multiplicity has been removed from N.IF(R.GT.1)GOTO1!No point dividing by one.END IF!If R = 0, M divides N.GCD=M!There we are.END FUNCTIONGCD!Euclid lives on!SUBROUTINERATIONAL10(X)!By contrast, this is rather crude.DOUBLE PRECISIONX!The number.DOUBLE PRECISIONR!Its latest rational approach.INTEGERP,Q!For R = P/Q.INTEGERF,WHACK!Assistants.PARAMETER(WHACK=10**8)!The rescale...P=X*WHACK+0.5!Multiply by WHACK/WHACK = 1 and round to integer.Q=WHACK!Thus compute X/1, sortof.F=GCD(P,Q)!Perhaps there is a common factor.P=P/F!Divide it out.Q=Q/F!For a proper rational number.R=DBLE(P)/DBLE(Q)!So, where did we end up?WRITE(MSG,1)P,Q,X-R,WHACK!Details.1FORMAT("x - ",I0,"/",I0,T28," = ",F18.14,1" via multiplication by ",I0)END SUBROUTINERATIONAL10!Enough of this.SUBROUTINERATIONAL(X)!Use brute force in a different way.DOUBLE PRECISIONX!The number.DOUBLE PRECISIONR,E,BEST!Assistants.INTEGERP,Q!For R = P/Q.INTEGERTRY,F!Floundering.P=1+X!Prevent P = 0.Q=1!So, X/1, sortof.BEST=X*6!A largeish value for the first try.DOTRY=1,10000000!Pound away.R=DBLE(P)/DBLE(Q)!The current approximation.E=X-R!Deviation.IF(ABS(E).LE.BEST)THEN!Significantly better than before?BEST=ABS(E)*0.125!Yes. Demand eightfold improvement to notice.F=GCD(P,Q)!We may land on a multiple.IF(BEST.LT.0.1D0)WRITE(MSG,1)P/F,Q/F,E!Skip early floundering.1FORMAT("x - ",I0,"/",I0,T28," = ",F18.14)!Try to align columns.IF(F.NE.1)WRITE(MSG,*)"Common factor!",F!A surprise!IF(E.EQ.0)EXIT!Perhaps we landed a direct hit?END IF!So much for possible announcements.IF(E.GT.0)THEN!Is R too small?P=P+CEILING(E*Q)!Yes. Make P bigger by the shortfall.ELSE IF(E.LT.0)THEN!But perhaps R is too big?Q=Q+1!If so, use a smaller interval.END IF!So much for adjustments.END DO!Try again.END SUBROUTINERATIONAL!Limited integers, limited sense.SUBROUTINERATIONALISE(X,WOT)!Run the tests.DOUBLE PRECISIONX!The value.CHARACTER*(*)WOT!Some blather.WRITE(MSG,*)X,WOT!Explanations can help.CALLRATIONAL10(X)!Try a crude method.CALLRATIONAL(X)!Try a laborious method.WRITE(MSG,*)!Space off.END SUBROUTINERATIONALISE!That wasn't much fun.END MODULEPQ!But computer time is cheap.PROGRAMAPPROXUSEPQDOUBLE PRECISIONPI,EMSG=6WRITE(MSG,*)"Rational numbers near to decimal values."WRITE(MSG,*)PI=1!Thus get a double precision conatant.PI=4*ATAN(PI)!That will determine the precision of ATAN.E=DEXP(1.0D0)!Rather than blabber on about 1 in double precision.CALLRATIONALISE(0.1D0,"1/10 Repeating in binary..")CALLRATIONALISE(3.14159D0,"Pi approx.")CALLRATIONALISE(PI,"Pi approximated better.")CALLRATIONALISE(E,"e: rational approximations aren't much use.")CALLRATIONALISE(10.15D0,"Exact in decimal, recurring in binary.")WRITE(MSG,*)WRITE(MSG,*)"Variations on 67/74"CALLRATIONALISE(0.9054D0,"67/74 = 0·9(054) repeating in base 10")CALLRATIONALISE(0.9054054D0,"Two repeats.")CALLRATIONALISE(0.9054054054D0,"Three repeats.")WRITE(MSG,*)WRITE(MSG,*)"Variations on 14/27"CALLRATIONALISE(0.518D0,"14/27 = 0·(518) repeating in decimal.")CALLRATIONALISE(0.519D0,"Rounded.")CALLRATIONALISE(0.518518D0,"Two repeats, truncated.")CALLRATIONALISE(0.518519D0,"Two repeats, rounded.")END

Some examples. Each rational value is followed by X - P/Q. Notice that 0·(518) repeating, presented as 0·518518, isnot correctly rounded.

 Rational numbers near to decimal values.  0.100000000000000      1/10 Repeating in binary..x - 1/10                    =   0.00000000000000 via multiplication by 100000000x - 1/2                     =  -0.40000000000000x - 1/7                     =  -0.04285714285714x - 1/10                    =   0.00000000000000   3.14159000000000      Pi approx.x - 314159/100000           =   0.00000000000000 via multiplication by 100000000x - 16/5                    =  -0.05841000000000x - 22/7                    =  -0.00126714285714x - 355/113                 =  -0.00000292035398x - 9563/3044               =  -0.00000001314060x - 85712/27283             =  -0.00000000109959x - 238010/75761            =  -0.00000000013199x - 314159/100000           =   0.00000000000000   3.14159265358979      Pi approximated better.x - 62831853/20000000       =   0.00000000358979 via multiplication by 100000000x - 16/5                    =  -0.05840734641021x - 22/7                    =  -0.00126448926735x - 355/113                 =  -0.00000026676419x - 104348/33215            =  -0.00000000033163x - 312689/99532            =  -0.00000000002914x - 1146408/364913          =  -0.00000000000161x - 5419351/1725033         =  -0.00000000000002   2.71828182845905      e: rational approximations aren't much use.x - 271828183/100000000     =  -0.00000000154095 via multiplication by 100000000x - 3/1                     =  -0.28171817154095x - 11/4                    =  -0.03171817154095x - 49/18                   =  -0.00394039376318x - 87/32                   =  -0.00046817154095x - 193/71                  =  -0.00002803069588x - 1457/536                =  -0.00000175363051x - 9620/3539               =  -0.00000017210609x - 23225/8544              =  -0.00000000674695x - 49171/18089             =  -0.00000000027665x - 566827/208524           =  -0.00000000001154x - 3820276/1405401         =  -0.00000000000130x - 11411657/4198114        =  -0.00000000000012   10.1500000000000      Exact in decimal, recurring in binary.x - 203/20                  =   0.00000000000000 via multiplication by 100000000x - 41/4                    =  -0.10000000000000x - 132/13                  =  -0.00384615384615x - 203/20                  =   0.00000000000000 Variations on 67/74  0.905400000000000      67/74 = 0·9(054) repeating in base 10x - 4527/5000               =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.09460000000000x - 9/10                    =   0.00540000000000x - 19/21                   =   0.00063809523810x - 67/74                   =  -0.00000540540541x - 2029/2241               =   0.00000062472111x - 4527/5000               =   0.00000000000000  0.905405400000000      Two repeats.x - 4527027/5000000         =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.09459460000000x - 9/10                    =   0.00540540000000x - 19/21                   =   0.00064349523810x - 67/74                   =  -0.00000000540541x - 2012029/2222241         =   0.00000000067562x - 2228707/2461557         =   0.00000000008442x - 2259125/2495153         =   0.00000000001050x - 2263011/2499445         =   0.00000000000120x - 2263480/2499963         =   0.00000000000008x - 4527027/5000000         =   0.00000000000000  0.905405405400000      Three repeats.x - 90540541/100000000      =  -0.00000000460000 via multiplication by 100000000x - 1/1                     =  -0.09459459460000x - 9/10                    =   0.00540540540000x - 19/21                   =   0.00064350063810x - 67/74                   =  -0.00000000000541 Variations on 14/27  0.518000000000000      14/27 = 0·(518) repeating in decimal.x - 259/500                 =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.48200000000000x - 1/2                     =   0.01800000000000x - 13/25                   =  -0.00200000000000x - 29/56                   =   0.00014285714286x - 72/139                  =   0.00001438848921x - 259/500                 =   0.00000000000000  0.519000000000000      Rounded.x - 519/1000                =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.48100000000000x - 1/2                     =   0.01900000000000x - 13/25                   =  -0.00100000000000x - 41/79                   =   0.00001265822785x - 478/921                 =  -0.00000108577633x - 519/1000                =   0.00000000000000  0.518518000000000      Two repeats, truncated.x - 259259/500000           =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.48148200000000x - 1/2                     =   0.01851800000000x - 13/25                   =  -0.00148200000000x - 14/27                   =  -0.00000051851852x - 32929/63506             =   0.00000006468680x - 36471/70337             =   0.00000000804697x - 36975/71309             =   0.00000000086946x - 37031/71417             =   0.00000000008401x - 185183/357139           =   0.00000000000560x - 259259/500000           =   0.00000000000000  0.518519000000000      Two repeats, rounded.x - 518519/1000000          =   0.00000000000000 via multiplication by 100000000x - 1/1                     =  -0.48148100000000x - 1/2                     =   0.01851900000000x - 13/25                   =  -0.00148100000000x - 14/27                   =   0.00000048148148x - 35461/68389             =  -0.00000006008276x - 39283/75760             =  -0.00000000739176x - 39815/76786             =  -0.00000000085953x - 39885/76921             =  -0.00000000001300x - 478634/923079           =   0.00000000000108x - 518519/1000000          =   0.00000000000000

FreeBASIC

'' Written in FreeBASIC'' (no error checking, limited to 64-bit signed math)typenumberaslongint#definestr2numvallng#definepow10(n)clngint(10^(n))functiongcd(aasnumber,basnumber)asnumberifa=0thenreturnbreturngcd(bmoda,a)endfunctionfunctionparserational(nasconststring)asstringdimasstringwhole,dec,num,denomdimasnumberiwhole,idec,inum,idenom,igcd'' find positions of '.', '(' and ')' in codedimasintegerdpos,r1pos,r2posdpos=instr(n&".",".")r1pos=instr(n&"(","(")r2pos=instr(n&")",")")'' extract sections of number (whole, decimal, repeated numerator), generate '999' denominatorwhole=left(n,dpos-1)dec=mid(n,dpos+1,r1pos-dpos-1)num=mid(n,r1pos+1,r2pos-r1pos-1)denom=string(len(num),"9"):ifdenom=""thendenom="1"'' parse sections to integeriwhole=str2num(whole)idec=str2num(dec)inum=str2num(num)idenom=str2num(denom)'' if whole was negative, decimal and repeated sections need to be negative tooifleft(ltrim(whole),1)="-"thenidec=-idec:inum=-inum'' add decimal part to repeated fraction, and scale downinum+=idec*idenomidenom*=pow10(len(dec))'' add integer part to fractioninum+=iwhole*idenom'' simplify fractionigcd=abs(gcd(inum,idenom))ifigcd<>0theninum\=igcdidenom\=igcdendifreturninum&" / "&idenom&" = "&(inum/idenom)endfunctiondata"0.9(054)","0.(518)","-.12(345)",""dodimasstringnreadnifn=""thenexitdoprintn&":",parserational(n)loop

Frink

println[toRational[0.9054054]]println[toRational[0.518518]]println[toRational[0.75]]
Output:
4527027/5000000 (exactly 0.9054054)259259/500000 (exactly 0.518518)3/4 (exactly 0.75)


Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in itswebsite.

Inthis page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

Without repeating digits

The FōrmulæRationalize expression converts from decimal numberts to rational in lower terms.


With repeating digits

FōrmulæRationalize expression can convert from decimal numbers with infinite number of repeating digits. The second arguments specifies the number of repeating digits.


In the following example, a conversion of the resulting rational back to decimal is provided in order to prove that it was correct:


0.999... is actually 1:

Programatically

Even when rationalization expressions are intrinsic in Fōrmulæ, we can write explicit functions:


Go

Go has no native decimal representation so strings are used as input here. The program parses it into a Go rational number, which automatically reduces.

packagemainimport("fmt""math/big")funcmain(){for_,d:=range[]string{"0.9054054","0.518518","0.75"}{ifr,ok:=new(big.Rat).SetString(d);ok{fmt.Println(d,"=",r)}else{fmt.Println(d,"invalid decimal number")}}}

Output:

0.9054054 = 4527027/50000000.518518 = 259259/5000000.75 = 3/4

Groovy

Solution:
Uses theRational number class andRationalCategory helper class created in the solution to theArithmetic/Rational task.

Test:

Number.metaClass.mixinRationalCategory[0.9054054,0.518518,0.75,Math.E,-0.423310825,Math.PI,0.111111111111111111111111].each{printf"%30.27f %s\n",it,itasRational}

Output:

 0.905405400000000000000000000 4527027//5000000 0.518518000000000000000000000 259259//500000 0.750000000000000000000000000 3//4 2.718281828459045000000000000 6121026514868073//2251799813685248-0.423310825000000000000000000 -16932433//40000000 3.141592653589793000000000000 884279719003555//281474976710656 0.111111111111111111111111000 111111111111111111111111//1000000000000000000000000

Clearly this solution does not make any assumptions or approximations regarding repeating decimals.

Haskell

Note that the decimal values of the task description are truncated in some cases.

The first map finds the simplest fractions within a given radius, because the floating-point representation is not exact. The second line shows that the numbers could be parsed into fractions at compile time if they are given the right type. The last converts the string representation of the given values directly to fractions.

Prelude>map(\d->Ratio.approxRationald0.0001)[0.9054054,0.518518,0.75][67%74,14%27,3%4]Prelude>[0.9054054,0.518518,0.75]::[Rational][4527027%5000000,259259%500000,3%4]Prelude>map(fst.head.Numeric.readFloat)["0.9054054","0.518518","0.75"]::[Rational][4527027%5000000,259259%500000,3%4]

J

J'sx: built-in will find a rational number which "best matches" a floating point number.

x:0.90540540.5185180.75NB. find "exact" rational representation127424481939351r140737488355328866492568306r16710944813993r4

These numbers are ratios where the integer on the left of ther is the numerator and the integer on the right of ther is the denominator. (Note that this use is in analogy with floating point notion, though it is true that hexadecimal notation and some languages' typed numeric notations use letters within numbers. Using letters rather than other characters makes lexical analysis simpler to remember - both letters and numbers are almost always "word forming characters".)

Note that the concept of "best" has to do with the expected precision of the argument:

x:0.90.59r101r2x:0.90540.51854527r50001037r2000x:0.90540540.5185185127424481939351r1407374883553281037037r2000000x:0.90540540540.51851851855358191125333r59180021384636073341499873r11712872893031x:0.90540540540540.518518518518567r7414r27x:0.90540540540540540.518518518518518567r7414r27

Note that J allows us to specify an epsilon, for the purpose of recognizing a best fit, but the allowed values must be rather small. In J version 6, the value 5e_11 was nearly the largest epsilon allowed:

x:(!.5e_11)0.90540540540.518518518567r7414r27

(Note that epsilon will be scaled by magnitude of the largest number involved in a comparison when testing floating point representations of numbers for "equality". Note also that this J implementation uses 64 bit ieee floating point numbers.)

Here are some other alternatives for dealing with decimals and fractions:

0j10":x:invx:0.90540540.5185180.75NB. invertible (shown to 10 decimal places)0.90540540000.51851800000.75000000000j10":x:inv67r7442r813r4NB. decimal representation (shown to 10 decimal places)0.90540540540.51851851850.7500000000x:x:inv67r7442r813r4NB. invertible67r7414r273r4

Java

doublefractionToDecimal(Stringstring){intindexOf=string.indexOf(' ');intinteger=0;intnumerator,denominator;if(indexOf!=-1){integer=Integer.parseInt(string.substring(0,indexOf));string=string.substring(indexOf+1);}indexOf=string.indexOf('/');numerator=Integer.parseInt(string.substring(0,indexOf));denominator=Integer.parseInt(string.substring(indexOf+1));returninteger+((double)numerator/denominator);}StringdecimalToFraction(doublevalue){Stringstring=String.valueOf(value);string=string.substring(string.indexOf('.')+1);intnumerator=Integer.parseInt(string);intdenominator=(int)Math.pow(10,string.length());intgcf=gcf(numerator,denominator);if(gcf!=0){numerator/=gcf;denominator/=gcf;}intinteger=(int)value;if(integer!=0)return"%d %d/%d".formatted(integer,numerator,denominator);return"%d/%d".formatted(numerator,denominator);}intgcf(intvalueA,intvalueB){if(valueB==0)returnvalueA;elsereturngcf(valueB,valueA%valueB);}
67/74 = 0.905405405405405414/27 = 0.51851851851851850.9054054 = 4527027/50000000.518518 = 259259/500000


importorg.apache.commons.math3.fraction.BigFraction;publicclassTest{publicstaticvoidmain(String[]args){double[]n={0.750000000,0.518518000,0.905405400,0.142857143,3.141592654,2.718281828,-0.423310825,31.415926536};for(doubled:n)System.out.printf("%-12s : %s%n",d,newBigFraction(d,0.00000002D,10000));}}
0.75         : 3 / 40.518518     : 37031 / 714170.9054054    : 67 / 740.142857143  : 1 / 73.141592654  : 104348 / 332152.718281828  : 23225 / 8544-0.423310825 : -1253 / 296031.415926536 : 208696 / 6643

JavaScript

Deriving an approximation within a specified tolerance:

(()=>{"use strict";// ---------------- APPROXIMATE RATIO ----------------// approxRatio :: Real -> Real -> RatioconstapproxRatio=epsilon=>n=>{constc=gcdApprox(0<epsilon?epsilon:(1/10000))(1,n);returnRatio(Math.floor(n/c),Math.floor(1/c));};// gcdApprox :: Real -> (Real, Real) -> RealconstgcdApprox=epsilon=>(x,y)=>{const_gcd=(a,b)=>b<epsilon?a:_gcd(b,a%b);return_gcd(Math.abs(x),Math.abs(y));};// ---------------------- TEST -----------------------// main :: IO ()constmain=()=>// Using a tolerance of 1/10000[0.9054054,0.518518,0.75].map(compose(showRatio,approxRatio(0.0001))).join("\n");// ---------------- GENERIC FUNCTIONS ----------------// compose (<<<) :: (b -> c) -> (a -> b) -> a -> cconstcompose=(...fs)=>// A function defined by the right-to-left// composition of all the functions in fs.fs.reduce((f,g)=>x=>f(g(x)),x=>x);// Ratio :: Int -> Int -> RatioconstRatio=(n,d)=>({type:"Ratio",n,d});// showRatio :: Ratio -> StringconstshowRatio=nd=>`${nd.n.toString()}/${nd.d.toString()}`;// MAIN ---returnmain();})();
Output:
67/7414/273/4

jq

Works withjq (*)

Works with gojq, the Go implementation of jq

The following definition of `number_to_r` can be used for JSON numbers in general, as illustrated by the examples.

This entry assumes the availabilityof two functions (`r/2` and `power/1`) as defined inthe "rational" moduleatArithmetic/Rational#jq, which also provides a definitionfor `rpp/0`, a pretty-printer used in the examples.

(*) With the caveat that the C implementation of jq does not support unlimited-precision integer arithmetic.

# include "rational"; # a reminder that r/2 and power/1 are required# Input: any JSON number, not only a decimal# Output: a rational, constructed using r/2# Requires power/1 (to take advantage of gojq's support for integer arithmetic)# and r/2 (for rational number constructor)def number_to_r:  # input: a decimal string  # $in - either null or the original input  # $e  - the integer exponent of the original number, or 0  def dtor($in; $e):    index(".") as $ix    | if $in and ($ix == null) then $in      else (if $ix then sub("[.]"; "") else . end | tonumber) as $n      | (if $ix then ((length - ($ix+1)) - $e) else - $e end) as $p      | if $p >= 0         then r( $n;   10|power($p))        else r( $n * (10|power(-$p)); 1)        end     end;          . as $in    | tostring    | if (test("[Ee]")|not) then dtor($in; 0)      else capture("^(?<s>[^eE]*)[Ee](?<e>.*$)")      | (.e | if length > 0 then tonumber else 0 end) as $e      | .s | dtor(null; $e)    end ;

Examples

0.9054054,0.518518,0.75,1e308 | "\(.) → \(number_to_r | rpp)"
Output:
0.9054054 → 4527027 // 50000000.518518 → 259259 // 5000000.75 → 3 // 41e+308 → 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 // 1

Julia

Julia has a native Rational type, and providesa convenience conversion function that implements a standard algorithm for approximating a floating-point number by a ratio of integers to within a given tolerance, which defaults to machine epsilon.

rationalize(0.9054054)rationalize(0.518518)rationalize(0.75)
4527027//5000000259259//5000003//4

Since Julia by default uses itsFloat64 type to represent floating-point numbers, if enough decimal digits are provided (so that the difference between the floating-point representation of the resulting fraction and the original number is smaller than the machine epsilon) the smaller fraction is returned, which in this case is the exact result:

julia> rationalize(0.5185185185185185)14//27julia> rationalize(0.9054054054054054)67//74

Here is the core algorithm written in Julia 1.0, without handling various data types and corner cases:

functionrat(x::AbstractFloat,tol::Real=eps(x))::Rationalp,q,pp,qq=copysign(1,x),0,0,1x,y=abs(x),1.0r,a=modf(x)nt,t,tt=tol,0.0,tolwhiler>nt# convergents of the continued fraction: np//nq = (p*a + pp) // (q*a + qq)np,nq=Int(a).*(p,q).+(pp,qq)p,pp,q,qq=np,p,nq,qx,y=y,r# instead of the inexact 1/r...a,r=divrem(x,y)t,tt=nt,t# maintain x = (p + (-1)^i * r) / qnt=a*t+ttendi=Int(cld(x-tt,y+t))# find optimal semiconvergent: smallest i such that x-i*y < i*t+ttreturn(i*p+pp)//(i*q+qq)end

Kotlin

// version 1.1.2classRational(valnum:Long,valden:Long){overridefuntoString()="$num/$den"}fundecimalToRational(d:Double):Rational{valds=d.toString().trimEnd('0').trimEnd('.')valindex=ds.indexOf('.')if(index==-1)returnRational(ds.toLong(),1L)varnum=ds.replace(".","").toLong()varden=1Lfor(nin1..(ds.length-index-1))den*=10Lwhile(num%2L==0L&&den%2L==0L){num/=2Lden/=2L}while(num%5L==0L&&den%5L==0L){num/=5Lden/=5L}returnRational(num,den)}funmain(args:Array<String>){valdecimals=doubleArrayOf(0.9054054,0.518518,2.405308,.75,0.0,-0.64,123.0,-14.6)for(decimalindecimals)println("${decimal.toString().padEnd(9)} = ${decimalToRational(decimal)}")}
Output:
0.9054054 = 4527027/50000000.518518  = 259259/5000002.405308  = 601327/2500000.75      = 3/40.0       = 0/1-0.64     = -16/25123.0     = 123/1-14.6     = -73/5

Liberty BASIC

'   Uses convention that one repeating sequence implies infinitely repeating sequence..'   Non-recurring fractions are limited to nd number of digits in nuerator & denominatornd =3   '   suggest 3. 4 is slow. >4 is .......do    read x$    data "0.5", "0.1", "0.333", "1 /3", "0.33", "0.14159265", "2^-0.5", "0.1 +0.9*rnd(1)"    data "0.142857142857", "int( 1000*rnd(1))/int( 1000*rnd(1))","end"   '   always between 0 and 0.999999...    if x$ ="end" then exit do    print x$; " is ";    type$ =check$( x$)    print type$;    if type$ ="recurring" then        x   =val( mid$( x$, 3, ( len( x$) -2) /2))        rep =( len( x$) -2) /2        num =x        den =10^rep -1        gcd =gcd( num, den)        print        print " Calculating exact fraction for ", recurring$( x); " recurring & found";        print num /gcd; " /"; den /gcd        print    else    '   non-recurring. Check numerators & denominators <1000        x =eval( x$)        print        print " Looking for fractions that are close to "; using( "#.############", x); " & found ";        eps =10^nd        for n = 1 to nd            for i =1 to 10^n -1                for j =i to 10^n -1                    fr =i /j                    if abs( x -fr) <eps then                        eps =abs( x -fr)                        'print i; " /"; j; " = ", using( "##.############", fr), "with error +/-"; using( "###.#########", eps /x *100); " %"                        ii =i: jj =j                        if eps =0 then exit for                    end if                next j                scan                if eps =0 then exit for            next i            if eps =0 then exit for        next n        print ii; " /"; jj        print    end ifloop until 0printprint "END."endfunction recurring$( x)    recurring$ ="0."    do        recurring$ =recurring$ +str$( x)    loop until len( recurring$) >=14end functionfunction gcd( a, b)  '   thanks Uncle Ben..    while b <>0       t =b       b =a mod b       a =t    wend    gcd =aend functionfunction check$( i$)    check$ ="non-recurring"    length =len( i$) -2     '   allow for the '0.'.    if length /2 =int( length /2) then if mid$( i$, 3, length /2) =mid$( i$, 3 +length /2, length /2) then check$ ="recurring"end function
 0.5 is non-recurring Looking for fractions that are close to 0.500000000000 & found 1 /20.1 is non-recurring Looking for fractions that are close to 0.100000000000 & found 1 /100.333 is non-recurring Looking for fractions that are close to 0.333000000000 & found 332 /9971 /3 is non-recurring Looking for fractions that are close to 0.333333333333 & found 1 /30.33 is recurring Calculating exact fraction for           0.333333333333 recurring & found1 /30.14159265 is non-recurring Looking for fractions that are close to 0.141592650000 & found 16 /1132^-0.5 is non-recurring Looking for fractions that are close to 0.707106781187 & found 408 /5770.1 +0.9*rnd(1) is non-recurring Looking for fractions that are close to 0.489587274383 & found 47 /960.142857142857 is recurring Calculating exact fraction for           0.142857142857 recurring & found1 /7int( 1000*rnd(1))/int( 1000*rnd(1)) is non-recurring Looking for fractions that are close to 0.032786885246 & found 2 /61END.

Lua

Brute force, and why not?

for_,vinipairs({0.9054054,0.518518,0.75,math.pi})dolocaln,d,dmax,eps=1,1,1e7,1e-15whilemath.abs(n/d-v)>epsandd<dmaxdod=d+1n=math.floor(v*d)endprint(string.format("%15.13f --> %d / %d",v,n,d))end
Output:
0.9054054000000 --> 4527027 / 50000000.5185180000000 --> 259259 / 5000000.7500000000000 --> 3 / 43.1415926535898 --> 31415926 / 10000000

M2000 Interpreter

moduleConvert_decimal_number_to_rational{FunctionRational(numeratorasdecimal,denominatorasdecimal=1){ifdenominator==0thendenominator=1whilefrac(numerator)<>0{numerator*=10@denominator*=10@}sgn=Sgn(numerator)*Sgn(denominator)denominator<=abs(denominator)numerator<=abs(numerator)*sgngcd1=lambda(aasdecimal,basdecimal)->{ifa<bthenswapa,bg=amodbwhileg>0@{a=b:b=g:g=amodb}' added >0@ for removing overflow.=abs(b)}gdcval=gcd1(abs(numerator),denominator)ifgdcval<denominatorandgdcval<>0thendenominator/=gdcvalnumerator/=gdcvalendif=(numerator,denominator)}PrintRational(0.9054054)#str$(" / ")="4527027 / 5000000"' truePrintRational(0.518518)#str$(" / ")="259259 / 500000"' truePrintRational(0.75)#str$(" / ")="3 / 4"' true}Convert_decimal_number_to_rational

Maple

>map(convert,[0.9054054,0.518518,0.75],'rational','exact');4527027259259[-------,------,3/4]5000000500000

Mathematica /Wolfram Language

Map[Rationalize[#,0]&,{0.9054054,0.518518,0.75}]->{4527027/5000000,259259/500000,3/4}

MATLAB /Octave

[a,b]=rat(.75)[a,b]=rat(.518518)[a,b]=rat(.9054054)

Output:

  >>   [a,b]=rat(.75)  a =  3  b =  4  >>   [a,b]=rat(.518518)  a =  37031  b =  71417  >>   [a,b]=rat(.9054054)  a =  67  b =  74

МК-61/52

This example isin need of improvement:

This example is not clear, please improve it or delete it!

П0П1ИП1{x}x#014КИП4ИП110*П1БП02ИП410^xП0ПAИП1ПBИПAИПB/П9КИП9ИПAИПBПAИП9*-ПBx=020ИПAИП0ИПA/П0ИП1ИПA/П1ИП0ИП1С/П

NetRexx

Now the nearly equivalent program.

/*NetRexx program to convert decimal numbers to fractions ************** 16.08.2012 Walter Pachl derived from Rexx Version 2**********************************************************************/optionsreplaceformatcommentsjavacrossrefsavelogsymbolsNumericDigits10/* use "only" 10 digs of precision */ratt('0.9054054054','67/74')ratt('0.5185185185','14/27')ratt('0.75','3/4')ratt('0.905405400',' 693627417/766095958')ratt('0.9054054054','67/74')ratt('0.1428571428','1/7')ratt('35.000','35')ratt('35.001','35001/1000')ratt('0.00000000001','?')ratt('0.000001000001','1/999999')ratt(0.9054054054,'1/3')methodratt(d=Rexx,fs=Rexx)publicstaticfract=rat(d)Say'  'd'->'fractParsefractno'/'deIfde=''Thenx=noElsex=no/deIfx<>dThenSay'> '||x'is different'methodrat(in,high='')publicstatic/*********************************************************************** rat(number<,high) returns a fraction or an integer that is equal to* or approximately equal to number.* Nominator and denominator must not have more than high digits* 16.08.2012 Walter Pachl derived from Rexx Version 2**********************************************************************/ifhigh==''thenhigh=10**(digits-1)/* maximum nominator/denominator */x=in/* working copy               */nom=0/* start values nominator     */den=1/*              denominator   */tnom=1/*         temp nominator     */tden=0/*         temp denominator   */loopWhiletnom<=high&tden<=high/* nominator... not too large */n=x.trunc()/* take integer part of x     */z=tnom;/* save temp nominator        */tnom=n*tnom+nom;/* compute new temp nominator */nom=z/* assign nominator           */z=tden;/* save temp denominator      */tden=n*tden+den/* compute new temp denominato*/den=z/* assign denominator         */ifn=x|tnom/tden=inthendoiftnom>high|tden>highthen/* temp value(s) too large    */Leave/* don't use them             */nom=tnom/* otherwise take them as     */den=tden/* final values               */leave/* and end the loop           */endx=1/(x-n)/* compute x for next round   */endIfden=1ThenReturnnom/* an integer                 */ElseReturnnom'/'den/* otherwise a fraction       */

Output is the same as for Rexx Version 2.

Nim

Similar to the Rust and Julia implementations.

importmathimportfenvtypeRational=objectnumerator:intdenominator:intproc`$`(self:Rational):string=ifself.denominator==1:$self.numeratorelse:$self.numerator&"//"&$self.denominatorfuncrationalize(x:float,tol:float=epsilon(float)):Rational=varxx=xletflagNeg=xx<0.0ifflagNeg:xx=-xxifxx<minimumPositiveValue(float):returnRational(numerator:0,denominator:1)ifabs(xx-round(xx))<tol:returnRational(numerator:int(round(xx)),denominator:1)vara=0varb=1varc=int(ceil(xx))vard=1varaux1=high(int)div2whilec<aux1andd<aux1:varaux2=(float(a)+float(c))/(float(b)+float(d))ifabs(xx-aux2)<tol:breakifxx>aux2:inca,cincb,delse:incc,aincd,bvargcd=gcd(a+c,b+d)ifflagNeg:Rational(numerator:-(a+c)divgcd,denominator:(b+d)divgcd)else:Rational(numerator:(a+c)divgcd,denominator:(b+d)divgcd)echorationalize(0.9054054054)echorationalize(0.9054054054,0.0001)echorationalize(0.5185185185)echorationalize(0.5185185185,0.0001)echorationalize(0.75)echorationalize(0.1428571428,0.001)echorationalize(35.000)echorationalize(35.001)echorationalize(0.9)echorationalize(0.99)echorationalize(0.909)echorationalize(0.909,0.001)
Output:
2263456195//249993669367//741037026019//199997875114//273//41//73535001//10009//1099//100909//100010//11

Nim also has a rationals library for this, though it does not allow you to set tolerances like the code above.

importrationalsechotoRational(0.9054054054)echotoRational(0.5185185185)echotoRational(0.75)echotoRational(0.1428571428)echotoRational(35.000)echotoRational(35.001)echotoRational(0.9)echotoRational(0.99)echotoRational(0.909)
Output:
67/741037036407/19999987853/41/735/135001/10009/1099/100909/1000

Ol

Any number in Ol by default is exact. It means that any number automatically converted into rational form. If you want to use real floating point numbers, use "#i" prefix.

Function `exact` creates exact number (possibly rational) from any inexact.

(print(exact#i0.9054054054))(print(exact#i0.5185185185))(print(exact#i0.75))(print(exact#i35.000))(print(exact#i35.001))(print(exact#i0.9))(print(exact#i0.99))(print(exact#i0.909))
Output:
4077583446378673/45035996273704964670399613402603/90071992547409923/4354925952829924835/1407374883553288106479329266893/90071992547409924458563631096791/45035996273704964093772061279781/4503599627370496

PARI/GP

Quick and dirty.

convert(x)={  my(n=0);  while(x-floor(x*10^n)/10^n!=0.,n++);  floor(x*10^n)/10^n};

To convert a number into a rational with a denominator not dividing a power of 10, usecontfrac and the Gauss-Kuzmin distribution to distinguish (hopefully!) where to truncate.

PascalABC.NET

##usesnumlibabc;functiontofraction(s:string):fraction;beginvarperiod:=s.IndexOf('.');result:=Frc(s.Remove(period,1).ToBigInteger,Power(10bi,s.Length-period-1));end;vardecimals:=|0.9054054,0.518518,0.75|;foreachvardecindecimalsdobeginprint(dec.ToString,'->');println(tofraction(dec.tostring));end;
Output:
0.9054054 -> 4527027/50000000.518518 -> 259259/5000000.75 -> 3/4

Perl

Note: the following is considerably more complicated than what was specified, because the specification is not, well, specific. Three methods are provided with different interpretation of what "conversion" means: keeping the string representation the same, keeping machine representation the same, or find best approximation with denominator in a reasonable range. None of them takes integer overflow seriously (though the best_approx is not as badly subject to it), so not ready for real use.

subgcd{my($m,$n)=@_;($m,$n)=($n,$m%$n)while$n;return$m}subrat_machine{my$n=shift;my$denom=1;while($n!=int$n){# assuming the machine format is base 2, and multiplying# by 2 doesn't change the mantissa$n*=2;# multiply denom by 2, ignoring (very) possible overflow$denom<<=1;}if($n){my$g=gcd($n,$denom);$n/=$g;$denom/=$g;}return$n,$denom;}# helper, make continued fraction back into normal fractionsubget_denom{my($num,$denom)=(1,pop@_);for(reverse@_){($num,$denom)=($denom,$_*$denom+$num);}wantarray?($num,$denom):$denom}subbest_approx{my($n,$limit)=@_;my($denom,$neg);if($n<0){$neg=1;$n=-$n;}my$int=int($n);my($num,$denom,@coef)=(1,$n-$int);# continued fraction, sort ofwhile(1){# make sure it terminateslastif$limit*$denom<1;my$i=int($num/$denom);# not the right way to get limit, but it workspush@coef,$i;if(get_denom(@coef)>$limit){pop@coef;last;}# we lose precision here, but c'est la vie($num,$denom)=($denom,$num-$i*$denom);}($num,$denom)=get_denom@coef;$num+=$denom*$int;return$neg?-$num:$num,$denom;}subrat_string{my$n=shift;my$denom=1;my$neg;# trival xyz.0000 ... case$n=~s/\.0+$//;return$n,1unless$n=~ /\./;if($n=~ /^-/){$neg=1;$n=~s/^-//;}# shift decimal point to the right till it's gone$denom*=10while$n=~s/\.(\d)/$1\./;$n=~s/\.$//;# removing leading zeros lest it looks like octal$n=~s/^0*//;if($n){my$g=gcd($n,$denom);$n/=$g;$denom/=$g;}return$neg?-$n:$n,$denom;}my$limit=1e8;my$x=3/8;print"3/8 = $x:\n";printf"machine: %d/%d\n",rat_machine$x;printf"string:  %d/%d\n",rat_string$x;printf"approx below $limit:  %d/%d\n",best_approx$x,$limit;$x=137/4291;print"\n137/4291 = $x:\n";printf"machine: %d/%d\n",rat_machine$x;printf"string:  %d/%d\n",rat_string$x;printf"approx below $limit:  %d/%d\n",best_approx$x,$limit;$x=sqrt(1/2);print"\n1/sqrt(2) = $x\n";printf"machine: %d/%d\n",rat_machine$x;printf"string:  %d/%d\n",rat_string$x;printf"approx below 10:  %d/%d\n",best_approx$x,10;printf"approx below 100:  %d/%d\n",best_approx$x,100;printf"approx below 1000:  %d/%d\n",best_approx$x,1000;printf"approx below 10000:  %d/%d\n",best_approx$x,10000;printf"approx below 100000:  %d/%d\n",best_approx$x,100000;printf"approx below $limit:  %d/%d\n",best_approx$x,$limit;$x=-4*atan2(1,1);print"\n-Pi = $x\n";printf"machine: %d/%d\n",rat_machine$x;printf"string:  %d/%d\n",rat_string$x;for(map{10**$_}1..10){printf"approx below %g: %d / %d\n",$_,best_approx($x,$_)}

Output:

3/8 = 0.375:machine: 3/8string:  3/8approx below 100000000:  3/8137/4291 = 0.0319272896760662:machine: 2300603678209305/72057594037927936string:  159636448380331/5000000000000000approx below 100000000:  137/42911/sqrt(2) = 0.707106781186548machine: 6369051672525773/9007199254740992string:  176776695296637/250000000000000approx below 10:  5/7approx below 100:  29/41approx below 1000:  408/577approx below 10000:  5741/8119approx below 100000:  33461/47321approx below 100000000:  38613965/54608393-Pi = -3.14159265358979machine: -884279719003555/281474976710656string:  -314159265358979/100000000000000approx below 10: -22 / 7approx below 100: -22 / 7approx below 1000: -355 / 113approx below 10000: -355 / 113approx below 100000: -208341 / 66317approx below 1e+06: -1146408 / 364913approx below 1e+07: -5419351 / 1725033approx below 1e+08: -245850922 / 78256779approx below 1e+09: -1881244168 / 598818617approx below 1e+10: -9978066541 / 3176117225

Phix

withjavascript_semanticsfunctiondecrat(strings)integernom=0,denom=1assert(s[1..2]="0.")fori=3tolength(s)dointegerch=s[i]assert(ch>='0'andch<='9')nom=nom*10+ch-'0'denom*=10endforreturnsq_div({nom,denom},gcd(nom,denom))endfunction?decrat("0.9054054")?decrat("0.518518")?decrat("0.75")
Output:
{4527027,5000000}{259259,500000}{3,4}

PHP

Works with:PHP version 5.3+
functionasRational($val,$tolerance=1.e-6){if($val==(int)$val){// integerreturn$val;}$h1=1;$h2=0;$k1=0;$k2=1;$b=1/$val;do{$b=1/$b;$a=floor($b);$aux=$h1;$h1=$a*$h1+$h2;$h2=$aux;$aux=$k1;$k1=$a*$k1+$k2;$k2=$aux;$b=$b-$a;}while(abs($val-$h1/$k1)>$val*$tolerance);return$h1.'/'.$k1;}echoasRational(1/5)."\n";// "1/5"echoasRational(1/4)."\n";// "1/4"echoasRational(1/3)."\n";// "1/3"echoasRational(5)."\n";// "5"

PL/I

(size, fofl):Convert_Decimal_To_Rational: procedure options (main); /* 14 January 2014, from Ada */Real_To_Rational: procedure (R, Bound, Numerator, Denominator) recursive         options (reorder);   declare R float (18), Bound float,          (Numerator, Denominator) fixed binary (31);   declare Error float;   declare Best fixed binary initial (1);   declare Best_Error float initial (huge(error));   declare I fixed binary (31);   if R = 0 then      do;         Numerator   = 0;         Denominator = 1;         return;      end;   else if R < 0 then      do;         call Real_To_Rational(-R, Bound, Numerator, Denominator);         Numerator = -Numerator;         return;      end;   else      do I = 1 to Bound;         Error = abs(I * R - trunc(I * R + sign(R)*0.5));         if Error < Best_Error then            do;               Best = I;               Best_Error = Error;            end;      end;   Denominator = Best;   Numerator   = Denominator * R + sign(R) * 0.5;end Real_To_Rational;   declare (Num, Denom) fixed binary (31);   declare R float (18);   declare I fixed BINARY;   do R = 0.75, 0.25,   0.3333333,   0.518518000,  0.905405400,          0.142857143,  3.141592654, 2.718281828, -0.423310825,          31.415926536, 0;      put skip edit(R) (f(13,9));      do I = 0 to 4;         call Real_to_Rational(R, 10**I, Num, Denom);         put edit('   ' || trim(Num) || ' / ' || trim(Denom)) (a);      end;   end;end Convert_Decimal_To_Rational;

Output:

  0.750000000   1 / 1   3 / 4   3 / 4   3 / 4   3 / 4  0.250000000   0 / 1   1 / 4   1 / 4   1 / 4   1 / 4  0.333333300   0 / 1   1 / 3   1 / 3   1 / 3   1 / 3  0.518518000   1 / 1   1 / 2   14 / 27   14 / 27   14 / 27  0.905405400   1 / 1   9 / 10   67 / 74   67 / 74   67 / 74  0.142857143   0 / 1   1 / 7   1 / 7   1 / 7   1 / 7  3.141592654   3 / 1   22 / 7   22 / 7   355 / 113   355 / 113  2.718281828   3 / 1   19 / 7   193 / 71   1457 / 536   25946 / 9545 -0.423310825   0 / 1   -3 / 7   -11 / 26   -69 / 163   -1253 / 2960 31.415926536   31 / 1   157 / 5   377 / 12   3550 / 113   208696 / 6643  0.000000000   0 / 1   0 / 1   0 / 1   0 / 1   0 / 1

Pluto

Library:Pluto-rat
Library:Pluto-fmt
require"rat"localfmt=require"fmt"localtests={0.9054054,0.518518,0.75}fortestsastestdolocalr=rat.decimal(test)fmt.print("%-9s -> %s",test,r)end
Output:
0.9054054 -> 4527027/50000000.518518  -> 259259/5000000.75      -> 3/4

PureBasic

Procedure.iggT(a.i,b.i)Definet.i:Ifa<b:Swapa,b:EndIfWhilea%b:t=a:a=b:b=t%a:Wend:ProcedureReturnbEndProcedureProcedure.sDec2Rat(dn.d)Definenk$,gt.i,res$nk$=Trim(StringField(StrD(dn),2,"."),"0")gt=ggT(Val(nk$),Int(Pow(10.0,Len(nk$))))res$=Str(Val(nk$)/gt)+"/"+Str(Int(Pow(10.0,Len(nk$)))/gt)ProcedureReturnres$EndProcedureOpenConsole()Defined.dRepeatRead.dd:IfNot(d>0.0Andd<1.0):Break:EndIfPrint(LSet(StrD(d),15," ")+" -> "+#TAB$+Dec2Rat(d)+#CRLF$)ForEverInput():EndDataSectionData.d0.9054054,0.518518,0.75,0.0EndDataSection
0.9054054       ->      4527027/50000000.518518        ->      259259/5000000.75            ->      3/4

Python

Works with:Python version 2.6+

Note that the decimal values of the task description are truncated in some cases.

The first loop limits the size of the denominator, because the floating-point representation is not exact. The second converts the string representation of the given values directly to fractions.

>>>fromfractionsimportFraction>>>fordin(0.9054054,0.518518,0.75):print(d,Fraction.from_float(d).limit_denominator(100))0.905405467/740.51851814/270.753/4>>>fordin'0.9054054 0.518518 0.75'.split():print(d,Fraction(d))0.90540544527027/50000000.518518259259/5000000.753/4>>>


Or, writing our ownapproxRatio function:

Works with:Python version 3.7
'''Approximate rationals from decimals'''frommathimport(floor,gcd)importsys# approxRatio :: Float -> Float -> RatiodefapproxRatio(epsilon):'''The simplest rational approximation to       n within the margin given by epsilon.    '''defgcde(e,x,y):def_gcd(a,b):returnaifb<eelse_gcd(b,a%b)return_gcd(abs(x),abs(y))returnlambdan:(lambdac=(gcde(epsilonif0<epsilonelse(0.0001),1,n)):ratio(floor(n/c))(floor(1/c)))()# main :: IO ()defmain():'''Conversions at different levels of precision.'''xs=[0.9054054,0.518518,0.75]print(fTable(__doc__+' (epsilon of 1/10000):\n')(str)(lambdar:showRatio(r)+' -> '+repr(fromRatio(r)))(approxRatio(1/10000))(xs))print('\n')e=minBound(float)print(fTable(__doc__+' (epsilon of '+repr(e)+'):\n')(str)(lambdar:showRatio(r)+' -> '+repr(fromRatio(r)))(approxRatio(e))(xs))# GENERIC -------------------------------------------------# fromRatio :: Ratio Int -> FloatdeffromRatio(r):'''A floating point value derived from a       a rational value.    '''returnr.get('numerator')/r.get('denominator')# minBound :: Bounded Type -> adefminBound(t):'''Minimum value for a bounded type.'''maxsize=sys.maxsizefloat_infomin=sys.float_info.minreturn{int:(-maxsize-1),float:float_infomin,bool:False,str:chr(0)}[t]# ratio :: Int -> Int -> Ratio Intdefratio(n):'''Rational value constructed       from a numerator and a denominator.    '''defgo(n,d):g=gcd(n,d)return{'type':'Ratio','numerator':n//g,'denominator':d//g}returnlambdad:go(n*signum(d),abs(d))# showRatio :: Ratio -> StringdefshowRatio(r):'''String representation of the ratio r.'''d=r.get('denominator')returnstr(r.get('numerator'))+(' / '+str(d)if1!=delse'')# signum :: Num -> Numdefsignum(n):'''The sign of n.'''return-1if0>nelse(1if0<nelse0)# DISPLAY -------------------------------------------------# fTable :: String -> (a -> String) ->#                     (b -> String) -> (a -> b) -> [a] -> StringdeffTable(s):'''Heading -> x display function -> fx display function ->                     f -> xs -> tabular string.    '''defgo(xShow,fxShow,f,xs):ys=[xShow(x)forxinxs]w=max(map(len,ys))returns+'\n'+'\n'.join(map(lambdax,y:y.rjust(w,' ')+' -> '+fxShow(f(x)),xs,ys))returnlambdaxShow:lambdafxShow:lambdaf:lambdaxs:go(xShow,fxShow,f,xs)# MAIN ---if__name__=='__main__':main()
Output:
Approximate rationals from decimals (epsilon of 1/10000):0.9054054 -> 67 / 74 -> 0.9054054054054054 0.518518 -> 14 / 27 -> 0.5185185185185185     0.75 -> 3 / 4 -> 0.75Approximate rationals from decimals (epsilon of 2.2250738585072014e-308):0.9054054 -> 4077583422059235 / 4503599627370496 -> 0.9054054 0.518518 -> 2335197471584895 / 4503599627370496 -> 0.518518     0.75 -> 3 / 4 -> 0.75

R

ratio<-function(decimal){denominator=1while(nchar(decimal*denominator)!=nchar(round(decimal*denominator))){denominator=denominator+1}str=paste(decimal*denominator,"/",sep="")str=paste(str,denominator,sep="")return(str)}
Output:
> ratio(.75)[1] "3/4"> ratio(0.9054054)[1] "4527027/5e+06"> ratio(3.14)[1] "157/50"

Quackery

Using the Quackery big number rational arithmetic librarybigrat.qky.

[ $ "bigrat.qky" loadfile ] now!  [ dup echo$     say " is "    $->v drop    dup 100 > if       [ say "approximately "        proper 100 round        improper ]    vulgar$ echo$     say "." cr ]     is task ( $ --> )$ "0.9054054 0.518518 0.75" nest$ witheach task
Output:
0.9054054 is approximately 67/74.0.518518 is approximately 14/27.0.75 is 3/4.

Racket

Racket has builtin exact and inexact representantions of numbers, 3/4 is a valid number syntactically, and one can change between the exact and inexact values with the functions showed in the example.They have some amount of inaccuracy, but i guess it can be tolerated.

#langracket(inexact->exact0.75); -> 3/4(exact->inexact3/4); -> 0.75(exact->inexact67/74); -> 0.9054054054054054(inexact->exact0.9054054054054054);-> 8155166892806033/9007199254740992

Raku

(formerly Perl 6)Decimals are natively represented as rationals in Raku, so if the task does not need to handle repeating decimals, it is trivially handled by the.nude method, which returns the numerator and denominator:

say .nude.join('/')for0.9054054,0.518518,0.75;
Output:
4527027/5000000259259/5000003/4

However, if we want to take repeating decimals into account, then we can get a bit fancier.

subdecimal_to_fraction (Str$n,Int$rep_digits =0 )returnsStr {my ($int,$dec ) = ($n ~~ /^ (\d+) \. (\d+) $/ )».Strordie;my ($numer,$denom ) = ($dec,10 **$dec.chars );if$rep_digits {my$to_move =$dec.chars -$rep_digits;$numer -=$dec.substr(0,$to_move);$denom -=10 **$to_move;    }my$rat =Rat.new($numer.Int,$denom.Int ).nude.join('/');return$int >0 ??"$int $rat" !!$rat;}my@a = ['0.9054',3], ['0.518',3], ['0.75',0], | (^4).map({['12.34567',$_]});for@a -> [$n,$d ] {say"$n with $d repeating digits = ",decimal_to_fraction($n,$d );}
Output:
0.9054 with 3 repeating digits = 67/740.518 with 3 repeating digits = 14/270.75 with 0 repeating digits = 3/412.34567 with 0 repeating digits = 12 34567/10000012.34567 with 1 repeating digits = 12 31111/9000012.34567 with 2 repeating digits = 12 17111/4950012.34567 with 3 repeating digits = 12 1279/3700

REXX

version 1

This REXX example supports almost any form of numeric input,   some examples are:

  •   ±nnn
  •   ±nnn.
  •   ±nnn.fff
  •   ±.fff
  •   ±nnnE±ppp
  •  .fffE±ppp
  •   ±nnn.fffE±ppp       (with an uppercase exponent signifier)
  •   ±nnn.fffe±ppp       (with an lowercase exponent signifier)
  •   numeratorNumber/denominatorNumber
  •   denominator is optional   (but if a  /   is used, it must be present)
  •   superfluous blanks are permitted (for whitespace)
  •   leading zeroes are permitted
  •   leading signs are permitted
  •   improper fractions are permitted

─── where:

  • nnn   represent decimal digits before the decimal point (if there is one)
  • fff     represent decimal digits   after   the decimal point (if there is one)
  • ppp   represent decimal digits of the (base ten) exponent
  •  ±     represent an optional (leading) sign, either  +   or  -
  •  .       if it's trailing, the decimal point is optional


REXX can support almost any number of decimal digits, but  10   was chosen for practicality for this task.

/*REXX program converts a rational fraction  [n/m]  (or  nnn.ddd)  to it's lowest terms.*/numericdigits10/*use ten decimal digits of precision. */parseargorig1n.1"/"n.2;ifn.2=''thenn.2=1/*get the fraction.*/ifn.1=''thencaller'no argument specified.'doj=1for2;if\datatype(n.j,'N')thencaller"argument isn't numeric:"n.jend/*j*//* [↑]  validate arguments:  n.1  n.2  */ifn.2=0thencaller"divisor can't be zero."/*Whoa!   We're dividing by zero !     */say'old ='space(orig)/*display the original fraction.       */say'new ='rat(n.1/n.2)/*display the result ──► terminal.     */exit/*stick a fork in it,  we're all done. *//*──────────────────────────────────────────────────────────────────────────────────────*/er:say;say'***error***';say;sayarg(1);say;exit13/*──────────────────────────────────────────────────────────────────────────────────────*/rat:procedure;parseargx1_x,y;ify==''theny=10**(digits()-1)b=0;g=0;a=1;h=1/* [↑]    Y   is the tolerance.*/dowhilea<=y&g<=y;n=trunc(_x)_=a;a=n*a+b;b=__=g;g=n*g+h;h=_ifn=_x|a/g=xthendo;ifa>y|g>ytheniterateb=a;h=g;leaveend_x=1/(_x-n)end/*while*/ifh==1thenreturnb/*don't return number  ÷  by 1.*/returnb'/'h/*proper or improper fraction. */

output   when using various inputs (which are displayed as part of the output):
(Multiple runs are shown, outputs are separated by a blank line.)

old = 0.9054054054new = 67/74old = 0.5185185185new = 14/27old = 0.75new = 3/4old = 0.905405400new = 693627417/766095958old = 0.9054054054new = 67/74old = 0.1428571428new = 1/7

version 2

/*REXX program to convert decimal numbers to fractions ***************** 15.08.2012 Walter Pachl derived from above for readability* It took me time to understand :-) I need descriptive variable names* Output shows where the fraction only approximates the number* due to the limit (high) imposed on nominator and denominator**********************************************************************/NumericDigits10/* use "only" 10 digs of precision */Calltest'0.9054054054','67/74'Calltest'0.5185185185','14/27'Calltest'0.75','3/4'Calltest'0.905405400',' 693627417/766095958'Calltest'0.9054054054','67/74'Calltest'0.1428571428','1/7'Calltest'35.000','35'Calltest'35.001','35001/1000'Calltest'0.00000000001','?'Calltest'0.000001000001','1/999999'Exittest:/*********************************************************************** Test driver for rat**********************************************************************/ParseArgd,fs/* number and expected fraction */fh=rat(d)/* convert number to fracrion   */Callo'  'dfhIffh<>fsThenCallo'                   not='fsinterpret'x='fh/* compute value of fraction    */Ifx<>dThen/* not exactly equal to number  */Callo'> '||x'is different'Callo' 'Returno:Sayarg(1);Returnrat:procedure/*********************************************************************** rat(number<,high) returns a fraction or an integer that is equal to* or approximately equal to number.* Nominator and denominator must not have more than high digits* 15.08.2012 Walter Pachl derived from Version 1**********************************************************************/parseargin,highx=in/* working copy               */ifhigh==''thenhigh=10**(digits()-1)/* maximum nominator/denominator */nom=0/* start values nominator     */den=1/*              denominator   */tnom=1/*         temp nominator     */tden=0/*         temp denominator   */doWhiletnom<=high&tden<=high/* nominator... not too large */n=trunc(x)/* take integer part of x     */z=tnom;/* save temp nominator        */tnom=n*tnom+nom;/* compute new temp nominator */nom=z/* assign nominator           */z=tden;/* save temp denominator      */tden=n*tden+den/* compute new temp denominato*/den=z/* assign denominator         */ifn=x|tnom/tden=inthendoiftnom>high|tden>highthen/* temp value(s) too large    */Leave/* don't use them             */nom=tnom/* otherwise take them as     */den=tden/* final values               */leave/* and end the loop           */endx=1/(x-n)/* compute x for next round   */endifden=1thenreturnnom/* denominator 1: integer     */returnnom'/'den/* otherwise a fraction       */

Output:

  0.9054054054 67/74  0.5185185185 14/27  0.75 3/4  0.905405400 693627417/766095958> 0.9054053996 is different  0.9054054054 67/74  0.1428571428 1/7> 0.1428571429 is different  35.000 35  35.001 35001/1000  0.00000000001 0                   not=?> 0 is different  0.000001000001 1/999999

version 3

/* REXX ---------------------------------------------------------------* 13.02.2014 Walter Pachl* specify the number as xxx.yyy(pqr) pqr is the period*        for the number xxx.yyypqrpqrpqrpqrpqr...*--------------------------------------------------------------------*/NumericDigits100Calltest'5.55555','111111/20000'Calltest'3','3'Calltest'0.03','3/100'Calltest'0.9(054)','67/74'Calltest'0.(3)','1/3'Calltest'5.28(571428)','37/7'Calltest'5.28(571428)','38/7 (demonstrate error case)'Calltest'0.(518)','14/27'Calltest'0.75','3/4'Calltest'0.(142857)','1/7'Calltest'0.1(428571)','1/7'Calltest'35.000','35'Calltest'35.001','35001/1000'Calltest'0.00000000001','1/100000000000'Calltest'0.000001000001','1000001/1000000000000'Exittest:ParseArgz,sollzin=zIfpos('(',z)=0ThenDoParseVarzi'.'fz=i||fn=10**length(f)EndElseDolp=pos('(',z)-3rp=pos(')',z)-4x=space(translate(z,'  ','()'),0)z1=x*10**lpParseVarz1z1'.'z2=x*10**rpz=z2-z1n=10**rp-10**lpEnddd=gcd(z,n)zz=z/ddnn=n/ddIfnn=1Thenfract=zzElsefract=zz'/'nnIffract==sollThentag='ok'Elsetag='should be'sollsayzin'='fracttagReturnGCD:procedure/*********************************************************************** Recursive procedure**********************************************************************/ParseArga,bifb=0thenreturnabs(a)returnGCD(b,a//b)

Output:

5.55555 = 111111/20000 ok3 = 3 ok0.03 = 3/100 ok0.9(054) = 67/74 ok0.(3) = 1/3 ok5.28(571428) = 37/7 ok5.28(571428) = 37/7 should be 38/7 (demonstrate error case)0.(518) = 14/27 ok0.75 = 3/4 ok0.(142857) = 1/7 ok0.1(428571) = 1/7 ok35.000 = 35 ok35.001 = 35001/1000 ok0.00000000001 = 1/100000000000 ok0.000001000001 = 1000001/1000000000000 ok

RPL

Starting with HP-48 versions, the conversion can be performed directly with the→Q instruction. Earlier versions must instead use the following code, which is based on continued fractions.

Works with:Halcyon Calc version 4.2.8
RPL codeComment
 ≪   ABS LAST SIGN 1E6 → sign dmax  ≪ (0,1) (1,0)DO        SWAP OVER 4 ROLL INV IP         LAST FP 5 ROLLD        * +UNTIL DUP2 IM SWAP IM * dmax >           4 PICK dmax INV < OREND     ROT ROT DROP2     "'" OVER RE sign * →STR + "/" +     SWAP IM →STR + STR→  ≫ ≫ '→PQ' STO
→PQ( x → 'p/q' )store sign(x) and max denominatora(0) = x ; hk(-2) = (0,1) ; hk(-1) = (1,0)loop  reorder int(a(n)), hk(n-1) and hk(n-2) in stack  a(n+1)=1/frac(a(n)) back to top of stack  hk(n) = a(n)*hk(n-1) + hk(n-2) until k(n)*(kn-1) > max denominator or      a(n+1) > max denominatorclean stackconvert a(n) from (p,q) to 'p/q' formatreturn 'p/q'
.518518→PQ.905405405405→PQ-3.875→PQ

Output:

 3: '37031/71417' 2: '67/74' 1: '-31/8'

Ruby

Works with:Ruby version 1.9+

Note that the decimal values of the task description are truncated in some cases.

This converts the string representation of the given values directly to fractions.

>'0.9054054 0.518518 0.75'.split.each{|d|puts"%s %s"%[d,Rational(d)]}0.90540544527027/50000000.518518259259/5000000.753/4=>["0.9054054","0.518518","0.75"]

This loop finds the simplest fractions within a given radius, because the floating-point representation is not exact.

[0.9054054,0.518518,0.75].each{|f|puts"#{f}#{f.rationalize(0.0001)}"}# =>0.9054054 67/74# =>0.518518 14/27# =>0.75 3/4
Works with:Ruby version 2.1.0+

A suffix for integer and float literals was introduced:

2.1.0p0 :001 > 0.9054054r => (4527027/5000000) 2.1.0p0 :002 > 0.518518r => (259259/500000) 2.1.0p0 :003 > 0.75r => (3/4)

Rust

extern crate rand;extern crate num;use num::Integer;use rand::Rng;fn decimal_to_rational (mut n : f64) -> [isize;2] {    //Based on Farey sequences    assert!(n.is_finite());    let flag_neg  = n < 0.0;    if flag_neg { n = n*(-1.0) }    if n < std::f64::MIN_POSITIVE { return [0,1] }    if (n - n.round()).abs() < std::f64::EPSILON { return [n.round() as isize, 1] }    let mut a : isize = 0;    let mut b : isize = 1;    let mut c : isize = n.ceil() as isize;    let mut d : isize = 1;    let aux1 = isize::max_value()/2;    while c < aux1  && d < aux1 {        let aux2 : f64 = (a as f64 + c as f64)/(b as f64 + d as f64);        if (n - aux2).abs() < std::f64::EPSILON { break }         if n > aux2 {             a = a + c;            b = b + d;        } else {            c = a + c;            d = b + d;        }    }    // Make sure that the fraction is irreducible    let gcd = (a+c).gcd(&(b+d));    if flag_neg { [-(a + c)/gcd, (b + d)/gcd] } else { [(a + c)/gcd, (b + d)/gcd] }} #[test]fn test1 () {    // Test the function with 1_000_000 random decimal numbers    let mut rng = rand::thread_rng();    for _i in 1..1_000_000 {        let number = rng.gen::<f64>();        let result = decimal_to_rational(number);        assert!((number - (result[0] as f64)/(result[1] as f64)).abs() < std::f64::EPSILON);        assert!(result[0].gcd(&result[1]) == 1);    }}fn main () {    let mut rng = rand::thread_rng();    for _i in 1..10 {        let number = rng.gen::<f64>();        let result = decimal_to_rational(number);        if result[1] == 1 { println!("{} -> {}", number, result[0]) } else { println!("{} ->  {}/{}", number, result[0], result[1]) }    }    for i in [-0.9054054, 0.518518, -0.75, 0.5185185185185185, -0.9054054054054054, 0.0, 1.0, 2.0].iter() {        let result = decimal_to_rational(*i as f64);        if result[1] == 1 { println!("{} = {}",*i, result[0]) } else { println!("{} =  {}/{}", *i, result[0], result[1]) }    }}

First test the function with 1_000_000 random double floats :

running 1 testtest test1 ... oktest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Now run it with 10 random double floats and some selected ones printing the results

0.47783621261626297 -> 36036136/754152470.29135687639237284 -> 164756020/5654783990.04962905490905656 -> 4105111/827158810.33418703921783965 -> 16612678/497107190.07284921759788943 -> 6252865/858329740.783712619202954 -> 62096920/792342990.3788902482801324 -> 30401287/802377130.03780115715370047 -> 1522201/402686350.9975233883406127 -> 79858287/80056556-0.9054054 ->  -4527027/50000000.518518 ->  259259/500000-0.75 ->  -3/40.5185185185185185 ->  14/27-0.9054054054054054 ->  -67/740 -> 01 -> 12 -> 2

Scala

Output:

Best seen running in your browserScastie (remote JVM).

importorg.apache.commons.math3.fraction.BigFractionobjectNumber2FractionextendsApp{valn=Array(0.750000000,0.518518000,0.905405400,0.142857143,3.141592654,2.718281828,-0.423310825,31.415926536)for(d<-n)println(f"$d%-12s :${newBigFraction(d,0.00000002D,10000)}%s")}

Seed7

The librarybigrat.s7idefines the functionbigRational,which creates abigRational number from a string.This function accepts, besides fractions, also a decimal number with repeating decimals.Internally a bigRational uses numerator and denominator to represent a rational number.Writing a bigRational does not create a fraction with numerator and denominator, but a decimal number with possibly repeating decimals.The functionfractionuses numerator and denominator from the bigRational number to get a string with the fraction.

$ include "seed7_05.s7i";  include "bigrat.s7i";const proc: main is func  begin    writeln(bigRational parse "0.9(054)");    writeln(bigRational parse "0.(518)");    writeln(bigRational parse "0.75");    writeln(bigRational parse "3.(142857)");    writeln(bigRational parse "0.(8867924528301)");    writeln(bigRational parse "0.(846153)");    writeln(bigRational parse "0.9054054");    writeln(bigRational parse "0.518518");    writeln(bigRational parse "0.14285714285714");    writeln(bigRational parse "3.14159265358979");    writeln(bigRational parse "2.718281828");    writeln(bigRational parse "31.415926536");    writeln(bigRational parse "0.000000000");        writeln;    writeln(fraction(bigRational("0.9(054)")));    writeln(fraction(bigRational("0.(518)")));    writeln(fraction(bigRational("0.75")));    writeln(fraction(bigRational("3.(142857)")));    writeln(fraction(bigRational("0.(8867924528301)")));    writeln(fraction(bigRational("0.(846153)")));    writeln(fraction(bigRational("0.9054054")));    writeln(fraction(bigRational("0.518518")));    writeln(fraction(bigRational("0.14285714285714")));    writeln(fraction(bigRational("3.14159265358979")));    writeln(fraction(bigRational("2.718281828")));    writeln(fraction(bigRational("31.415926536")));    writeln(fraction(bigRational("0.000000000")));  end func;
Output:
0.9(054)0.(518)0.753.(142857)0.(8867924528301)0.(846153)0.90540540.5185180.142857142857143.141592653589792.71828182831.4159265360.067/7414/273/422/747/5311/134527027/5000000259259/5000007142857142857/50000000000000314159265358979/100000000000000679570457/2500000003926990817/1250000000/1

Sidef

By default, literal numbers are represented in rational form:

say0.75.as_frac#=> 3/4say0.518518.as_frac#=> 259259/500000say0.9054054.as_frac#=> 4527027/5000000

Additionally,Num(str) can be used for parsing a decimal expansion into rational form:

'0.9054054 0.518518 0.75'.split.each{|str|sayNum(str).as_frac}
Output:
4527027/5000000259259/5000003/4

For rational approximations, the Number.rat_approx method can be used:

say0.518518.rat_approx.as_frac#=> 14/27say0.9054054.rat_approx.as_frac#=> 67/74

TAV

From floating point number

\( convert float to rational (built-in)   rationals are automatically reduced and converted to integer if possible\)main(parms):+  inp =: 0.009054054, 0.518518, 0.75, -3.141592, 12.0319272, 230.0  for f =: tuple inp give values    print f, '=', float f as rational    \ not (yet) in the standard library:float (@) as rational:  m, e =: float @ split decimal     \ library function does the work  return m * 10^e
Output:
0.00905405 = 4527027/5000000000.518518 = 259259/5000000.75 = 3/4-3.14159 = -392699/12500012.0319 = 15039909/1250000230.0 = 230

From string

\( convert decimal string to reduced rational and print\)main(parms):+  inp =: "0.009054054", "0.518518", "0.752", "-3.141592", "12.0319272", "30.0"  for f =: tuple inp give values    r =: string f as pair    print f, '=', join r by '/'\ convert decimal number from string to numerator and denominatorstring (str) as pair:  intfrac =: string str split by '.'  ? intfrac.Count ~= 2    :> str                      \ nor  single decimal point  int =: string intfrac.1 as integer  frac =: string intfrac.2 as integer  den =: 10^(intfrac.2.Count)  num =: int * den + frac  gcd =: integer den, num gcd  ? gcd > 1    num =: num // gcd    den =: den // gcd  :> num,  den
Output:
0.009054054 = 4527027/5000000000.518518 = 259259/5000000.752 = 94/125-3.141592 = -357301/12500012.0319272 = 15039909/125000030.0 = 30/1

Tcl

Works with:Tcl version 8.4+

Here is a complete script with the implemented function and a small test suite (which is executed when this script is called directly from a shell) - originally onhttp://wiki.tcl.tk/752:

#!/usr/bin/env tclshprocdbl2frac{dbl{eps0.000001}}{for{setden1}{$den<1024}{incrden}{setnum[expr{round($dbl*$den)}]if{abs(double($num)/$den-$dbl)<$eps}break}list$num$den}#-------------------- That's all... the rest is the test suiteif{[filetail$argv0]eq[filetail[infoscript]]}{foreach{test->expected}{{dbl2frac0.518518}->{4281}{dbl2frac0.75}->{34}{dbl2frac0.9054054}->{6774}}{catch$testresif{$resne$expected}{puts"$test -> $res, expected $expected"}}}

Running it shows one unexpected result, but on closer examination it is clear that 14/27 equals 42/81, so it should indeed be the right solution:

~ $ fractional.tcldbl2frac 0.518518 -> 14 27, expected 42 81~ $

TI SR-56

Texas Instruments SR-56 Program Listing for "Convert decimal number to rational"
DisplayKeyDisplayKeyDisplayKeyDisplayKey
00 33STO25 0005075
01 00026 64*5176
02 00027 34RCL5277
03 33STO28 0115378
04 01129 94=5479
05 56*CP30 41R/S5580
06 011315681
07 35SUM325782
08 011335883
09 34RCL345984
10 011356085
11 64*366186
12 34RCL376287
13 000386388
14 94=396489
15 12Inv406590
16 29*Int416691
17 12Inv426792
18 37*x=t436893
19 000446994
20 066457095
21 34RCL467196
22 011477297
23 32x<>t487398
24 34RCL497499

Asterisk denotes 2nd function key.

Register allocation
0: Decimal1: Denominator2: Unused3: Unused4: Unused
5: Unused6: Unused7: Unused8: Unused9: Unused

Annotated listing:

STO 0                      // Decimal := User Input0 STO 1                    // Denominator := 0*CP                        // RegT := 01 SUM 1                    // Denominator += 1RCL 1 * RCL 0 = Inv *Int   // Find fractional part of Decimal * DenominatorInv *x=t 0 6               // If it is nonzero loop back to instruction 6RCL 1 x<>t                 // Report denominatorRCL 0 * RCL 1 =            // Report numeratorR/S                        // End

Usage:

Enter the decimal and then press RST R/S. Once a suitable rational is found, the numerator will be displayed. Press x<>t to toggle between the numerator and denominator.

Input:

0.875 RST R/S

Output:

After about five seconds,3 will appear on the screen. Press x<>t and8 will appear on the screen. The fraction is 3/8.

Any fraction with denominator <=100 is found in 1 minute or less. 100 denominators are checked per minute.

Vala

Translation of:C
structFraction{publiclongd;publiclongn;}Fractionrat_approx(doublef,longmd){longa;long[]h={0,1,0};long[]k={1,0,0};longx,d,n=1;boolneg=false;if(md<=1)return{1,(long)f};if(f<0){neg=true;f=-f;}while(f!=Math.floor(f)){n<<=1;f*=2;}d=(long)f;for(inti=0;i<64;i++){a=(n!=0)?d/n:0;if(i!=0&&a==0)break;x=d;d=n;n=x%n;x=a;if(k[1]*a+k[0]>=md){x=(md-k[0])/k[1];if(x*2>=a||k[1]>=md)i=65;elsebreak;}h[2]=x*h[1]+h[0];h[0]=h[1];h[1]=h[2];k[2]=x*k[1]+k[0];k[0]=k[1];k[1]=k[2];}return{k[1],neg?-h[1]:h[1]};}voidmain(){doublef;print("f = %16.14f\n",f=1.0/7);for(inti=1;i<20000000;i*=16){print("denom <= %11d: ",i);varr=rat_approx(f,i);print("%11ld/%ld\n",r.n,r.d);}print("f = %16.14f\n",f=Math.atan2(1,1)*4);for(inti=1;i<20000000;i*=16){print("denom <= %11d: ",i);varr=rat_approx(f,i);print("%11ld/%ld\n",r.n,r.d);}}
Output:
f = 0.14285714285714denom <=           1:           0/1denom <=          16:           1/7denom <=         256:           1/7denom <=        4096:           1/7denom <=       65536:           1/7denom <=     1048576:           1/7denom <=    16777216:           1/7f = 3.14159265358979denom <=           1:           3/1denom <=          16:          22/7denom <=         256:         355/113denom <=        4096:         355/113denom <=       65536:      104348/33215denom <=     1048576:     3126535/995207denom <=    16777216:    47627751/15160384

VBA

Translation of:D
FunctionReal2Rational(rAsDouble,boundAsLong)AsStringIfr=0ThenReal2Rational="0/1"ElseIfr<0ThenResult=Real2Rational(-r,bound)Real2Rational="-"&ResultElsebest=1bestError=1E+99Fori=1Tobound+1currentError=Abs(i*r-Round(i*r))IfcurrentError<bestErrorThenbest=ibestError=currentErrorIfbestError<1/boundThenGoToSkipLoopEndIfNextiSkipLoop:Real2Rational=Round(best*r)&"/"&bestEndIfEndFunctionSubTestReal2Rational()Debug.Print"0.75"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(0.75,CLng(Order));NextiDebug.PrintDebug.Print"0.518518"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(0.518518,CLng(Order));NextiDebug.PrintDebug.Print"0.9054054"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(0.9054054,CLng(Order));NextiDebug.PrintDebug.Print"0.142857143"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(0.142857143,CLng(Order));NextiDebug.PrintDebug.Print"3.141592654"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(3.141592654,CLng(Order));NextiDebug.PrintDebug.Print"2.718281828"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(2.718281828,CLng(Order));NextiDebug.PrintDebug.Print"-0.423310825"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(-0.423310825,CLng(Order));NextiDebug.PrintDebug.Print"31.415926536"&":";Fori=0To5Order=CDbl(10)^CDbl(i)Debug.Print" "&Real2Rational(31.415926536,CLng(Order));NextiEndSub
Output:
0.75: 1/1 3/4 3/4 3/4 3/4 3/40.518518: 1/1 1/2 14/27 14/27 14/27 37031/714170.9054054: 1/1 1/1 67/74 67/74 67/74 67/740.142857143: 0/1 1/7 1/7 1/7 1/7 1/73.141592654: 3/1 22/7 22/7 355/113 355/113 104348/332152.718281828: 3/1 19/7 193/71 1457/536 23225/8544 173459/63812-0.423310825: -0/1 -3/7 -11/26 -69/163 -1253/2960 -10093/2384331.415926536: 31/1 157/5 377/12 3550/113 208696/6643 1563445/49766

Wren

Library:Wren-rat
Library:Wren-fmt
import"./rat"forRatimport"./fmt"forFmtvartests=[0.9054054,0.518518,0.75]for(testintests){varr=Rat.fromFloat(test)System.print("%(Fmt.s(-9,test)) ->%(r)")}
Output:
0.9054054 -> 4527027/50000000.518518  -> 259259/5000000.75      -> 3/4

zkl

Translation of:D
fcn real2Rational(r,bound){   if (r == 0.0) return(0,1);   if (r < 0.0){      result := real2Rational(-r, bound);      return(-result[0],result[1]);   } else {      best,bestError := 1,(1.0).MAX;      foreach i in ([1 .. bound + 1]){         error := (r*i - (r*i).round()).abs(); if (error < bestError) best,bestError = i,error;      }      return((r*best).round().toInt(),best);   }}
tests := T(0.750000000,  0.518518000, 0.905405400,   0.142857143,  3.141592654, 2.718281828,  -0.423310825, 31.415926536);foreach r in (tests) {   print("%8.9f  ".fmt(r));   foreach i in (6)      { print("  %d/%d".fmt(real2Rational(r,(10).pow(i)).xplode())) }   println();}
Output:
0.750000000    1/1  3/4  3/4  3/4  3/4  3/40.518518000    1/2  1/2  14/27  14/27  14/27  37031/714170.905405400    1/1  10/11  67/74  67/74  67/74  67/740.142857143    0/1  1/7  1/7  1/7  1/7  1/73.141592654    3/1  22/7  22/7  355/113  355/113  104348/332152.718281828    3/1  19/7  193/71  2721/1001  25946/9545  222630/81901-0.423310825    -1/2  -3/7  -11/26  -69/163  -1253/2960  -10093/2384331.415926536    63/2  157/5  3173/101  3550/113  208696/6643  2918194/92889
Retrieved from "https://rosettacode.org/wiki/Convert_decimal_number_to_rational?oldid=395918"
Categories:
Hidden category:
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

[8]ページ先頭

©2009-2026 Movatter.jp