फ़्लोट्स को मानव-पठनीय अंशों में कैसे बदलें?


103

मान लीजिए कि हमारे पास 0.33उत्पादन करने की आवश्यकता है 1/3
अगर हमारे पास है 0.4, तो हमें आउटपुट चाहिए 2/5

उपयोगकर्ता को डेटा को समझने का एक बेहतर तरीका के रूप में " समझ से बाहर x भागों " को बनाने के लिए विचार मानव-पठनीय बनाने के लिए है ।

मुझे पता है कि प्रतिशत एक अच्छा विकल्प है लेकिन मैं सोच रहा था कि क्या ऐसा करने का एक सरल तरीका था?


.33=> "1/3"उदाहरण चिंताओं मुझे; मैं उम्मीद होती है .33=> "33/100"। मेरा मानना ​​है कि आप .33...निश्चित रूप से मतलब है, लेकिन यह सवाल के साथ एक समस्या को उजागर करता है - इससे पहले कि हम एक एल्गोरिथ्म पर व्यवस्थित हो सकें हमें अपेक्षित व्यवहार पर निर्णय लेने की आवश्यकता है। @ देबिल्स्की के पाइथन उत्तर का उपयोग करता है .limit_denominator()जो 10 ^ 7 के अधिकतम हर के लिए चूक करता है ; शायद अभ्यास में एक अच्छा डिफ़ॉल्ट, लेकिन यह अभी भी बग प्रस्तुत कर सकते हैं अगर आप सावधान नहीं हैं, और करता है वापसी "33/100"में .33मामला।
dimo414

जो भी भाषा के साथ- विशिष्ट सुविधाएँ उपलब्ध हैं। यदि आप पूछ रहे हैं तो स्पष्ट करें, यदि वास्तव में यह केवल एक विरोधाभास नहीं है।
लोरेन का

जवाबों:


70

मैंने डेविड एप्पस्टीन की वास्तविक संख्या सी कोड दिए जाने के बारे में तर्कसंगत अनुमान लगाया है कि वास्तव में आप क्या पूछ रहे हैं। निरंतर भिन्न और बहुत तेज और काफी कॉम्पैक्ट के सिद्धांत पर आधारित है।

मैंने विशिष्ट अंश और हर सीमा के लिए इसके अनुकूलित संस्करणों का उपयोग किया है।

/*
** find rational approximation to given real number
** David Eppstein / UC Irvine / 8 Aug 1993
**
** With corrections from Arno Formella, May 2008
**
** usage: a.out r d
**   r is real number to approx
**   d is the maximum denominator allowed
**
** based on the theory of continued fractions
** if x = a1 + 1/(a2 + 1/(a3 + 1/(a4 + ...)))
** then best approximation is found by truncating this series
** (with some adjustments in the last term).
**
** Note the fraction can be recovered as the first column of the matrix
**  ( a1 1 ) ( a2 1 ) ( a3 1 ) ...
**  ( 1  0 ) ( 1  0 ) ( 1  0 )
** Instead of keeping the sequence of continued fraction terms,
** we just keep the last partial product of these matrices.
*/

#include <stdio.h>

main(ac, av)
int ac;
char ** av;
{
    double atof();
    int atoi();
    void exit();

    long m[2][2];
    double x, startx;
    long maxden;
    long ai;

    /* read command line arguments */
    if (ac != 3) {
        fprintf(stderr, "usage: %s r d\n",av[0]);  // AF: argument missing
        exit(1);
    }
    startx = x = atof(av[1]);
    maxden = atoi(av[2]);

    /* initialize matrix */
    m[0][0] = m[1][1] = 1;
    m[0][1] = m[1][0] = 0;

    /* loop finding terms until denom gets too big */
    while (m[1][0] *  ( ai = (long)x ) + m[1][1] <= maxden) {
        long t;
        t = m[0][0] * ai + m[0][1];
        m[0][1] = m[0][0];
        m[0][0] = t;
        t = m[1][0] * ai + m[1][1];
        m[1][1] = m[1][0];
        m[1][0] = t;
        if(x==(double)ai) break;     // AF: division by zero
        x = 1/(x - (double) ai);
        if(x>(double)0x7FFFFFFF) break;  // AF: representation failure
    } 

    /* now remaining x is between 0 and 1/ai */
    /* approx as either 0 or 1/m where m is max that will fit in maxden */
    /* first try zero */
    printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
           startx - ((double) m[0][0] / (double) m[1][0]));

    /* now try other possibility */
    ai = (maxden - m[1][1]) / m[1][0];
    m[0][0] = m[0][0] * ai + m[0][1];
    m[1][0] = m[1][0] * ai + m[1][1];
    printf("%ld/%ld, error = %e\n", m[0][0], m[1][0],
           startx - ((double) m[0][0] / (double) m[1][0]));
}

6
रूबी में एक समाधान की तलाश में आप के लिए, हम भाग्य में हैं! क्रिस्टोफर लॉर्ड ने रूबी रत्न में उपरोक्त एल्गोरिदम को लागू किया है। देखें christopher.lord.ac/fractions-in-ruby और rubygems.org/gems/fraction
Shedd

6
ज्ञात रहे कि कुछ धार के मामले हैं जो इस कोड को बहुत अच्छी तरह से नहीं संभालते हैं: जब -1.3333333 को 4 के अधिकतम हर के साथ दिया जाता है तो यह 3.333333e-08 और -5/4 की त्रुटि के साथ 4/3 देता है = एक त्रुटि के साथ -8.333330e-02, जो सही है। लेकिन जब एक ही अधिकतम भाजक के साथ -1.33333337 दिया जाता है, तो यह 12.61211 / -9090908 त्रुटि के साथ = 4.218847e-15 और -4/3 के साथ -3.666667e-08 की त्रुटि के साथ बदल जाता है, जो सही नहीं है। यह विशेष रूप से एक समस्या है जब एल्गोरिथ्म को कम्प्यूटिंग फ्लोटिंग पॉइंट नंबर्स जैसे कि -4/3 के साथ प्रस्तुत किया जाता है, जो इन जैसे गलत परिणाम देता है।
एडस्को

26

पायथन 2.6 से fractionsमॉड्यूल है।

(डॉक्स से उद्धरण।)

>>> from fractions import Fraction
>>> Fraction('3.1415926535897932').limit_denominator(1000)
Fraction(355, 113)

>>> from math import pi, cos
>>> Fraction.from_float(cos(pi/3))
Fraction(4503599627370497, 9007199254740992)
>>> Fraction.from_float(cos(pi/3)).limit_denominator()
Fraction(1, 2)

6
कार्यान्वयन और एल्गोरिदम नोट्स hg.python.org/cpython/file/822c7c0d27d1/Lib/fractions.py#l211
piro

2
@Debilski ओपी language agnosticऔर algorithmटैग्स में से कौन आपका उत्तर संतुष्ट करता है?
vladr

2
@vladr खैर, यह देखते हुए कि मैंने यह उत्तर लगभग 6 साल पहले लिखा था (और सवाल पूछे जाने के एक साल से अधिक समय बाद), मुझे लगता है कि मुझे नहीं पता कि मेरा तर्क क्या था। सबसे शायद मैं इस टिप्पणी का उल्लेख कर रहा था: stackoverflow.com/questions/95727/… OTOH यह भी हो सकता है कि इस उत्तर को दूसरे प्रश्न से मिला दिया गया हो। उन सभी वर्षों के बाद कौन बता सकता है ...
देबिल्स्की

आप भिन्न मॉड्यूल द्वारा उपयोग किए गए एल्गोरिथ्म के बारे में कुछ वाक्य जोड़ सकते हैं (और शायद पायथन 3 के लिए अपना उत्तर अपडेट करें)।
ईनपोकलम

21

यदि आउटपुट मानव पाठक को परिणाम के क्रम का तेज़ प्रभाव देने के लिए है, तो यह "113/211" की तरह कुछ भी नहीं देता है, इसलिए आउटपुट को केवल एक-अंकीय संख्या (और शायद 1 /) का उपयोग करने के लिए सीमित करना चाहिए 10 और 9/10)। यदि हां, तो आप देख सकते हैं कि केवल 27 अलग-अलग अंश हैं।

चूंकि आउटपुट उत्पन्न करने के लिए अंतर्निहित गणित कभी नहीं बदलेगा, इसलिए एक समाधान केवल बाइनरी सर्च ट्री को हार्ड-कोड करने के लिए हो सकता है, ताकि फ़ंक्शन अधिकांश लॉग (27) ~ = 4 3/4 की तुलना में प्रदर्शन करे। यहाँ कोड का एक परीक्षण किया हुआ C संस्करण है

char *userTextForDouble(double d, char *rval)
{
    if (d == 0.0)
        return "0";

    // TODO: negative numbers:if (d < 0.0)...
    if (d >= 1.0)
        sprintf(rval, "%.0f ", floor(d));
    d = d-floor(d); // now only the fractional part is left

    if (d == 0.0)
        return rval;

    if( d < 0.47 )
    {
        if( d < 0.25 )
        {
            if( d < 0.16 )
            {
                if( d < 0.12 ) // Note: fixed from .13
                {
                    if( d < 0.11 )
                        strcat(rval, "1/10"); // .1
                    else
                        strcat(rval, "1/9"); // .1111....
                }
                else // d >= .12
                {
                    if( d < 0.14 )
                        strcat(rval, "1/8"); // .125
                    else
                        strcat(rval, "1/7"); // .1428...
                }
            }
            else // d >= .16
            {
                if( d < 0.19 )
                {
                    strcat(rval, "1/6"); // .1666...
                }
                else // d > .19
                {
                    if( d < 0.22 )
                        strcat(rval, "1/5"); // .2
                    else
                        strcat(rval, "2/9"); // .2222...
                }
            }
        }
        else // d >= .25
        {
            if( d < 0.37 ) // Note: fixed from .38
            {
                if( d < 0.28 ) // Note: fixed from .29
                {
                    strcat(rval, "1/4"); // .25
                }
                else // d >=.28
                {
                    if( d < 0.31 )
                        strcat(rval, "2/7"); // .2857...
                    else
                        strcat(rval, "1/3"); // .3333...
                }
            }
            else // d >= .37
            {
                if( d < 0.42 ) // Note: fixed from .43
                {
                    if( d < 0.40 )
                        strcat(rval, "3/8"); // .375
                    else
                        strcat(rval, "2/5"); // .4
                }
                else // d >= .42
                {
                    if( d < 0.44 )
                        strcat(rval, "3/7"); // .4285...
                    else
                        strcat(rval, "4/9"); // .4444...
                }
            }
        }
    }
    else
    {
        if( d < 0.71 )
        {
            if( d < 0.60 )
            {
                if( d < 0.55 ) // Note: fixed from .56
                {
                    strcat(rval, "1/2"); // .5
                }
                else // d >= .55
                {
                    if( d < 0.57 )
                        strcat(rval, "5/9"); // .5555...
                    else
                        strcat(rval, "4/7"); // .5714
                }
            }
            else // d >= .6
            {
                if( d < 0.62 ) // Note: Fixed from .63
                {
                    strcat(rval, "3/5"); // .6
                }
                else // d >= .62
                {
                    if( d < 0.66 )
                        strcat(rval, "5/8"); // .625
                    else
                        strcat(rval, "2/3"); // .6666...
                }
            }
        }
        else
        {
            if( d < 0.80 )
            {
                if( d < 0.74 )
                {
                    strcat(rval, "5/7"); // .7142...
                }
                else // d >= .74
                {
                    if(d < 0.77 ) // Note: fixed from .78
                        strcat(rval, "3/4"); // .75
                    else
                        strcat(rval, "7/9"); // .7777...
                }
            }
            else // d >= .8
            {
                if( d < 0.85 ) // Note: fixed from .86
                {
                    if( d < 0.83 )
                        strcat(rval, "4/5"); // .8
                    else
                        strcat(rval, "5/6"); // .8333...
                }
                else // d >= .85
                {
                    if( d < 0.87 ) // Note: fixed from .88
                    {
                        strcat(rval, "6/7"); // .8571
                    }
                    else // d >= .87
                    {
                        if( d < 0.88 ) // Note: fixed from .89
                        {
                            strcat(rval, "7/8"); // .875
                        }
                        else // d >= .88
                        {
                            if( d < 0.90 )
                                strcat(rval, "8/9"); // .8888...
                            else
                                strcat(rval, "9/10"); // .9
                        }
                    }
                }
            }
        }
    }

    return rval;
}

3
यह उस तरह की पार्श्व सोच है जिसकी हमें अधिक आवश्यकता है! बहुत बढ़िया सुझाव।
edsko

1
इसका थोड़ा बदसूरत लेकिन बहुत तेज और व्यावहारिक तरीका है
बॉस्केट नोव

1
यह एक दिलचस्प दृष्टिकोण है जो आश्चर्यजनक रूप से सरल है। स्थान को बचाने के लिए आप बाइनरी को खोजने के बजाय एक सरणी खोज सकते हैं, या एक बाइनरी ट्री बना सकते हैं, लेकिन आपका दृष्टिकोण शायद थोड़ा तेज़ है (आप वापसी से पहले स्ट्रैकट पर एक सिंगल कॉल का उपयोग करके अंतरिक्ष को बचा सकते हैं और एक संस्करण असाइन करें जहां अब इसे कहा जाता है)। इसके अलावा मैंने 3/10 और 7/10 को शामिल किया होगा, लेकिन शायद यह सिर्फ मैं ही हूं।
जिम्हार्क

1
इस समाधान से प्रेरित होकर, मैंने एक छोटा (लेकिन पूरी तरह से अडॉप्ट किए हुए) कोड बनाया है। यह आसानी से भिन्न की एक बड़ी रेंज को कवर करने के लिए बढ़ाया जा सकता है। jsfiddle.net/PdL23/1
दीपक जॉय

1
ध्यान दें कि 1/1000यह बहुत मानवीय रूप से पठनीय है, लेकिन उपरोक्त एल्गोरिथ्म केवल बहुत मोटे 1/10अनुमान का उत्पादन करेगा ; मुझे विश्वास है कि सुधार शर्तों जिनमें से आदमियत पठनीय हरों एक से चुन सकते हैं में किया जा सकता है, और / या के अलावा <, >, <<, >>उपसर्गों सन्निकटन की बेअदबी की एक विचार देने के लिए।
vladr

16

दशमलव को एक अंश में परिवर्तित करने के पीछे गणित की व्याख्या करने वाला एक लिंक यहां दिया गया है:

http://www.webmath.com/dec2fract.html

और यहाँ VB (www.freevbcode.com/ShowCode.asp?ID=582 से) का उपयोग करके वास्तव में इसे कैसे करना है, इसके लिए एक उदाहरण समारोह है:

Public Function Dec2Frac(ByVal f As Double) As String

   Dim df As Double
   Dim lUpperPart As Long
   Dim lLowerPart As Long

   lUpperPart = 1
   lLowerPart = 1

   df = lUpperPart / lLowerPart
   While (df <> f)
      If (df < f) Then
         lUpperPart = lUpperPart + 1
      Else
         lLowerPart = lLowerPart + 1
         lUpperPart = f * lLowerPart
      End If
      df = lUpperPart / lLowerPart
   Wend
Dec2Frac = CStr(lUpperPart) & "/" & CStr(lLowerPart)
End Function

(Google खोजों से: दशमलव को अंश में बदलें, दशमलव को भिन्न कोड में बदलें)


2
ध्यान दें कि यह एल्गोरिदम algorithm (m) समय लेता है जब f = n / m। और यह बहुत कुछ हो सकता है, भले ही आपने इसे करने का इरादा नहीं किया हो (0.66666666667 पर विचार करें)।
ईनपोकलुम

10

आप पढ़ना चाह सकते हैं कि हर कंप्यूटर वैज्ञानिक को फ्लोटिंग पॉइंट अंकगणित के बारे में क्या जानना चाहिए

आपको बड़ी संख्या से गुणा करके कुछ सटीक निर्दिष्ट करना होगा:

3.141592 * 1000000 = 3141592

तो आप एक अंश बना सकते हैं:

3 + (141592 / 1000000)

और GCD के माध्यम से कम करें ...

3 + (17699 / 125000)

लेकिन इच्छित अंश को बाहर निकालने का कोई तरीका नहीं है। आप हमेशा अपने कोड में भिन्न का उपयोग करना चाहते हो सकता है - जब आप ओवरफ्लो से बचने के लिए कर सकते हैं तो फ्रैक्चर को कम करना याद रखें!


9

यहाँ devinmoore द्वारा सुझाए गए VB कोड के पर्ल और जावास्क्रिप्ट संस्करण हैं:

पर्ल:

sub dec2frac {
    my $d = shift;

    my $df  = 1;
    my $top = 1;
    my $bot = 1;

    while ($df != $d) {
      if ($df < $d) {
        $top += 1;
      }
      else {
         $bot += 1;
         $top = int($d * $bot);
      }
      $df = $top / $bot;
   }
   return "$top/$bot";
}

और लगभग समान जावास्क्रिप्ट:

function dec2frac(d) {

    var df = 1;
    var top = 1;
    var bot = 1;

    while (df != d) {
        if (df < d) {
            top += 1;
        }
        else {
            bot += 1;
            top = parseInt(d * bot);
        }
        df = top / bot;
    }
    return top + '/' + bot;
}

9

एसी # कार्यान्वयन

/// <summary>
/// Represents a rational number
/// </summary>
public struct Fraction
{
    public int Numerator;
    public int Denominator;

    /// <summary>
    /// Constructor
    /// </summary>
    public Fraction(int numerator, int denominator)
    {
        this.Numerator = numerator;
        this.Denominator = denominator;
    }

    /// <summary>
    /// Approximates a fraction from the provided double
    /// </summary>
    public static Fraction Parse(double d)
    {
        return ApproximateFraction(d);
    }

    /// <summary>
    /// Returns this fraction expressed as a double, rounded to the specified number of decimal places.
    /// Returns double.NaN if denominator is zero
    /// </summary>
    public double ToDouble(int decimalPlaces)
    {
        if (this.Denominator == 0)
            return double.NaN;

        return System.Math.Round(
            Numerator / (double)Denominator,
            decimalPlaces
        );
    }


    /// <summary>
    /// Approximates the provided value to a fraction.
    /// http://stackoverflow.com/questions/95727/how-to-convert-floats-to-human-readable-fractions
    /// </summary>
    private static Fraction ApproximateFraction(double value)
    {
        const double EPSILON = .000001d;

        int n = 1;  // numerator
        int d = 1;  // denominator
        double fraction = n / d;

        while (System.Math.Abs(fraction - value) > EPSILON)
        {
            if (fraction < value)
            {
                n++;
            }
            else
            {
                d++;
                n = (int)System.Math.Round(value * d);
            }

            fraction = n / (double)d;
        }

        return new Fraction(n, d);
    }
}


6

समस्या का एक हिस्सा यह है कि इतने सारे अंश वास्तव में आसानी से भिन्न नहीं होते हैं। Eg 0.33 1/3 नहीं है, यह 33/100 है। लेकिन अगर आपको अपना प्राथमिक विद्यालय प्रशिक्षण याद है, तो दशमलव मानों को भिन्न में बदलने की एक प्रक्रिया है, हालाँकि यह आपको देने की संभावना नहीं है कि आप क्या चाहते हैं क्योंकि अधिकांश समय दशमलव संख्या 0.33 पर संग्रहीत नहीं होती है, लेकिन 0.3299999999998 या कुछ इस तरह से।

अपने आप को एक एहसान करो और इस के साथ परेशान मत करो, लेकिन अगर आपको जरूरत है तो आप निम्न कार्य कर सकते हैं:

जब तक आप भिन्नात्मक भाग को हटाते हैं, मूल मूल्य को 10 से गुणा करें। उस नंबर को रखें, और इसे भाजक के रूप में उपयोग करें। फिर सामान्य हर की तलाश में सरलीकरण की एक श्रृंखला करें।

तो 0.4 4/10 होगा। आप तब कम मूल्यों के साथ शुरू होने वाले सामान्य भाजक की तलाश करेंगे, शायद प्राइम नंबर। 2 से शुरू करते हुए, आप देखेंगे कि क्या 2 अंश और हर दोनों को समान रूप से जाँच कर विभाजित करता है यदि विभाजन का फर्श विभाजन के समान ही है।

floor(5/2) = 2
5/2 = 2.5

तो 5 समान रूप से 2 को विभाजित नहीं करता है। तो फिर आप अगले नंबर की जांच करते हैं, कहते हैं 3. आप ऐसा तब तक करते हैं जब तक आप छोटी संख्या के वर्गमूल पर या उसके ऊपर नहीं मारते।

जब आप ऐसा करेंगे, उसके बाद आपको जरूरत होगी


1
मैं उस अंतिम चरण के लिए यूक्लिडियन एल्गोरिथ्म का उपयोग करने का सुझाव दूंगा
ग्राफिक्स नूब


4

"मान लें कि हमारे पास 0.33 हैं, हमें" 1/3 "आउटपुट की आवश्यकता है।"

आप "समाधान" की क्या सटीकता की उम्मीद करते हैं? 0.33 1/3 के बराबर नहीं है। आप एक "अच्छे" (पढ़ने में आसान) उत्तर को कैसे पहचानते हैं?

कोई बात नहीं, एक संभव एल्गोरिथ्म हो सकता है:

यदि आप X / Y के किसी निकटतम अंश को खोजने की अपेक्षा करते हैं जहां Y 10 से कम है, तो आप प्रत्येक Y कंप्यूट X के लिए सभी 9 संभावित Ys, हालांकि लूप कर सकते हैं और फिर सबसे सटीक एक का चयन कर सकते हैं।


3

मुझे लगता है कि ऐसा करने का सबसे अच्छा तरीका यह है कि आप अपने फ्लोट वैल्यू को पहले एक एस्की प्रतिनिधित्व में बदल दें। C ++ में आप ostringstream या C का उपयोग कर सकते हैं, आप स्प्रिंट का उपयोग कर सकते हैं। यहाँ यह C ++ में कैसा दिखेगा:

ostringstream oss;
float num;
cin >> num;
oss << num;
string numStr = oss.str();
int i = numStr.length(), pow_ten = 0;
while (i > 0) {
    if (numStr[i] == '.')
        break;
    pow_ten++;
    i--;
}
for (int j = 1; j < pow_ten; j++) {
    num *= 10.0;
}
cout << static_cast<int>(num) << "/" << pow(10, pow_ten - 1) << endl;

एक समान दृष्टिकोण सीधे सी में लिया जा सकता है।

बाद में आपको यह जांचना होगा कि अंश सबसे कम शब्दों में है। यह एल्गोरिथ्म सटीक उत्तर देगा, अर्थात 0.33 "33/100" का उत्पादन करेगा, न कि "1/3"। हालाँकि, 0.4 "4/10" देगा, जो सबसे कम शब्दों में घटकर "2/5" होगा। यह एप्सटाइटिन के समाधान जितना शक्तिशाली नहीं हो सकता है, लेकिन मेरा मानना ​​है कि यह अधिक सीधा है।


8 साल बाद मैं आपके समाधान के लिए आया हूं, मैंने परीक्षण किया है और यह अभी तक पूरी तरह से काम कर रहा है, लेकिन आपने कहा कि यह एप्सटाइटिन के समाधान के रूप में शक्तिशाली नहीं है और मुझे आश्चर्य है कि क्यों। चूँकि आपका समाधान कहीं अधिक सरल है, इसलिए यह पसंद का समाधान नहीं होना चाहिए, क्या हम तब तक सरल कोड को संभव नहीं कर सकते जब तक यह काम करता है और यह सुरक्षित है ??
HBatalha

3

आर में निर्मित समाधान:

library(MASS)
fractions(0.666666666)
## [1] 2/3

यह एक निरंतर अंश विधि का उपयोग करता है और इसमें परिशुद्धता को समायोजित करने के लिए वैकल्पिक cyclesऔर max.denominatorतर्क होते हैं।


इसके अलावा library(numbers)और contFrac(0.6666); वांछित के रूप में स्ट्रिंग उत्पादन प्राप्त करने के लिए:paste(contFrac(0.666, tol=1e-03)$rat, collapse="/")
rbatt

2

आपको यह पता लगाना होगा कि आप किस स्तर की त्रुटि स्वीकार करने को तैयार हैं। सभी दशमलव अंश एक साधारण अंश तक कम नहीं होंगे। मैं शायद 60 की तरह एक आसानी से-विभाज्य संख्या चुनूंगा, और यह पता लगाऊंगा कि कितने 60 वें मूल्य के सबसे करीब है, फिर अंश को सरल बनाएं।


2

आप निम्न चरणों का उपयोग करके किसी भी प्रोग्रामिंग भाषा में ऐसा कर सकते हैं:

  1. गुणा करें और विभाजित करें 10 ^ x जहां x 10 की शक्ति है यह सुनिश्चित करने के लिए आवश्यक है कि संख्या में कोई दशमलव स्थान शेष नहीं है। उदाहरण: इसे 3333 बनाने के लिए 0.33 को 10 ^ 2 = 100 से गुणा करें और 33/100 प्राप्त करने के लिए इसे उसी से विभाजित करें
  2. जब तक आप परिणाम से पूर्णांक प्राप्त नहीं कर सकते, तब तक अंश और परिणामी अंश के हर को कम करें।
  3. परिणामी घटा हुआ अंश आपका उत्तर होना चाहिए।

उदाहरण: 0.2 = 0.2 x 10 ^ 1/10 ^ 1 = 2/10 = 1/5

तो, '5 में से 1 भाग' के रूप में पढ़ा जा सकता है


2

एक उपाय यह है कि सभी संख्याओं को पहली जगह में तर्कसंगत संख्याओं के रूप में संग्रहीत किया जाए। तर्कसंगत संख्या अंकगणित (उदाहरण के लिए जीएमपी ) के लिए पुस्तकालय हैं । यदि आप OO भाषा का उपयोग कर रहे हैं, तो आप अपनी संख्या वर्ग को बदलने के लिए एक तर्कसंगत संख्या वर्ग लाइब्रेरी का उपयोग कर सकते हैं।

दूसरों के बीच, वित्त कार्यक्रम, इस तरह के समाधान का उपयोग सटीक गणना करने में सक्षम होने और सटीक संरक्षण करने में सक्षम होगा जो एक सादे नाव का उपयोग करके खो सकता है।

बेशक यह बहुत धीमा होगा, इसलिए यह आपके लिए व्यावहारिक नहीं हो सकता है। इस बात पर निर्भर करता है कि आपको कितनी गणना करने की आवश्यकता है, और आपके लिए परिशुद्धता कितनी महत्वपूर्ण है।

a = rational(1);
b = rational(3);
c = a / b;

print (c.asFraction)  --->  "1/3"
print (c.asFloat) ----> "0.333333"

2

मान लें कि हमारे पास 0.33 है, हमें "1/3" आउटपुट की आवश्यकता है। यदि हमारे पास "0.4" है, तो हमें "2/5" आउटपुट की आवश्यकता है।

यह सामान्य मामले में गलत है, क्योंकि 1/3 = 0.3333333 = 0. (3) इसके अलावा, ऊपर दिए गए समाधानों में से यह पता लगाना असंभव है कि दशमलव को परिभाषित परिशुद्धता के साथ अंश में परिवर्तित किया जा सकता है, क्योंकि आउटपुट हमेशा भिन्न होता है।

लेकिन, मैं अनंत ज्यामितीय श्रृंखला के विचार पर आधारित कई विकल्पों के साथ अपने व्यापक कार्य का सुझाव देता हूं , विशेष रूप से सूत्र पर:

यहां छवि विवरण दर्ज करें

सबसे पहले यह फ़ंक्शन स्ट्रिंग प्रतिनिधित्व में अंश की अवधि खोजने की कोशिश कर रहा है। उसके बाद ऊपर वर्णित फॉर्मूला लागू किया जाता है।

तर्कसंगत संख्या कोड को स्टीफन एम। मैककेमी तर्कसंगत संख्या कार्यान्वयन से C # में उधार लिया गया है। मुझे उम्मीद है कि अन्य भाषाओं पर अपने कोड को पोर्ट करने के लिए बहुत मुश्किल नहीं है।

/// <summary>
/// Convert decimal to fraction
/// </summary>
/// <param name="value">decimal value to convert</param>
/// <param name="result">result fraction if conversation is succsess</param>
/// <param name="decimalPlaces">precision of considereation frac part of value</param>
/// <param name="trimZeroes">trim zeroes on the right part of the value or not</param>
/// <param name="minPeriodRepeat">minimum period repeating</param>
/// <param name="digitsForReal">precision for determination value to real if period has not been founded</param>
/// <returns></returns>
public static bool FromDecimal(decimal value, out Rational<T> result, 
    int decimalPlaces = 28, bool trimZeroes = false, decimal minPeriodRepeat = 2, int digitsForReal = 9)
{
    var valueStr = value.ToString("0.0000000000000000000000000000", CultureInfo.InvariantCulture);
    var strs = valueStr.Split('.');

    long intPart = long.Parse(strs[0]);
    string fracPartTrimEnd = strs[1].TrimEnd(new char[] { '0' });
    string fracPart;

    if (trimZeroes)
    {
        fracPart = fracPartTrimEnd;
        decimalPlaces = Math.Min(decimalPlaces, fracPart.Length);
    }
    else
        fracPart = strs[1];

    result = new Rational<T>();
    try
    {
        string periodPart;
        bool periodFound = false;

        int i;
        for (i = 0; i < fracPart.Length; i++)
        {
            if (fracPart[i] == '0' && i != 0)
                continue;

            for (int j = i + 1; j < fracPart.Length; j++)
            {
                periodPart = fracPart.Substring(i, j - i);
                periodFound = true;
                decimal periodRepeat = 1;
                decimal periodStep = 1.0m / periodPart.Length;
                var upperBound = Math.Min(fracPart.Length, decimalPlaces);
                int k;
                for (k = i + periodPart.Length; k < upperBound; k += 1)
                {
                    if (periodPart[(k - i) % periodPart.Length] != fracPart[k])
                    {
                        periodFound = false;
                        break;
                    }
                    periodRepeat += periodStep;
                }

                if (!periodFound && upperBound - k <= periodPart.Length && periodPart[(upperBound - i) % periodPart.Length] > '5')
                {
                    var ind = (k - i) % periodPart.Length;
                    var regroupedPeriod = (periodPart.Substring(ind) + periodPart.Remove(ind)).Substring(0, upperBound - k);
                    ulong periodTailPlusOne = ulong.Parse(regroupedPeriod) + 1;
                    ulong fracTail = ulong.Parse(fracPart.Substring(k, regroupedPeriod.Length));
                    if (periodTailPlusOne == fracTail)
                        periodFound = true;
                }

                if (periodFound && periodRepeat >= minPeriodRepeat)
                {
                    result = FromDecimal(strs[0], fracPart.Substring(0, i), periodPart);
                    break;
                }
                else
                    periodFound = false;
            }

            if (periodFound)
                break;
        }

        if (!periodFound)
        {
            if (fracPartTrimEnd.Length >= digitsForReal)
                return false;
            else
            {
                result = new Rational<T>(long.Parse(strs[0]), 1, false);
                if (fracPartTrimEnd.Length != 0)
                    result = new Rational<T>(ulong.Parse(fracPartTrimEnd), TenInPower(fracPartTrimEnd.Length));
                return true;
            }
        }

        return true;
    }
    catch
    {
        return false;
    }
}

public static Rational<T> FromDecimal(string intPart, string fracPart, string periodPart)
{
    Rational<T> firstFracPart;
    if (fracPart != null && fracPart.Length != 0)
    {
        ulong denominator = TenInPower(fracPart.Length);
        firstFracPart = new Rational<T>(ulong.Parse(fracPart), denominator);
    }
    else
        firstFracPart = new Rational<T>(0, 1, false);

    Rational<T> secondFracPart;
    if (periodPart != null && periodPart.Length != 0)
        secondFracPart =
            new Rational<T>(ulong.Parse(periodPart), TenInPower(fracPart.Length)) *
            new Rational<T>(1, Nines((ulong)periodPart.Length), false);
    else
        secondFracPart = new Rational<T>(0, 1, false);

    var result = firstFracPart + secondFracPart;
    if (intPart != null && intPart.Length != 0)
    {
        long intPartLong = long.Parse(intPart);
        result = new Rational<T>(intPartLong, 1, false) + (intPartLong == 0 ? 1 : Math.Sign(intPartLong)) * result;
    }

    return result;
}

private static ulong TenInPower(int power)
{
    ulong result = 1;
    for (int l = 0; l < power; l++)
        result *= 10;
    return result;
}

private static decimal TenInNegPower(int power)
{
    decimal result = 1;
    for (int l = 0; l > power; l--)
        result /= 10.0m;
    return result;
}

private static ulong Nines(ulong power)
{
    ulong result = 9;
    if (power >= 0)
        for (ulong l = 0; l < power - 1; l++)
            result = result * 10 + 9;
    return result;
}

Usings के कुछ उदाहरण हैं:

Rational<long>.FromDecimal(0.33333333m, out r, 8, false);
// then r == 1 / 3;

Rational<long>.FromDecimal(0.33333333m, out r, 9, false);
// then r == 33333333 / 100000000;

दाहिने भाग के साथ आपका मामला शून्य भाग ट्रिमिंग:

Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 1 / 3;

Rational<long>.FromDecimal(0.33m, out r, 28, true);
// then r == 33 / 100;

न्यूनतम अवधि डेमोस्ट्रेशन:

Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.5m));
// then r == 1234 / 9999;
Rational<long>.FromDecimal(0.123412m, out r, 28, true, 1.6m));
// then r == 123412 / 1000000; because of minimu repeating of period is 0.1234123 in this case.

अंत में गोलाई:

Rational<long>.FromDecimal(0.8888888888888888888888888889m, out r));
// then r == 8 == 9;

सबसे दिलचस्प मामला:

Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 9);
// then r == 12345678 / 100000000;

Rational<long>.FromDecimal(0.12345678m, out r, 28, true, 2, 8);
// Conversation failed, because of period has not been founded and there are too many digits in fraction part of input value.

Rational<long>.FromDecimal(0.12121212121212121m, out r, 28, true, 2, 9));
// then r == 4 / 33; Despite of too many digits in input value, period has been founded. Thus it's possible to convert value to fraction.

अन्य परीक्षण और कोड हर कोई मेरे मैथफंक्शन लायब्रेरी में जीथब पर पा सकता है ।


2

रूबी के पास पहले से निर्मित समाधान है:

0.33.rationalize.to_s # => "33/100"
0.4.rationalize.to_s # => "2/5"

रेल में, ActiveRecord संख्यात्मक विशेषताओं को भी परिवर्तित किया जा सकता है:

product.size = 0.33
product.size.to_r.to_s # => "33/100"

2

C ++ में उत्तर दें, यह मानते हुए कि आपके पास एक 'BigInt' वर्ग है, जो असीमित आकार के पूर्णांक स्टोर कर सकता है।

आप इसके बजाय 'अहस्ताक्षरित लंबे समय' का उपयोग कर सकते हैं, लेकिन यह केवल कुछ मूल्यों के लिए काम करेगा।

void GetRational(double val)
{
    if (val == val+1) // Inf
        throw "Infinite Value";
    if (val != val) // NaN
        throw "Undefined Value";

    bool sign = false;
    BigInt enumerator = 0;
    BigInt denominator = 1;

    if (val < 0)
    {
        val = -val;
        sign = true;
    }

    while (val > 0)
    {
        unsigned int intVal = (unsigned int)val;
        val -= intVal;
        enumerator += intVal;
        val *= 2;
        enumerator *= 2;
        denominator *= 2;
    }

    BigInt gcd = GCD(enumerator,denominator);
    enumerator /= gcd;
    denominator /= gcd;

    Print(sign? "-":"+");
    Print(enumerator);
    Print("/");
    Print(denominator);

    // Or simply return {sign,enumerator,denominator} as you wish
}

BTW, GetRational (0.0) "+0/1" वापस आ जाएगी, इसलिए आप इस मामले को अलग से संभाल सकते हैं।

पुनश्च: मैं कई वर्षों से इस कोड का उपयोग अपने 'रेशनलनम' वर्ग में कर रहा हूँ, और इसे पूरी तरह से परखा गया है।


आपका उदाहरण 1.333333 जैसे मूल्यों पर टूटता हुआ प्रतीत होता है .. यह मूल्य खोजने की कोशिश में बहुत लंबे पाश में चला जाता है और काम नहीं करता है ... अन्य सरल मूल्यों जैसे 1.25 के साथ ठीक करता है
एडम्सकी

@ एडम्सकी: धन्यवाद। whileलूप की "अभिसरण" अवधि के आकार से घिरा होता है double, जो आमतौर पर 64 बिट्स होता है। तो यह इनपुट के प्रारंभिक मूल्य ( val) पर निर्भर नहीं करता है । GCDसमारोह, तथापि, यह मान पर निर्भर करते हैं, हालांकि यह आम तौर पर बहुत जल्दी एक समाधान करने के लिए अभिमुख है। क्या यह संभव है कि आपने इस फ़ंक्शन को ठीक से लागू नहीं किया?
बराक मानोस

@ एडम्सकी: इसके अलावा, जैसा कि मैंने उत्तर की शुरुआत में उल्लेख किया था, यदि आप unsigned long longइसके बजाय उपयोग कर रहे हैं BigInt, तो यह जरूरी नहीं कि हर इनपुट मूल्य के लिए सही परिणाम मिले ... लेकिन उस परिदृश्य में भी, कोड नहीं है माना जाता है "बहुत लंबे लूप में जाना"।
बरक मानस

आह ठीक है हाँ, यह पूरी तरह से संभव है, जो जीसीडी फ़ंक्शन मैं उपयोग कर रहा था वह ज्यूस लाइब्रेरी बिगइंटरेगर वर्ग का हिस्सा है। जानकारी के लिए धन्यवाद!
एडम्सकी

@ Adamski: तो यह समझ में नहीं आता है कि GCDफ़ंक्शन ठीक से लागू नहीं किया गया है। क्या आपने जाँच की है कि कोड whileलूप के दौरान या उसके बाद लंबे समय तक चलता है? मैं 1.33333 के मूल्य की जांच करूंगा, यह देखने के लिए कि इसके पीछे क्या है। धन्यवाद।
बराक मानोस

2

इयान रिचर्ड्स / जॉन कैनेडी द्वारा यह एल्गोरिथ्म न केवल अच्छे अंशों को लौटाता है, यह गति के मामले में भी बहुत अच्छा प्रदर्शन करता है। यह मेरे द्वारा दिए गए उत्तर के अनुसार लिया गया C # कोड है।

यह doubleNaN और +/- इन्फिनिटी जैसे विशेष मूल्यों को छोड़कर सभी मूल्यों को संभाल सकता है , जिन्हें आपको जरूरत पड़ने पर जोड़ना होगा।

यह एक रिटर्न new Fraction(numerator, denominator)। अपने प्रकार से बदलें।

अधिक उदाहरण मूल्यों और अन्य एल्गोरिदम के साथ तुलना के लिए, यहां जाएं

public Fraction RealToFraction(double value, double accuracy)
{
    if (accuracy <= 0.0 || accuracy >= 1.0)
    {
        throw new ArgumentOutOfRangeException("accuracy", "Must be > 0 and < 1.");
    }

    int sign = Math.Sign(value);

    if (sign == -1)
    {
        value = Math.Abs(value);
    }

    // Accuracy is the maximum relative error; convert to absolute maxError
    double maxError = sign == 0 ? accuracy : value * accuracy;

    int n = (int) Math.Floor(value);
    value -= n;

    if (value < maxError)
    {
        return new Fraction(sign * n, 1);
    }

    if (1 - maxError < value)
    {
        return new Fraction(sign * (n + 1), 1);
    }

    double z = value;
    int previousDenominator = 0;
    int denominator = 1;
    int numerator;

    do
    {
        z = 1.0 / (z - (int) z);
        int temp = denominator;
        denominator = denominator * (int) z + previousDenominator;
        previousDenominator = temp;
        numerator = Convert.ToInt32(value * denominator);
    }
    while (Math.Abs(value - (double) numerator / denominator) > maxError && z != (int) z);

    return new Fraction((n * denominator + numerator) * sign, denominator);
}

इस एल्गोरिथ्म द्वारा लौटाए गए उदाहरण मूल्य:

Accuracy: 1.0E-3      | Richards                     
Input                 | Result           Error       
======================| =============================
   3                  |       3/1          0         
   0.999999           |       1/1         1.0E-6     
   1.000001           |       1/1        -1.0E-6     
   0.50 (1/2)         |       1/2          0         
   0.33... (1/3)      |       1/3          0         
   0.67... (2/3)      |       2/3          0         
   0.25 (1/4)         |       1/4          0         
   0.11... (1/9)      |       1/9          0         
   0.09... (1/11)     |       1/11         0         
   0.62... (307/499)  |       8/13        2.5E-4     
   0.14... (33/229)   |      16/111       2.7E-4     
   0.05... (33/683)   |      10/207      -1.5E-4     
   0.18... (100/541)  |      17/92       -3.3E-4     
   0.06... (33/541)   |       5/82       -3.7E-4     
   0.1                |       1/10         0         
   0.2                |       1/5          0         
   0.3                |       3/10         0         
   0.4                |       2/5          0         
   0.5                |       1/2          0         
   0.6                |       3/5          0         
   0.7                |       7/10         0         
   0.8                |       4/5          0         
   0.9                |       9/10         0         
   0.01               |       1/100        0         
   0.001              |       1/1000       0         
   0.0001             |       1/10000      0         
   0.33333333333      |       1/3         1.0E-11    
   0.333              |     333/1000       0         
   0.7777             |       7/9         1.0E-4     
   0.11               |      10/91       -1.0E-3     
   0.1111             |       1/9         1.0E-4     
   3.14               |      22/7         9.1E-4     
   3.14... (pi)       |      22/7         4.0E-4     
   2.72... (e)        |      87/32        1.7E-4     
   0.7454545454545    |      38/51       -4.8E-4     
   0.01024801004      |       2/195       8.2E-4     
   0.99011            |     100/101      -1.1E-5     
   0.26... (5/19)     |       5/19         0         
   0.61... (37/61)    |      17/28        9.7E-4     
                      | 
Accuracy: 1.0E-4      | Richards                     
Input                 | Result           Error       
======================| =============================
   0.62... (307/499)  |     299/486      -6.7E-6     
   0.05... (33/683)   |      23/476       6.4E-5     
   0.06... (33/541)   |      33/541        0         
   1E-05              |       1/99999     1.0E-5     
   0.7777             |    1109/1426     -1.8E-7     
   3.14... (pi)       |     333/106      -2.6E-5     
   2.72... (e)        |     193/71        1.0E-5     
   0.61... (37/61)    |      37/61         0         

1

आपको दो बुनियादी समस्याएं होने वाली हैं जो इसे कठिन बना देंगी:

1) फ्लोटिंग पॉइंट एक सटीक प्रतिनिधित्व नहीं है, जिसका अर्थ है कि यदि आपके पास "x / y" का एक अंश है, जिसके परिणामस्वरूप "z" का मान होता है, तो आपका अंश एल्गोरिथ्म "x / y" के अलावा एक परिणाम दे सकता है।

2) तर्कसंगत की तुलना में अनंत कई अपरिमेय संख्याएँ हैं। एक तर्कसंगत संख्या वह है जिसे अंश के रूप में दर्शाया जा सकता है। तर्कहीन होने वाले जो नहीं कर सकते हैं।

हालांकि, सस्ते प्रकार में, चूंकि फ्लोटिंग पॉइंट की सीमा सटीकता है, तो आप इसे हमेशा किसी न किसी प्रकार के गुट के रूप में प्रतिनिधित्व कर सकते हैं। (मुझे लगता है...)


4
एक नाव (या डबल) है एक अंश। इसका हर दो की शक्ति है। यही कारण है कि वे कुछ तर्कसंगत संख्याओं का प्रतिनिधित्व नहीं कर सकते हैं।
इरिकसन

1

उपरोक्त कोड को पूरा किया और इसे as3 में बदल दिया

public static function toFrac(f:Number) : String
    {
        if (f>1)
        {
            var parte1:int;
            var parte2:Number;
            var resultado:String;
            var loc:int = String(f).indexOf(".");
            parte2 = Number(String(f).slice(loc, String(f).length));
            parte1 = int(String(f).slice(0,loc));
            resultado = toFrac(parte2);
            parte1 *= int(resultado.slice(resultado.indexOf("/") + 1, resultado.length)) + int(resultado.slice(0, resultado.indexOf("/")));
            resultado = String(parte1) +  resultado.slice(resultado.indexOf("/"), resultado.length)
            return resultado;
        }
        if( f < 0.47 )
            if( f < 0.25 )
                if( f < 0.16 )
                    if( f < 0.13 )
                        if( f < 0.11 )
                            return "1/10";
                        else
                            return "1/9";
                    else
                        if( f < 0.14 )
                            return "1/8";
                        else
                            return "1/7";
                else
                    if( f < 0.19 )
                        return "1/6";
                    else
                        if( f < 0.22 )
                            return "1/5";
                        else
                            return "2/9";
            else
                if( f < 0.38 )
                    if( f < 0.29 )
                        return "1/4";
                    else
                        if( f < 0.31 )
                            return "2/7";
                        else
                            return "1/3";
                else
                    if( f < 0.43 )
                        if( f < 0.40 )
                            return "3/8";
                        else
                            return "2/5";
                    else
                        if( f < 0.44 )
                            return "3/7";
                        else
                            return "4/9";
        else
            if( f < 0.71 )
                if( f < 0.60 )
                    if( f < 0.56 )
                        return "1/2";
                    else
                        if( f < 0.57 )
                            return "5/9";
                        else
                            return "4/7";
                else
                    if( f < 0.63 )
                        return "3/5";
                    else
                        if( f < 0.66 )
                            return "5/8";
                        else
                            return "2/3";
            else
                if( f < 0.80 )
                    if( f < 0.74 )
                        return "5/7";
                    else
                        if(f < 0.78 )
                            return "3/4";
                        else
                            return "7/9";
                else
                    if( f < 0.86 )
                        if( f < 0.83 )
                            return "4/5";
                        else
                            return "5/6";
                    else
                        if( f < 0.88 )
                            return "6/7";
                        else
                            if( f < 0.89 )
                                return "7/8";
                            else
                                if( f < 0.90 )
                                    return "8/9";
                                else
                                    return "9/10";
    }

धन्यवाद, मैंने डेल्फी के लिए इसका इस्तेमाल किया, जो कि घुंघराले सामान की तुलना में आसान है
पीटर टर्नर

1

यहां जावास्क्रिप्ट में एक त्वरित और गंदा कार्यान्वयन है जो एक क्रूर बल दृष्टिकोण का उपयोग करता है। बिल्कुल भी अनुकूलित नहीं है, यह अंशों की पूर्वनिर्धारित सीमा के भीतर काम करता है: http://jsfiddle.net/PdL23/1/

/* This should convert any decimals to a simplified fraction within the range specified by the two for loops. Haven't done any thorough testing, but it seems to work fine.

I have set the bounds for numerator and denominator to 20, 20... but you can increase this if you want in the two for loops.

Disclaimer: Its not at all optimized. (Feel free to create an improved version.)
*/

decimalToSimplifiedFraction = function(n) {

    for(num = 1; num < 20; num++) {  // "num" is the potential numerator
        for(den = 1; den < 20; den++) {  // "den" is the potential denominator
            var multiplyByInverse = (n * den ) / num;

            var roundingError = Math.round(multiplyByInverse) - multiplyByInverse;

            // Checking if we have found the inverse of the number, 
            if((Math.round(multiplyByInverse) == 1) && (Math.abs(roundingError) < 0.01)) {
                return num + "/" + den;
            }
        }
    }
};

//Put in your test number here.
var floatNumber = 2.56;

alert(floatNumber + " = " + decimalToSimplifiedFraction(floatNumber));

यह जेपीएस द्वारा उपयोग किए गए दृष्टिकोण से प्रेरित है।


0

जैसा कि कई लोगों ने कहा है कि आप वास्तव में फ़्लोटिंग पॉइंट को एक अंश में नहीं बदल सकते (जब तक कि यह बहुत सटीक न हो ।25)। बेशक, आप भिन्न प्रकार के अंशों के लिए कुछ प्रकार के लुक तैयार कर सकते हैं और आप जिस परिणाम की तलाश कर रहे हैं उसका उत्पादन करने के लिए कुछ प्रकार के फ़ज़ी लॉजिक का उपयोग कर सकते हैं। फिर भी यह सटीक नहीं होगा और आपको यह निर्धारित करने की आवश्यकता होगी कि आपके जाने वाले को कितना बड़ा हिस्सा चाहिए।

.32 <x <.34 = 1/3 या ऐसा ही कुछ।



0

मैं एक विशेष रूप से सुरुचिपूर्ण हस्केल समाधान में आया था जो एनामॉर्फिज़्म का उपयोग कर रहा था। यह इस पर निर्भर करता प्रत्यावर्तन-योजनाओं पैकेज।

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts    #-}

import           Control.Applicative   (liftA2)
import           Control.Monad         (ap)
import           Data.Functor.Foldable
import           Data.Ratio            (Ratio, (%))

isInteger :: (RealFrac a) => a -> Bool
isInteger = ((==) <*>) (realToFrac . floor)

continuedFraction :: (RealFrac a) => a -> [Int]
continuedFraction = liftA2 (:) floor (ana coalgebra)
    where coalgebra x
              | isInteger x = Nil
              | otherwise = Cons (floor alpha) alpha
                  where alpha = 1 / (x - realToFrac (floor x))

collapseFraction :: (Integral a) => [Int] -> Ratio a
collapseFraction [x]    = fromIntegral x % 1
collapseFraction (x:xs) = (fromIntegral x % 1) + 1 / collapseFraction xs

-- | Use the nth convergent to approximate x
approximate :: (RealFrac a, Integral b) => a -> Int -> Ratio b
approximate x n = collapseFraction $ take n (continuedFraction x)

यदि आप इसे gci में आज़माते हैं, तो यह वास्तव में काम करता है!

λ:> approximate pi 2
22 % 7
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.