Converting a floating-point decimal value to a fraction
Asked Answered
C

6

7

Given a decimal floating-point value, how can you find its fractional equivalent/approximation? For example:

as_fraction(0.1) -> 1/10
as_fraction(0.333333) -> 1/3
as_fraction(514.0/37.0) -> 514/37

Is there a general algorithm that can convert a decimal number to fractional form? How can this be implemented simply and efficiently in C++?

Caddis answered 30/10, 2014 at 1:46 Comment(6)
One idea, just an idea, figure out a way to find 2 fractions, one less than the answer, the other larger. Then from there, loop towards each other and find the closest, unless there is always going to be a whole number.Tutto
By "decimal", do you mean your input is a string of decimal digits and a decimal point, or do you simply mean, not integer? Note that both decimals and binary floating-point numbers actually are representations of fractions, but not necessarily the fraction you were thinking of. For example, the representation of the fraction 1/3 in either binary or decimal is actually a different number.Hartnett
There's an efficient algorithm outlined in this answer #12098961 It finds successively closer fractional approximations of "nice" form.Instruction
I wrote up an answer, but since this has been closed I've put it as a gist : gist.github.com/mikeando/7073d62385a34a61a6f7Instruction
There's a slightly better answer at https://mcmap.net/q/162111/-algorithm-for-simplifying-decimal-to-fractions, and my gist now contains a C++ implementation of it and a comparison of the two methods.Instruction
Old question, but with a continued fraction, you get a series of ever better approximations. E.g. pi≈3; pi≈3+1/7; pi≈3+1/(7+1/16)=3+16/113; pi≈3+1/(7+1/(16-1/294))=3+4703/33215 -> accurate up to 10 digits!Nuclear
J
11

First get the fractional part and then take the gcd. Use the Euclidean algorithm http://en.wikipedia.org/wiki/Euclidean_algorithm

void foo(double input)
{
    double integral = std::floor(input);
    double frac = input - integral;

    const long precision = 1000000000; // This is the accuracy.

    long gcd_ = gcd(round(frac * precision), precision);

    long denominator = precision / gcd_;
    long numerator = round(frac * precision) / gcd_;

    std::cout << integral << " + ";
    std::cout << numerator << " / " << denominator << std::endl;
}

long gcd(long a, long b)
{
    if (a == 0)
        return b;
    else if (b == 0)
        return a;

    if (a < b)
        return gcd(a, b % a);
    else
        return gcd(b, a % b);
}
Jarry answered 30/10, 2014 at 2:6 Comment(9)
I don't think you should be dividing by the denominator, and this won't find the "nicest" fraction, but it is a reasonable approach to getting some reduced fraction.Hartnett
This site can help some people to understand your algorithm: webmath.com/dec2fract.htmlEaton
@BenVoigt: Sorry that was a typo.Jarry
@Ludovic: That webpage uses a very different algorithm. Try putting 0.3333333 into it.Hartnett
@benVoigt ok i saw what you mean but it can be a good help to understand it, isn't it?Eaton
+1 frac = input - (long) input; - maybe better to use input - std::floor(input)...?Cliff
@BenVoigt the site appears to use at least two different algorithms, depending on the number you give it. One of them is very similar to this answer, and both depend on the GCD as shown here.Cetane
Gah, that web2frac is aweful. Tried it on 1.17171 and it gave nothing of value. The algorithm in my gist gives the values "41/35", "116/99" and "1549/1322" as successively better approximations.Instruction
@MichaelAnderson: Good answer. I think you had is a good idea to use continued fractions.Jarry
E
7
#include <iostream>
#include <valarray> 

using namespace std;

void as_fraction(double number, int cycles = 10, double precision = 5e-4){
    int sign  = number > 0 ? 1 : -1;
    number = number * sign; //abs(number);
    double new_number,whole_part;
    double decimal_part =  number - (int)number;
    int counter = 0;
    
    valarray<double> vec_1{double((int) number), 1}, vec_2{1,0}, temporary;
    
    while(decimal_part > precision & counter < cycles){
        new_number = 1 / decimal_part;
        whole_part = (int) new_number;
        
        temporary = vec_1;
        vec_1 = whole_part * vec_1 + vec_2;
        vec_2 = temporary;
        
        decimal_part = new_number - whole_part;
        counter += 1;
    }
    cout<<"x: "<< number <<"\tFraction: " << sign * vec_1[0]<<'/'<< vec_1[1]<<endl;
}

int main()
{
    as_fraction(3.142857);
    as_fraction(0.1);
    as_fraction(0.333333);
    as_fraction(514.0/37.0);
    as_fraction(1.17171717);
    as_fraction(-1.17);
}


x: 3.14286      Fraction: 22/7                                                                                                                
x: 0.1          Fraction: 1/10                                                                                                                        
x: 0.333333     Fraction: 1/3                                                                                                                 
x: 13.8919      Fraction: 514/37                                                                                                              
x: 1.17172      Fraction: 116/99                                                                                                              
x: 1.17         Fraction: -117/100

Sometimes you would want to approximate the decimal, without needing the equivalence. Eg pi=3.14159 is approximated as 22/7 or 355/113. We could use the cycles argument to obtain these:

as_fraction(3.14159, 1);
as_fraction(3.14159, 2);
as_fraction(3.14159, 3);

x: 3.14159      Fraction: 22/7                                                                                                                
x: 3.14159      Fraction: 333/106                                                                                                             
x: 3.14159      Fraction: 355/113
Embarrass answered 13/11, 2020 at 22:17 Comment(10)
@Embarrass Could you elaborate on what cycles and precision are supposed to mean? It is not obvious (to me, at least) why 0.33328, 0.3333 and 0.33338 would all return the fraction 1/3.Consultation
@Consultation increase the number of cycles and precision and you will have the result. eg as_fraction(0.33328,10, 1e-7);Embarrass
@Embarrass Thanks, but that would only shift the question to different examples. Could you state (in the answer) what the expected result is in terms of cycles and precision in general? Without that, I can't even tell whether 1/3 is the correct answer in those cases, simply because I don't know what the function is expected to return.Consultation
@Consultation i ran that and I got 2083/6250 which is exactly 0.33328. This is the reason as to why I gave the precision and cycles parametersEmbarrass
@Embarrass That you get a different result on your machine than the 1/3 that I linked to only confirms that this is implementation dependent, and inherently unreliable. Leaving that aside for a moment, though, you have still not defined what the function is supposed to return in terms of its arguments. I don't see the point of a function whose behavior remains unspecified. Something like "as_fraction returns <whatever>" would be a proper description. "If you don't like the result use a different precision" is not.Consultation
@Consultation and as_fraction(0.33338,10, 1e-7); will give you 16669/50000. The higher the precision, the more correct the approximation. Note that when you write 0.3333 for example, this can be interpreted as 3333/10000 rather than 1/3. So you need to really tell when you need 1/3 or even 3333/10000 and you could use the cycle and precision parameters. The best thing to do is try and give the correct values into the function. ie x<- 234.0/67.0; as_fraction(x); in this case, the value of x passed is quite accurate as compared to 3.492Embarrass
Any result could be defended, as long as you do not (or cannot) specify what the expected return of the function is in the general case.Consultation
@Consultation technically, there there is no decimal equivalent for 1/3 but we still take 0.3333 as an approximateEmbarrass
@dxiv. The function I wrote kind of tries to approximate the fractional representation of a decimal up to the 4th significant value. eg 0.333 =>333/1000, while 0.3333=>1/3. Note that when you have 0.33332=>1/3. So can use the precision argument and/or cycles argument to increase the precision of your fraction estimation. You can look at the algorithm under continued fractions on wikipediaEmbarrass
The main difficulty in defining what as_fraction actually does is that you cannot guarantee consistent results as long as you are using floating point calculations in that loop. The rest of my would-be comment had to go into an "answer" of sorts because it wouldn't fit here.Consultation
C
1

(Too long for a comment.)

Some comments claim that this is not possible. But I am of a contrary opinion.

I am of the opinion that it is possible in the right interpretation, but it is too easy to misstate the question or misunderstand the answer.

The question posed here is to find rational approximation(s) to a given floating point value.

This is certainly possible since floating point formats used in C++ can only store rational values, most often in the form of sign/mantissa/exponent. Taking IEEE-754 single precision format as an example (to keep the numbers simpler), 0.333 is stored as 1499698695241728 * 2^(-52). That is equivalent to the fraction 1499698695241728 / 2^52 whose convergents provide increasingly accurate approximations, all the way up to the original value: 1/3, 333/1000, 77590/233003, 5586813/16777216.

Two points of note here.

  • For a variable float x = 0.333; the best rational approximation is not necessarily 333 / 1000, since the stored value is not exactly 0.333 but rather 0.333000004291534423828125 because of the limited precision of the internal representation of floating points.

  • Once assigned, a floating point value has no memory of where it came from, or whether the source code had it defined as float x = 0.333; vs. float x = 0.333000004; because both of those values have the same internal representation. This is why the (related, but different) problem of separating a string representation of a number (for example, a user-entered value) into integer and fractional parts cannot be solved by first converting to floating point then running floating point calculations on the converted value.


[ EDIT ]   Following is the step-by-step detail of the 0.333f example.

  1. The code to convert a float to an exact fraction.
#include <cfloat>
#include <cmath>
#include <limits>
#include <iostream>
#include <iomanip>

void flo2frac(float val, unsigned long long* num, unsigned long long* den, int* pwr)
{
    float mul = std::powf(FLT_RADIX, FLT_MANT_DIG);
    *den = (unsigned long long)mul;
    *num = (unsigned long long)(std::frexp(val, pwr) * mul);
    pwr -= FLT_MANT_DIG;
}

void cout_flo2frac(float val)
{
    unsigned long long num, den; int pwr;
    flo2frac(val, &num, &den, &pwr);

    std::cout.precision(std::numeric_limits<float>::max_digits10);
    std::cout << val << " = " << num << " / " << den << " * " << FLT_RADIX << "^(" << pwr << ")" << std::endl;
}

int main()
{
    cout_flo2frac(0.333f);
}
  1. Output.
0.333000004 = 11173626 / 16777216 * 2^(-1)
  1. This gives the rational representation of float val = 0.333f; as 5586813/16777216.

  2. What remains to be done is determine the convergents of the exact fraction, which can be done using integer calculations, only. The end result is (courtesy WA):

0, 1/3, 333/1000, 77590/233003, 5586813/16777216
Consultation answered 14/11, 2020 at 4:14 Comment(10)
could you try as_fractions(0.333) it will give you 333/1000 and not 1/3 but try increasing that ie as_fractions(0.333333333) this will give you 1/3. So what point exactly are you trying to put across? What is the contention about? Get any simple fraction ie upto 4 significant places and try it out and see whether you will not get the result you want. The notion here is to try and do an approximation. First we can not have an exact 1/3 representation. even a simple 1/10 which is 0.1 does not have exact representation in Binary. The method I provided which is a simple continued fraction is...Embarrass
used by matlab and R and probably others to represent decimals to fraction equivalent, with the. In matlab, the precision is to 1e-6 i believe whereby 0.3333333 will be 1/3 and thus 0.33333333768 will still be 1/3. So I just presented a quick way of solving the problem in C++. You can write the same function while letting the default precision to be 1e-8 and you will have pretty accurate fractional approximations of the fractionEmbarrass
@Embarrass 1) Again, you ask the user to tweak the parameters in order to obtain a result they know already. That's not how it's supposed to work. Instead, you should document what the function does and what the expected result is in terms of its inputs. 2) But that is difficult to do with the code as-is, because of numerical instabilities due to using floating point in the intermediate calculations e.g. I posted a link to 0.33328 returning 1/3 while you got 2083/6250. 3) There is a right way to do it, using exact integers as described above, but that takes considerably more work.Consultation
@Embarrass "Get any simple fraction ie upto 4 significant places and try it out and see whether you will not get the result you want" If I "wanted" a certain result, I wouldn't need to call the function to begin with ;-) For "simple examples", as_fraction(987.0/610.0); returns 144/89, and (4181.0/6765.0) returns 55/89. I am not saying the results are wrong, and neither can I say they are right, simply because the function does not set any expectation of what it is supposed to be returning.Consultation
I feel we are in different spectrums. Could you please just define a funtion that would transform a decimal to its approximate/equivalent fraction just like in matlab, R, Python and the rest and post it here. Let it not be too sophisticated. I would indeed accept your answer.Embarrass
@Embarrass See for example frexp and how can I extract the mantissa of a double.Consultation
In no way does frexp give a rational representation of a number. Eg if you are given 0.1, it does not return 1/10. Please look at the question again. We need a rational representation of a decimal numberEmbarrass
@Embarrass You are missing the point that there is no double that has a value of exactly 0.1. When you write double x = 0.1; what gets stored in x is a value close to, but not equal to 0.1.Consultation
Yes there is no double that is exactly 0.1. That is true. But could you get a rational approximation of 0.1? Please note that that rational approximation is used in mathematica, matlab, Python, R etc. So what is the issue of contention? My funtion is a simple funtion that can do the rational approximation. Is it 100%correct? Of course not. Even the built in funtion in matlab is not 100%accurate.Embarrass
@Embarrass I added the code to convert a floating point value to the exact rational fraction (less error checking etc). After that, you can add the integer calculations for convergents, and write a function that returns consistent, predictable results. And of course, you can use similar code to "get a rational approximation of 0.1". All being said, I'll leave it at that since this doesn't seem to be going anywhere.Consultation
C
0

I came up with an algorithm for this problem, but I think it is too lengthy and can be accomplished with less lines of code. Sorry about the poor indentation it is hard trying to align everything on overflow.

#include <iostream>
using namespace std;


// converts the string half of the inputed decimal number into numerical values void converting
 (string decimalNumber, float&numerator, float& denominator )

 { float number; string valueAfterPoint =decimalNumber.substr(decimalNumber.find("."    ((decimalNumber.length() -1) )); // store the value after the decimal into a valueAfterPoint 

int length = valueAfterPoint.length(); //stores the length of the value after the decimal point into length 

numerator = atof(valueAfterPoint.c_str()); // converts the string type decimal number into a float value and stores it into the numerator

// loop increases the decimal value of the numerator by multiples of ten as long as the length is above zero of the decimal

for (; length > 0; length--)  
    numerator *= 10;

do
 denominator *=10;
  while  (denominator < numerator);



// simplifies the the converted values of the numerator and denominator into simpler values for          an easier to read output 


void simplifying (float& numerator, float& denominator) { int maximumNumber = 9; //Numbers in the tenths place can only range from zero to nine so the maximum number for a position in a position for the decimal number will be nine

bool isDivisble; // is used as a checker to verify whether the value of the numerator has the       found the dividing number that will a value of zero
 // Will check to see if the numerator divided denominator is will equal to zero


   if(int(numerator) % int(denominator) == 0) {
   numerator /= denominator;
   denominator = 1;   
   return; }


  //check to see if the maximum number is greater than the denominator to simplify to lowest     form while (maximumNumber < denominator) { maximumNumber *=10;  }


 // the maximum number loops from nine to zero. This conditions stops if the function isDivisible is true 
 for(; maximumNumber > 0;maximumNumber --){

 isDivisble = ((int(numerator) % maximumNumber == 0) && int(denominator)% maximumNumber == 0);

  if(isDivisble)
 {
    numerator /= maximumNumber;  // when is divisible true numerator be devided by the max        number value for example 25/5 = numerator = 5

   denominator /= maximumNumber; //// when is divisible true denominator be devided by themax        number value for example 100/5 = denominator = 20

 }


 // stop value if numerator and denominator is lower than 17 than it is at the lowest value
 int stop = numerator + denominator;

 if (stop < 17)
 {
     return;
 } } }   
Caddis answered 30/10, 2014 at 1:46 Comment(0)
M
0

I agree completely with dxiv's solution but I needed a more general function (I threw in the signed stuff for fun because my use cases only included positive values):

#include <concepts>

/**
 * \brief Multiply two numbers together checking for overflow.
 * \tparam T The unsigned integral type to check for multiplicative overflow.
 * \param a The multiplier.
 * \param b The multicland.
 * \return The result and a value indicating whether the multiplication 
 *         overflowed.
 */
template<std::unsigned_integral T>
auto mul_overflow(T a, T b) -> std::tuple<T, bool>
{
    size_t constexpr shift{ std::numeric_limits<T>::digits / 2 };
    T constexpr mask{ (T{ 1 } << shift) - T{ 1 } };
    T const a_high = a >> shift;
    T const a_low = a & mask;
    T const b_high = b >> shift;
    T const b_low = b & mask;

    T const low_low{ a_low * b_low };
    if (!(a_high || b_high))
    {
        return { low_low, false };
    }

    bool overflowed = a_high && b_high;
    T const low_high{ a_low * b_high };
    T const high_low{ a_high * b_low };

    T const ret{ low_low + ((low_high + high_low) << shift) };
    return
    {
        ret,
        overflowed
        || ret < low_low
        || (low_high >> shift) != 0
        || (high_low >> shift) != 0
    };
}

/**
 * \brief Converts a floating point value to a numerator and
 * denominator pair.
 *
 * If the floating point value is larger than the maximum that the Tout
 * type can hold, the results are silly.
 *
 * \tparam Tout The integral output type.
 * \tparam Tin The floating point input type.
 * \param f The value to convert to a numerator and denominator.
 * \return The numerator and denominator.
 */
template <std::integral Tout, std::floating_point Tin>
auto to_fraction(Tin f) -> std::tuple<Tout, Tout>
{
    const Tin multiplier
    {
        std::pow(std::numeric_limits<Tin>::radix, 
                 std::numeric_limits<Tin>::digits)
    };
    uint64_t denominator{ static_cast<uint64_t>(multiplier) };
    int power;
    Tout num_fix{ 1 };
    if constexpr (std::is_signed_v<Tout>)
    {
        num_fix = f < static_cast<Tin>(0) ? -1 : 1;
        f = std::abs(f);
    }

    uint64_t numerator
    {
        static_cast<uint64_t>(std::frexp(f, &power) * multiplier)
    };
    uint64_t const factor
    {
        static_cast<uint64_t>(std::pow(
            std::numeric_limits<Tin>::radix, std::abs(power)))
    };
    if (power > 0)
    {
        while(true)
        {
            auto const [res, overflow]{ mul_overflow(numerator, factor) };
            if (!overflow)
            {
                numerator = res;
                break;                    
            }
            numerator >>= 1;
            denominator >>= 1;
        }
    }
    else
    {
        while (true)
        {
            auto const [res, overflow]{ mul_overflow(denominator, factor) };
            if (!overflow)
            {
                denominator = res;
                break;
            }
            numerator >>= 1;
            denominator >>= 1;
        }
    }

    // get the results into the requested sized integrals.
    while ((numerator > std::numeric_limits<Tout>::max()
            || denominator > std::numeric_limits<Tout>::max())
           && denominator > 1)
    {
        numerator >>= 1;
        denominator >>= 1;
    }

    return 
    {
        num_fix * static_cast<Tout>(numerator),
        static_cast<Tout>(denominator)
    };
}

You can call this like:

auto [n, d] { to_fraction<int8_t>(-124.777f) };

And you get n=-124, d=1;

auto [n, d] { to_fraction<uint64_t>(.33333333333333) };

gives n=6004799503160601, d=18014398509481984

Manns answered 3/6, 2022 at 12:4 Comment(0)
N
0
#include<iostream>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<string>
#include<vector>
#include <exception>
#include <sstream>

// note using std = c++11
// header section

#ifndef rational_H
#define rational_H

struct invalid : std::exception {
    const char* what() const noexcept { return "not a number\n"; }};

struct Fraction {
public:
    long long value{0};
    long long numerator{0};
    long long denominator{0};
}; Fraction F;

class fraction : public Fraction{

public:
    fraction() {}
    void ctf(double &);
    void get_fraction(std::string& w, std::string& d, long double& n) {
        F.value = (long long )n;
        set_whole_part(w);
        set_fraction_part(d);
        make_fraction();
    }
    long long set_whole_part(std::string& w) {
        return whole = std::stoll(w);
    }
    long long set_fraction_part(std::string& d) {
         return decimal = std::stoll(d);
    }
    void make_fraction();
    bool cmpf(long long&, long long&, const long double& epsilon);
    int Euclids_method(long long&, long long&);

    long long get_f_part() { return decimal; };
    void convert(std::vector<long long>&);
    bool  is_negative{ false };

    friend std::ostream& operator<<(std::ostream& os, fraction& ff);
    struct get_sub_length;

private:
    long long whole{ 0 };
    long long decimal{ 0 };
};
#endif // rational_H

// definitions/source

struct get_sub_length {
    size_t sub_len{};
    size_t set_decimal_length(size_t& n) {
        sub_len = n;
        return sub_len;
    }
    size_t get_decimal_length() { return sub_len; }
}; get_sub_length slen;

struct coefficient {
    std::vector<long long>coef;
}; coefficient C;

//compare's the value returned by convert with the original 
// decimal value entered.
//if its within the tolarence of the epsilon consider it the best
//approximation you can get.
//feel free to experiment with the epsilon.
//for better results.
 
bool fraction::cmpf(long long& n1, long long& d1, const long double& epsilon = 0.0000005) 
{
long double ex = pow(10, slen.get_decimal_length());
long long  d = get_f_part();       // the original fractional part to use for comparison.
long double  a = (long double)d / ex;
long double b = ((long double)d1 / (long double)n1);
if ((fabs(a - b) <= epsilon)) { return true; }
return false;
}

//Euclids algorithm returns the cofficients of a continued fraction through recursive division,
//for example: 0.375 -> 1/(375/1000) (note: for the fractional portion only).
// 1000/375 -> Remainder of 2.6666.... and  1000 -(2*375)=250,using only the integer value
// 375/250 -> Remainder of 1.5  and   375-(1*250)=125,
// 250/125 -> Remainder of 2.0  and   250-(2*125)=2
//the coefficients of the continued fraction are the integer values 2,1,2
// These are generally written [0;2,1,2] or [0;2,1,1,1] were 0 is the whole number value.

int fraction::Euclids_method(long long& n_dec, long long& exp) 
{

    long long quotient = 0;

    if ((exp >= 1) && (n_dec != 0)) {
        quotient = exp / n_dec;

        C.coef.push_back(quotient);

        long long divisor = n_dec;
        long long dividend = exp - (quotient * n_dec);

        Euclids_method(dividend, divisor); // recursive division 
    }
    return 0;
}

 // Convert is adding the elements stored in coef as a simple continued fraction
// which should result in a good approximation of the original decimal number.

void fraction::convert(std::vector<long long>& coef) 
{
    std::vector<long long>::iterator pos;
    pos = C.coef.begin(), C.coef.end();
    long long n1 = 0;
    long long n2 = 1;
    long long d1 = 1;
    long long d2 = 0;

    for_each(C.coef.begin(), C.coef.end(), [&](size_t pos) {

        if (cmpf(n1, d1) == false) {

            F.numerator = (n1 * pos) + n2;
            n2 = n1;
            n1 = F.numerator;

            F.denominator = (d1 * pos) + d2;
            d2 = d1;
            d1 = F.denominator;
        }
    });

    //flip the fraction back over to format the correct output.
    F.numerator = d1;
    F.denominator = n1;
}

// creates a fraction from the decimal component
// insures its in its abs form to ease calculations.

void fraction::make_fraction() {

    size_t count = slen.get_decimal_length();
    long long n_dec = decimal;
    long long exp = (long long)pow(10, count);

    Euclids_method(n_dec, exp);
    convert(C.coef);
}

std::string get_w(const std::string& s) 
{
    std::string st = "0";
    std::string::size_type pos;
    pos = s.find(".");
        if (pos - 1 == std::string::npos) {
            st = "0";
            return st;
        }
        else { st = s.substr(0, pos);
        return st;
        }

    if (!(s.find("."))){
            st = "0";
        return st;
    }
    return st;
 }

std::string get_d(const std::string& s)
{ 
    std::string st = "0";
    std::string::size_type pos;
        pos = s.find(".");
        if (pos == std::string::npos) {
            st = "0";
            return st;
        }
        std::string sub = s.substr(pos + 1);
            st = sub;
                size_t sub_len = sub.length(); 
                    slen.set_decimal_length(sub_len);
        return st;
}

void fraction::ctf(double& nn)
{
        //using stringstream for conversion to string
        std::istringstream is;
        is >> nn;
        std::ostringstream os;
        os << std::fixed << std::setprecision(14) << nn;

        std::string s = os.str();

        is_negative = false; //reset for loops
        C.coef.erase(C.coef.begin(), C.coef.end()); //reset for loops

        long double n = 0.0;
        int m = 0;

        //The whole number part will be seperated from the decimal part leaving a pure fraction.
        //In such cases using Euclids agorithm would take the reciprocal 1/(n/exp) or exp/n.
        //for pure continued fractions the cf must start with 0 + 1/(n+1/(n+...etc
        //So the vector is initilized with zero as its first element.

        C.coef.push_back(m);
        std::cout << '\n';
    
        if (s == "q") { // for loop structures
            exit(0);
        }

        if (s.front() == '-') { // flag negative values. 
            is_negative = true; // represent nagative in output
            s.erase(remove(s.begin(), s.end(), '-'), s.end()); // using abs
        }

        // w, d, seperate the string components
        std::string w = get_w(s); 
        std::string d = get_d(s);

        try
        {
            if (!(n = std::stold(s))) {throw invalid(); } // string_to_double()
            get_fraction(w, d, n);
        } 
        catch (std::exception& e) {
            std::cout << e.what();
            std::cout <<'\n'<< std::endl;
        }
}

// The ostream formats and displays the various outputs

std::ostream& operator<<(std::ostream& os, fraction& f) 
{
    std::cout << '\n';
    if (f.is_negative == true) {
        os << "The coefficients are [" << '-' << f.whole << ";";
            for (size_t i = 1; i < C.coef.size(); ++i) {
                os << C.coef[i] << ',';
            }
            std::cout << "]" << '\n';
        os << "The cf is: " << '-' << f.whole;
            for (size_t i = 1; i < C.coef.size(); ++i) {
                os << "+1/(" << C.coef[i];
            }
            for (size_t i = 1; i < C.coef.size(); ++i) {
                os << ')';
            }
            std::cout << '\n';

        if (F.value >= 1 && F.numerator == 0 && F.denominator == 1) {
            F.numerator = abs(f.whole);
                os << '-' << F.numerator << '/' << F.denominator << '\n';
                return os;
        }
        else if (F.value == 0 && F.numerator == 0 && F.denominator == 1) {
                os << F.numerator << '/' << F.denominator << '\n';
                return os;
        }
        else if (F.value == 0 && F.numerator != 0 && F.denominator != 0) {
                os << '-' << abs(F.numerator) << '/' << abs(F.denominator) << '\n';
                return os;
        }
        else if (F.numerator == 0 && F.denominator == 0) {
                os << '-' << f.whole << '\n';
                return os;
        }
        else
                os << '-' << (abs(f.whole) * abs(F.denominator) + abs(F.numerator)) << '/' << abs(F.denominator) << '\n';
    }

    if (f.is_negative == false) {

        os << "The coefficients are [" << f.whole << ";";
             for (size_t i = 1; i < C.coef.size(); ++i) {
                os << C.coef[i] << ',';
            }
            std::cout << "]" << '\n';
        os << "The cf is: " << f.whole;
            for (size_t i = 1; i < C.coef.size(); ++i) {
                os << "+1/(" << C.coef[i];
            }
            for (size_t i = 1; i < C.coef.size(); ++i) {
                os << ')';
            }
            std::cout << '\n';

        if (F.value >= 1 && F.numerator == 0 && F.denominator == 1) {
            F.numerator = abs(f.whole);
                os << F.numerator << '/' << F.denominator << '\n';
                return os;
        }
        else if (F.value == 0 && F.numerator != 0 && F.denominator != 0) {
                os << abs(F.numerator) << '/' << abs(F.denominator) << '\n';
                return os;
        }
        else if (F.numerator == 0 && F.denominator == 0) {
            os << f.whole << '\n';
            return os;
        }
        else
            os << (abs(f.whole) * abs(F.denominator) + abs(F.numerator)) << '/' << abs(F.denominator) << '\n';

            os << f.whole << ' ' << F.numerator << '/' << F.denominator << '\n';
    }
    return os;
}

int main() 
{
    fraction f;
    double s = 0;
    std::cout << "Enter a number to convert to a fraction\n";
    std::cout << "Enter a \"q\" to quit\n";
    // uncomment for a loop

    while (std::cin >> s) {
        f.ctf(s);
        std::cout << f << std::endl;
    }

    // comment out these lines if you want the loop

    //std::cin >> s; 
    //f.ctf(s);
    //std::cout << f << std::endl;
 }
Nougat answered 6/11, 2022 at 4:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.