Yuvarlak olmayan kesirler


22

Bir kesiri ondalık sayıya dönüştürdüğünüzde ve bu sayıyı saklamak istediğinizde, sık sık yuvarlamanız gerekir, çünkü yalnızca belirli bir miktarda bellek kullanmak istiyorsunuz. Diyelim ki sadece 5 ondalık basamak saklayabilirsiniz, ardından 5/3 1.6667 olur. Yalnızca 2 ondalık basamak saklayabiliyorsanız, 1.7 olacaktır (şimdi her zaman 0 ile 9,99 arasında olduğu varsayılmaktadır).

Şimdi bu işlemi 1.7 ile tersine çevirmeye çalışırsanız ve kesirinizi geri almak istiyorsanız, 1.7'nin yalnızca yuvarlak bir sayı olduğunu bildiğiniz için bu zor olabilir. Tabii ki 17/10 deneyebilirsiniz, ancak 'zarif' 5/3 ile karşılaştırıldığında oldukça 'çirkin' bir kesir.

Bu nedenle amaç, a / b fraksiyonunu en az b paydaşıyla bulmaktır; bu, doğru yuvarlandığında yuvarlanmış ondalık sayı ile sonuçlanır.

ayrıntılar

Girdi, 0 (dahil) ve 10 (dahil değil) arasında '1' olan 1 - 5 basamaktan oluşan bir dize içerir. ilk haneden sonra. Diyelim ki nrakam sayısını gösterir. Çıktı, iki tamsayıdan oluşan bir liste / dizi [numerator, denominator]veya paytörün negatif olmadığı ve paydanın pozitif olduğu rasyonel bir veri türü (kendinizinkini oluşturabilir veya yerleşik kullanabilirsiniz) olmalıdır. Kesir payı / payda, nbasamağa doğru yuvarlandığında girişe eşit olmalıdır (bu n-1, ondalık basamağın ardından gelen basamaklar anlamına gelir ).

Kısıtlama: sadece bir döngü ifadesine izin verilir. Bu, kodunuzun tamamında yalnızca bir tek döngü ifadesi (benzer forveya whileveya gotovb. Yanı sıra bir listenin / dizinin her öğesine kod uygulayan mapveya folduygulayan) gibi işlevsel döngüler kullanabileceğiniz anlamına gelir , ancak bu kodu 'kötüye kullanma' konusunda özgürsünüz veya özyineleme vb.

Bir fonksiyon yazmalısın. Dilinizde işlev yoksa (veya olsa bile), alternatif olarak girişin bir değişkende (veya stdin aracılığıyla giriş) saklandığını varsayabilir ve sonucu yazdırabilir veya bir dosyaya yazabilirsiniz. En düşük bayt sayısı kazanır.

yuvarlatma

Yuvarlama 'geleneksel' yuvarlama kurallarına uymalıdır, yani kesilecek olan son rakam 5 veya daha büyükse, yuvarlama yapacak ve diğer durumlar için yuvarlama yapacaksınız, örneğin:

4.5494 yuvarlanırken sonuçlanır

  • 1 hane: 5
  • 2 hane: 4.5
  • 3 basamak: 4.55
  • 4 basamak: 4.549

Örnekler

Lütfen aşağıdaki test vakalarını ve diğer 'ilginç' olayları ekleyin:

Input 1.7     Output 5/3
Input 0.      Output 0/1
Input 0.001   Output 1/667
Input 3.1416  Output 355/113

1
Fakat fonksiyonel dillerde döngü diye bir şey yoktur. Haskell'deki foe örneği repeat, argümanının sonsuz bir listesini oluşturur. Döngü gibi görünüyor ama aslında O'nun zaman karmaşıklığı var (1). Ancak, her durumu ayrı ayrı sıralamak, işlevsel dillere izin vermemekten daha iyidir.
Gurur haskeller 23:14

3
Şu anki "loop" tanımını beğenmedim. Python'da, örneğin, for n in numbers: f(g(n))eşdeğerdir map(f, map(g, numbers)). İşlevsel sürüm mapiki kez kullanıyor , buna gerçekten izin verilmiyor mu?
Flornquake

1
@ MartinBüttner belirsizlik yüzünden işlevsel dillerin yasaklanacağı olgusundan bahsettim
gururlu haskeller 23:14

1
İşlevsel programlama hakkındaki bilgilerim temelde sıfır olduğu için bu tartışmaya gerçekten katkı sağlayamadığım için üzgünüm. 'Kurallara' uyup uymadığından emin olmadığınız bir çözümünüz varsa, lütfen yine de gönderin! Sonunda eğlenceli ve eğitici bir meydan okuma olması gerekiyordu!
kusur

2
@Dennis Talihsiz bir ifade değil, dilediğiniz herhangi bir şekilde gönderebilirsiniz, eğer diliniz giriş numarasını 'okumak' için daha fazla bayt alırsa, bu paragrafın arkasındaki ana fikir dezavantajınızın olmaması gerektiğidir.
kusur

Yanıtlar:


4

CJam, 41 40 36 bayt

Q'./1=,:L0\{;)_Qd*mo_d2$/LmOQd-}g'/@

Giriş dizesinin, soru tarafından açıkça izin verilen Q olarak kaydedildiğini varsayar. Çevrimiçi deneyin.

Test durumları

$ for d in 1.7 0. 0.001 3.1416; do cjam <(echo "\"$d\":Q;
> Q'./1=,:L0\{;)_Qd*mo_d2$/LmOQd-}g'/@
> "); echo; done
5/3
0/1
1/667
355/113

Nasıl çalışır

Q'./1=,:L  " Count the number of characters after the dot and store it in L.     ";
0\         " Push 0 (denominator) and swap it with L (dummy value).              ";
{          "                                                                     ";
  ;        " Discard the topmost item from the stack (numerator or dummy value). ";
  )        " Increment the denominator.                                          ";
  _Qd*mo   " Multiply a copy by Double(Q) and round.                             ";
  _d2$/    " Cast a copy to Double and it divide it by the denominator.          ";
  LmO      " Round to L digits.                                                  ";
  Qd       " If the result is not Double(Q),                                     ";
}g         " repeat the loop.                                                    ";
./@        " Push a slash and rotate the denominator on top of it.               ";

15

T-SQL 254

T-SQL bu tür bir şey için gerçekten uygun olmamakla birlikte, denemek eğlenceli olur. Performans, payda arttıkça kötüleşiyor. 1000 payda ile sınırlıdır.

Giriş bir değişken değişkendir @

WITH e AS(SELECT *FROM(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(0))n(n)),t AS(SELECT ROW_NUMBER()OVER(ORDER BY(SELECT \))N FROM e a,e b,e c,e d)SELECT TOP 1concat(n.n,'/',d.n)FROM t d,t n WHERE round(n.n/(d.n+.0),len(parsename(@,1)))=@ ORDER BY d.n,n.n

Sorgunun dökümü

WITH                                      -- Start CTE(Common Table Expression)
 e AS(                                    --Create a set of 10 rows
   SELECT *
   FROM(VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(0))n(n)
 ),
 t AS(                                    
   SELECT ROW_NUMBER()OVER(ORDER BY(SELECT \))N 
   FROM e a,e b,e c,e d                   --Cross join e to produce 1000 numbered rows
 )
SELECT 
  TOP 1                                   --Grab first result
  concat(n.n,'/',d.n)                     --Build output
FROM t d,t n                              --Cross join t against itself for denominator and numerator
WHERE round(
  n.n/(d.n+.0),                           --Force float division with +.0
  len(parsename(@,1))                     --Get rounding length
  )=@                                     --Filter where the rounded result = input
ORDER BY d.n,n.n                          --Order by denominator then numerator

+1. Onu seviyorum. Ben koydum 3.14159ve usulüne uygun bana verdi355/113
Tom Chantler

1
+1 Burada bir SQL dili görmeyi beklemiyordum !!!
kusur

@TomChantler Sonunda demek istediğinden şüpheleniyorum :)
MickyT

@flawr Dürüst olmak gerekirse işe yarayacağını düşünmemiştim .. çok kaba kuvvet yöntemi olsa.
MickyT

12

Haskell, 62 59

Keşke isimler o kadar uzun olmasaydı ...

import Data.Ratio
f s=approxRational(read s)$50/10^length s

bu bir Rationaldeğer döndüren bir işlevdir .

açıklama: işlev approxRationalbir kayan sayı ve kayan bir epsilon alan ve girişin uzaktaki epsilon içindeki en basit rasyonel olanı döndüren bir işlevdir. Temel olarak, şamandıranın en basit yaklaşımını for affedilir hata “mesafesindeki rasyonel bir değere döndürür.

Bu işlevi kullanmamız için kullanalım. Bunun için verilen sayıya yuvarlanan yüzen alanın ne olduğunu bulmamız gerekecek. Sonra bunu approxRationalfonksiyona dahil etmek bize cevabı verecektir.

Örneğin 1.7 deneyelim. 1.7'ye yuvarlanan en düşük seviye 1.65'tir. Herhangi bir düşük 1.7'ye yuvarlamaz. benzer şekilde, 1,7'ye yuvarlanan yüzerlerin üst sınırı 1,75'tir.
Her iki limit de sınırlar +/- 0,05 olan giriş sayılarıdır. bu mesafenin her zaman olduğu kolayca görülebilir 5 * 10 ^ -(the length of the input - 1)(-1 çünkü girişte her zaman bir '.' vardır). buradan kod oldukça basittir.

test durumları:

*Main> map f ["1.7", "0.001", "3.1416"]
[5 % 3,1 % 667,355 % 113]

maalesef "0" da çalışmıyor Zira Haskell'in çözümleyici işlevi .şamandıranın sonunda bir tanımaz . Bu değiştirerek 5 bayt için sabitlenebilir read starafından read$s++"0".


Sahip olması ilginç bir fonksiyon. Normalde, bu tür fonksiyonlar, kesikli sürekli kesir gösterimleri kullanılarak kanıtlanmış bir şekilde en az adımda bir sayıya en iyi rasyonel yaklaşımı bulmak amacıyla mevcuttur. Alternatif olarak, en düşük payda ile bir kesir bulmak daha akademik bir meraktır. Normalde standart bir kütüphane işlevi bulmayı beklemiyorduk.
COTO

4
@COTO Bu Haskell, akademik araştırmalarla dolu.
Gurme haskeller 23:14

7

Ruby, 127 125 bayt

f=->n{b=q=r=(m=n.sub(?.,'').to_r)/d=10**p=n.count('0-9')-1
b=r if(r=(q*d-=1).round.to_r/d).round(p).to_f.to_s==n while d>1
b}

Sonucu a folarak döndüren bir işlevi tanımlar Rational. Örneğin bu kodu eklerseniz

p f["1.7"]
p f["0."]
p f["0.001"]
p f["3.1416"]

Sen almak

(5/3)
(0/1)
(1/667)
(355/113)

Döngü, paydaların üzerindedir. Tam kesirle başlıyorum, örneğin 31416/10000son örnek için. Sonra paydayı azaltıyorum, pay oranını orantılı olarak azaltın (ve yuvarlayın). Elde edilen rasyonel giriş numarası ile aynı yuvarlanırsa, yeni bir en iyi kesri hatırlıyorum.


4

Mathematica, 49 53 karakter

Rationalize[ToExpression@#,5 10^(1-StringLength@#)]&@

Kullanımı:

Rationalize[ToExpression@#,5 10^(1-StringLength@#)]&@"1.7"

Çıktı:

5/3

Test durumları:

input: 1.7     output: 5/3
input: 0.      output: 0
input: 0.001   output: 1/999
input: 3.1416  output: 355/113

0.001 davası bana garip geldi; rasyonelleştirme işlevi, 1/667 vakasını bulamadığında açıklamasına göre çalışmadı. Sayıyı belirtilen sınırlar içinde olan en küçük payda ile vermelidir.


2
haha Ben de aynı çözümü kullandım. Haskell'de çok kötü, daha uzun. btw, çözümünüzün şartname gereği bir girdi olarak aldığı bir dizge gibi görünmüyor.
Gurme haskeller 23:14

Bekle, girdi bir dize miydi? Dang, bu koddan bazı şeyleri çıkarabileceğim anlamına geliyor.
Tally

İçin çıktılarınız 0.001OP Rationalizeile eşleşmiyor çünkü paydayı minimize etmek için kısıtlama altında değil. Gurur haskeller'den bahsettiğim gibi, paydayı en aza indirmeye konu olan rasyonel bir yaklaşım işlevi oldukça ezoteriktir (kısacası, sayıları tahmin etmenin berbat ve verimsiz bir yoludur). Normalde standart bir kütüphane işlevi olmasını beklemiyordum.
COTO

@COTO Docs göre o yok gerçi payda en aza indirir.
Martin Ender

@ MartinBüttner: Çıktıları biraz ilginç 1/999. 999, kabaca 1e-6 ile 2e-6 arasındaki bir hata için (kabul edilebilir) en düşük payda haline gelir. Hata kesin olarak açıkça 5e-4. Öyleyse, Mathematica bu durumda ne yaparsa yapsın, kesinlikle işe yaramadı. : P
COTO

4

Python 2.7+, 111 karakter

Herhangi bir dilde korkunç kod yazabileceğinizi kanıtlayın:

def f(s):
 t,e,y=float(s),50*10**-len(s),1;n=d=x=0
 while x|y:n,d=n+x,d+y;a=1.*n/d;x,y=a<t-e,a>t+e
 return n,d

Çıktı

>>> [f(s) for s in ("1.7", "0.", "0.001", "3.1416")]
[(5, 3), (0, 1), (1, 667), (355, 113)]

3

APL, 50

2↑⍎⍕(⍎x←⍞){50>|(10*⍴x)×⍺-⍵÷⍨n←⌊.5+⍺×⍵:n ⍵⋄''}¨⍳1e5

Saymadığınız sürece evalve toStringdöngüler

açıklama

Yaklaşım, payda olarak 1 ila 10000'ün üzerinde yineleme yapmak ve şamandıranın en yakın eşleşmesini sağlayan payı hesaplamak ve ardından hatanın sınırlar dahilinde olup olmadığını kontrol etmektir. Son olarak, bulunan tüm kesirlerden en küçük çifti seçin.

(⍎x←⍞)Ekrandan dize girişi alın, atayın xve değerlendirin
⍳1e5. 1'den 10000'e kadar dizi üretme Dizinin
{...}¨her elemanı için, onunla işlev çağırın (⍎x←⍞)ve argümanlar (loop)

⍺×⍵Çarpın argümanlar
⌊.5+Yuvarlama (aşağı yuvarlama 0.5 ilave edilerek)
n←Ata n
⍺-⍵÷⍨doğru değişken ile bölünen, daha sonra sol argüman çıkarma
(10*⍴x)×"uzunluğunun gücüne 10 ile Multiply x"
|mutlak değer almak
50>az 50 (uzunluk ise kontrol x2 daha fazla olduğu dp ait, bu yüzden yerine) 0,5 buraya 50 kullanımı No daha.
:n ⍵⋄''bir önceki onay döner doğru, o zaman dizi döndürür nve sağ argüman, başka dönüş boş dize.

⍎⍕ toStringve sonra evaldizideki tüm sayıların bir dizisini elde etmek için
2↑Bulunan ilk sayı -payda çifti olan sadece ilk 2 elemanı seçin.


2

GNU dc, 72 bayt

Döngü yok - dc onlarda bile yok. Bunun yerine, kontrol tek bir özyinelemeli makrodan gelir - dc için deyimsel.

?dXAr^d2*sf*sq1sd0[ld1+sd]sD[r1+r]sN[dlf*ld/1+2/dlq>Ndlq<Dlq!=m]dsmxpldp

Çıktı:

$ for n in 1.7 0. 0.001 3.1416; do echo "    n = $n:"; dc unround.dc <<< $n; done
    n = 1.7:
5
3
    n = 0.:
0
1
    n = 0.001:
1
667
    n = 3.1416:
355
113
$ 

Uf. Bu cevapta kısmi açıklama .


2

Mathematica, 111 karakter

f=Module[{a=0,b=1,k},While[Round[a/b,10^-(StringLength[#]-2)]!=(k=ToExpression)@#,If[N[a/b]>k@#,b++,a++]];a/b]&

Gerçekten oldukça basit, ve pay ve payda birer birer artar, çünkü diğer çözümler kadar hızlı bir yerde bir araya geldiğini sanmıyorum. Bunun için en basit çözümü bulmak isterdim. Diğer cevapları görmeliyim ve orada ne kadar zekice davranırsın.

Çıktı

f/@{"1.7","0.0","0.001","3.1416","3.14"}
{5/3, 0, 1/667, 355/113, 22/7}

Burada kimse Pi Yaklaşım Gününü kutladı mı ?


Hayır, sadece tau yaklaşma gününü kutluyorum. = P Ama | 355/113 - pi | <10 ^ -6 =)
kusurunu farkettim.

2

Uygulama,> 300 bayt

Bunu doğal olarak gerekli olan yuvarlama türünü yapan bir dilde yapmak istedim. Applescript tasarıya uygun çıkıyor. Sonra enum'u gördüm ve rounding as taught in schoolkullanmaya, Applescript'in golf oynamak için kesin bir rekabet gücü olmamasına rağmen, kullanamadım:

on u(q)
    set n to 0
    set d to 1
    set x to 0
    set AppleScript's text item delimiters to "."
    set f to 10 ^ (q's text item 2's length)
    repeat until x = q as real
        set x to (round n * f / d rounding as taught in school) / f
        if x < q then set n to n + 1
        if x > q then set d to d + 1
    end repeat
    return {n, d}
end u

log my u("1.7")
log my u("0.")
log my u("0.001")
log my u("3.1416")

Bu biraz daha golf olabilir, ama muhtemelen buna değer değil.

Çıktı:

(*5, 3*)
(*0, 1*)
(*1, 667*)
(*355, 113*)

2

M.Ö, 151 148 bayt

Düzenle - daha hızlı ve daha kısa sürüm

define f(v){s=scale(x=v);for(i=r=1;i<=10^s;i+=1){t=v*i+1/2;scale=0;p=t/=1;scale=s+1;t=t/i+10^-s/2;scale=s;t=t/1-v;if((t*=-1^(t<0))<r){r=t;n=p;d=i}}}

Aynı test durumu.

Çok önceki sürüme benzer, ancak tüm olası n / d kombinasyonlarını denemek yerine, m == v * d katsayılarının v ve d. Yine hesaplamanın kesinliği aynıdır.

İşte karışık

define f(v)
{
    s= scale(x=v)
    for( i=r=1; i <= 10^s; i+=1 ){
        t= v * i +1/2
        scale=0
        m=t/=1 # this rounded multiple becomes nominator if
               # backward quotient is first closest to an integer
        scale=s+1
        t= t / i +10^-s/2 # divide multiple back by denominator, start rounding again...
        scale=s
        t= t/1 - v # ...rounding done. Signed residue of backward quotient
        if( (t*= -1^(t < 0)) < r ){
            r=t
            n=m
            d=i
        }
    }
}

Bu sürüm gerçekten sadece bir tek döngü vardır ve sadece $ \ Theta \ left (\ operatorname {fractional_decimals} (v) \ right) $ aritmetik işlem yapar.

Orijinal - yavaş versiyon

Bu fonksiyonlar, en küçük n ve n paydasını hesaplar, öyle ki, n / d fraksiyonel_devimals (v) rakamlarına yuvarlanmış kısım n, belirli bir ondalık değere v eşit olur.

define f(v){s=scale(v);j=0;for(i=r=1;j<=v*10^s;){scale=s+1;t=j/i+10^-s/2;scale=s;t=t/1-v;if((t*=-1^(t<0))<r){r=t;n=j;d=i};if((i+=1)>10^s){i=1;j+=1}};v}

test durumu:

define o(){ print "Input ",x,"\tOutput ",n,"/",d,"\n" }
f(1.7); o()
> 0
> Input 1.7       Output 5/3
> 0
f(0.); o()
> 0
> Input 0 Output 0/1
> 0
f(0.001); o()
> 0
> Input .001      Output 1/667
> 0
f(3.1416); o()
> 0
> Input 3.1416    Output 355/113
> 0

Ve işte karışık

define f(v)
{
    s=scale(x=v) # save in global for later print
    j=0
    # do a full sequential hill-climb over the residues r of v and all possible
    # fractions n / d with fractional_decimals(v) == s precision.
    for( i=r=1; j <= v * 10^s; ){
        scale=s+1
        t= j / i +10^-s/2 # start rounding...
        scale=s
        t= t/1 - v # ...rounding done. New residue, but still signed
        if( (t*= -1^(t < 0)) < r ){ # absolute residue better?
            # climb hill
            r=t
            n=j
            d=i
        }
        if( (i+=1) > 10^s ){ # next inner step. End?
            # next outer step
            i=1
            j+=1
        }
    }
    v
}

Kabul ediyorum, tek bir dış döngü içinde ikinci bir iç döngü taklit ederek biraz aldattım, ancak başka döngü ifadeleri kullanmadan. Bu yüzden aslında $ \ Theta \ left (v \ operatorname {fractional_decimals} (v) ^ 2 \ right) $ aritmetik işlem yapar.


1
Muhtemelen yeni sürümü postun önüne
taşımalısınız

@proudhaskeller bitti
Franki

1

C, 233

Bu, 1 (l) bir başlangıç ​​paydası olan bir rasyonalizasyon fonksiyonunu çağırarak çalışır. Fonksiyon, bir numarayı artırmaya başlar ve her artışta, elde edilen sayının, orijinal rakam ile aynı sayıya yuvarlandığında aynı dizgeye sahip olup olmadığını kontrol eder. orijinal olarak temsil edilmesi. Pay, sonuç orijinalden daha büyük olacak şekilde artırıldığında, işlev, paydayı artırır ve kendisini çağırır.

Bu elbette çok daha fazla kod kullanıyor, ancak sorunun ruhunun bu çıplak kemik yaklaşımını desteklediğini düşünüyorum; bildiğimiz kadarıyla, modern dillerin içsel rasyonelleştiren () fonksiyonları birçok içsel döngüye sahiptir.

Bunun "0" girişi için çalışmadığını unutmayın. bu bir şamandıra yazmak için standart bir yol değildir, bu nedenle şamandırayı dizeye yeniden yazdığında sonuç asla "0" olmaz.

Spesifikasyonlar sadece ekrana yazdırmak yerine değerleri döndüren bir fonksiyon istiyor, dolayısıyla argüman geçişi.

Kod (asılsız):

void r(char* x, int* a, int* b) {
    int i = -1;
    char z[32];
    double v =atof(x);
    while(1) {
        i++;
        double y = ((double)i)/((double)(*b));
        double w;
        sprintf(z, "%.*f", strlen(strchr(x,'.'))-1, y);
        if(strcmp(x, z)==0) {
            *a = i;
            return;
        }
        w = atof(z);
        if(w > v) {
            (*b)++;
            r(x, a, b);
            return;
        }
    }
}

Kullanımı:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char* argv[]) {
    int num;
    int denom = 1; // start with a denominator of 1
    r(argv[1], &num, &denom);
    printf("%d/%d\n", num, denom);
    return 0;
}

Golf kodu:

typedef double D;
void r(char*x,int*a,int*b){int i=-1;char z[32];D v=atof(x);while(1){i++;D y=((D)i)/((D)(*b));D w;sprintf(z,"%.*f",strlen(strchr(x,'.'))-1,y);if(!strcmp(x,z)){*a=i;return;}w=atof(z);if(w>v){(*b)++;r(x,a,b);return;}}}

Aslında, Haskell kütüphane uygulamasında ( hackage.haskell.org/package/base-4.7.0.1/docs/src/… ) tanımında, yalnızca approxRationalbir özyinelemeli yardımcı işlevi vardır ve bundan daha fazlası yoktur.
Gurur haskeller 23:14

iyi, yanılmışım, aslında iki özyinelemeli yardımcı işlevi var, ancak spec tarafından tamam
gururlu haskeller 23:03

Kimsenin çözümlerinin geçersiz olduğunu söylemek istemedim, sadece yerleşik bir rasyonalizasyon olmadan bir tane göndermek istedim :)
RT

elbette, ama tanımın kendisinde döngüler olmadığı gerçeği hoş ve nezaketsiz olarak yazdığınız yazıda “bildiğimiz her şey için, modern dillerin içsel rasyonelleştirici () işlevleri çok fazla iç döngüye sahip”. bu yüzden kontrol ettim.
Gurur haskeller 23:14

neyse, çözüm nasıl çalışıyor?
Gurme haskeller 23:14

1

Saf Bash, 92 bayt

Bu cevap için kısmi bir açıklama olarak , burada bash ile gösterilmiştir:

f=${1#*.}
q=${1//.}
for((n=0,d=1;x-q;x=2*10**${#f}*n/d+1>>1,n+=x<q,d+=x>q));{ :;}
echo $n/$d

Özellikle:

  • bash, sadece tamsayı aritmetiğine sahiptir. Bu yüzden her şeyi 2 * 10 ^ (kesirli basamak sayısı) ile uygun şekilde ölçeklendiririz.
  • bash mermi aşağı en yakın tam sayıya; Yukarıdaki ifadedeki 2, bunun yerine en yakın tam sayıya ( yukarı veya aşağı ) yuvarlayabiliyoruz .
  • Sadece bir döngü
  • rasyonelin ondalık sayıyı aştığını veya altını çizip atamadığını kontrol eder ve buna göre paydayı veya payları artırır.

Çıktı:

$ for n in 1.7 0. 0.001 3.1416; do echo "    n = $n:"; ./unround.sh $n; done
    n = 1.7:
5/3
    n = 0.:
0/1
    n = 0.001:
1/667
    n = 3.1416:
355/113
$ 

Oldukça basit - intsadece c'ye bağlantı noktası olmalı
Dijital Travma

1

JavaScript (E6) 85

F=r=>(l=>{for(n=r,d=1;l&&r!=((n=r*d+1/2|0)/d).toFixed(l);d++);})(r.length-2)||[n|0,d]

Ungolfed

F=r=>{
  l = r.length-2; // decimal digits
  if (l==0) return [r|0, 1] // if no decimal return the same (conv to number) with denominator 1

  // loop for increasing denominator 
  for(d = 2; 
      r != ( // loop until find an equal result
      // given R=N/D ==> N=R*D
      (n=r*d+1/2|0) // find possible numerator, rounding (+0.5 and trunc)
      /d).toFixed(l); // calc result to given decimals
      d++);
  return [n,d]
}

FireFox / FireBug konsolunda test edin

;["1.7","0.","0.001","3.1416","9.9999"].forEach(v => console.log(v,F(v)))

Çıktı

1.7 [5, 3]
0. [0, 1]
0.001 [1, 667]
3.1416 [355, 113]
9.9999 [66669, 6667]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.