Need help reducing negative fraction, also using istream

Pages: 12
Apr 22, 2020 at 3:06am
My problem consists of attempting to reduce a mixed fraction and not reducing the positive mixed fraction to match the output of my assignment *Will provide that below*. I am also having trouble reading a Fraction from a stream using an istream extraction (>>) overloaded operator and displaying the file contents which I will also provide sample output below as well. Any help would be appreciated I am really stuck.

---SAMPLE OUTPUT FOR BOTH THE REDUCING AND ISTREAM READABILITY-----
***********************************************************************
* Basic Test: Testing member constructor, simplify() and nonmember *
* friend ostream << operator for basic Fraction object creation & *
* printing(Fractions should be in reduced form, and as mixed numbers.)*
***********************************************************************
Fraction [0] = 1/2
Fraction [1] = -5/7
Fraction [2] = 10
Fraction [3] = -4
Fraction [4] = 0
Fraction [5] = 4+2/3
Fraction [6] = 0

***********************************************************************
* Basic Test: Testing simplify() and nonmember friend istream >> and *
* ostream << operators for reading and display of Fraction objects *
* from data file *
***********************************************************************
Enter file name with fraction data to read: frac.txt
frac.txt not found!
Make sure the fraction data file to read is in the project folder.
Enter file name with fraction data to read: frac_data.txt
Read Fraction = -1/3
Read Fraction = 1/2
Read Fraction = 3/4
Read Fraction = -4/5
Read Fraction = 6
Read Fraction = 5
Read Fraction = -8
Read Fraction = 1+2/5
Read Fraction = -16+2/3
Read Fraction = 1+1/4
Read Fraction = 2
Read Fraction = -4+1/4
Read Fraction = -10+5/6

MY OUTPUT FOR THE FIRST PART:
* friend ostream << operator for basic Fraction object creation & *
* printing(Fractions should be in reduced form, and as mixed numbers.)*
***********************************************************************
Fraction [0] = 1/2

Fraction [1] = -5/7

Fraction [2] = 10

Fraction [3] = -4+0/-1

Fraction [4] = 0

Fraction [5] = 4+2/3

Fraction [6] = 0


Project#2 -Fraction class (ADT) testing now concluded.
Check output for correct results from the Fraction class (ADT) implementation.

Process returned 0 (0x0) execution time : 0.094 s
Press any key to continue.


Code for my header file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*USED FOR CLASS WITH FUNCTIONS ETC */
#ifndef FRACTION_H
#define FRACTION_H

#include <iostream>
#include <cmath>
#include <cctype>
#include <cassert>
using namespace std;

namespace cs10b_fraction
{
class Fraction
{
public:
    Fraction(int n = 0, int d = 1)
    {
        num = n;
        denom = d;
        assert(denom != 0);
        Simplify();
    }

friend ostream& operator << (std::ostream &out, const Fraction printMe);
friend std::istream& operator >> (std::istream &in, Fraction readMe);

private:
    int num;
    int denom;

    void Simplify();
};
}

#endif


Code for my implementation file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* USED FOR FUNCTIONS */
#include <iostream>
#include <cmath>
#include <cctype>
#include <cassert>
#include "fraction.h"
using namespace std;

namespace cs10b_fraction
{

void Fraction::Simplify()
//Pre:
//This function will reduce the two fractions
//after it has been transformed and output them
//correctly

//Post:
//The result of the two fractions after they are transformed
//are reduced
{
    //For loop that goes through and simplifies fraction
    for(int i = abs(num * denom); i > 1; i--)
    {
        if((num % i) == 0 && (denom % i) == 0)
        {
            num = num / i;
            denom = denom / i;
        }
    }
}

ostream& operator << (std::ostream &out, const Fraction printMe)
{

    if (printMe.denom == 1)
    {
        out << printMe.num << endl;
    }

    else if (printMe.num == 0)
    {
        out << printMe.num << endl;
    }

    else if(printMe.num < printMe.denom && printMe.num != 0)
        out << printMe.num << "/" << printMe.denom << endl;

    else if(abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << "+" << (printMe.num % printMe.denom) << "/" << printMe.denom << endl;



   /* else if (abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << endl;

    else if (abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << "+" << (printMe.num % printMe.denom) << "/" << printMe.denom << endl; */

    return out;
}

istream& operator >> (std::istream &in, Fraction readMe)
{

    

}



Code for my client file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include "fraction.h"
#include <fstream>
#include <cassert>
#include <string>
using namespace std;
using namespace cs10b_fraction;

void BasicTest();
void RelationTest();
void BinaryMathTest();
void MathAssignTest();
bool eof(/*inout*/ifstream& in);
string boolString(/*in*/bool convertMe);


int main()
{
    cout << "Project#2: Fraction class (ADT) client program to test CLASS INVARIANT\n";
    cout << "There are two data members used to represent the denominator and numerator\n";
    cout << "for each instance of a Fraction class object class.\n";
    cout << "The client code provides an interface to test correct operations on fraction  \n";
    cout << "objects that are negative, improper (larger numerator than denominator), \n";
    cout << "or whole numbers (denominator of 1).\n";
    cout << "Here is a list test type and order in which the tests will be conducted\n";
    cout << "1. BasicTest\n";
    cout << "2. RelationTest\n";
    cout << "3. BinaryMathTest\n";
    cout << "4. MathAssignTest\n\n";

    BasicTest();
    /*RelationTest();
    BinaryMathTest();
    MathAssignTest();*/

    cout << "\nProject#2 -Fraction class (ADT) testing now concluded.\n";
    cout << "Check output for correct results from the Fraction class (ADT) implementation.\n";

     return 0;
}

// Function provides the interface to test the following Fraction class member implementation algorithms
// Class constructor, a fraction reduction algorithm in simplify, and two nonmember friend ostream << and istream >> operator functions
void BasicTest()
{
    cout << "***********************************************************************\n";
    cout << "* Basic Test: Testing member constructor, simplify() and nonmember    *\n";
    cout << "* friend ostream << operator for basic Fraction object creation &     *\n";
    cout << "* printing(Fractions should be in reduced form, and as mixed numbers.)*\n";
    cout << "***********************************************************************\n";

    const Fraction fr[] = {Fraction(4, 8), Fraction(-15,21),
                           Fraction(10), Fraction(12, -3),
                           Fraction(), Fraction(28, 6), Fraction(0, 12)};

    for (int i = 0; i < 7; i++){
        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
    }

    cout << "\n***********************************************************************\n";
    cout << "* Basic Test: Testing simplify() and nonmember friend istream >> and  *\n";
    cout << "* ostream << operators for reading and display of Fraction objects    *\n";
    cout << "* from data file                                                      *\n";
    cout << "***********************************************************************\n";

    string fileName;

    cout << "Enter file name with fraction data to read: ";
    cin >> fileName;

    ifstream in(fileName);

    while(!in)
    {
        cin.ignore(200, '\n');
        cout << fileName << " not found!" <<endl;
        cout << "Make sure the fraction data file to read is in the project folder." << endl;
        cout << "Enter file name with fraction data to read: ";
        cin >> fileName;
        in.open(fileName);
    }

    while (!eof(in)) {
        Fraction f;
        if(in.peek() == '/' || in.peek() == '*' || isalpha(in.peek()) ){
            in.ignore(200, '\n');   //skip this line, it's a comment
        } else {
            in >> f;
            cout << "Read Fraction = " << f << endl;
        }
    }
}
Last edited on Apr 22, 2020 at 3:29am
Apr 22, 2020 at 4:27am
.
Last edited on Apr 23, 2020 at 2:53am
Apr 22, 2020 at 4:29am
I believe std::regex may be quite useful here:
 
std::regex(R"((?:([+-]?\d*)\+)?(\d+)\/([+-]?\d+))")


Or something similar
Last edited on Apr 22, 2020 at 4:30am
Apr 22, 2020 at 4:41am
My class has not learned about regex yet so I am a bit of unaware on how to use it.
Last edited on Apr 22, 2020 at 4:42am
Apr 22, 2020 at 5:23am
Before you worry about reading from a file, fix your basic test.

> Fraction [3] = -4+0/-1
You (or indeed any other newbies reading) need to learn how to use a debugger if you ever want to get past the "hello world" stage and into writing non-trivial programs.
If you're using a "visual" IDE, then you almost certainly have a "visual" debugger with it.

Anyway,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
$ g++ -std=c++11 -g foo.cpp
$ gdb -q ./a.out
Reading symbols from ./a.out...done.
(gdb) b 147
Breakpoint 1 at 0x400d02: file foo.cpp, line 147.
(gdb) run
Starting program: a.out 
Project#2: Fraction class (ADT) client program to test CLASS INVARIANT
There are two data members used to represent the denominator and numerator
for each instance of a Fraction class object class.
The client code provides an interface to test correct operations on fraction  
objects that are negative, improper (larger numerator than denominator), 
or whole numbers (denominator of 1).
Here is a list test type and order in which the tests will be conducted
1. BasicTest
2. RelationTest
3. BinaryMathTest
4. MathAssignTest

***********************************************************************
* Basic Test: Testing member constructor, simplify() and nonmember    *
* friend ostream << operator for basic Fraction object creation &     *
* printing(Fractions should be in reduced form, and as mixed numbers.)*
***********************************************************************

Breakpoint 1, BasicTest () at foo.cpp:147
147	        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
(gdb) c
Continuing.
Fraction [0] = 1/2


Breakpoint 1, BasicTest () at foo.cpp:147
147	        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
(gdb) c
Continuing.
Fraction [1] = -5/7


Breakpoint 1, BasicTest () at foo.cpp:147
147	        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
(gdb) c
Continuing.
Fraction [2] = 10


Breakpoint 1, BasicTest () at foo.cpp:147
147	        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
(gdb) p fr[i]
$1 = {num = 4, denom = -1}
(gdb) s
cs10b_fraction::operator<< (out=..., printMe=...) at foo.cpp:59
59	    if (printMe.denom == 1)
(gdb) 
64	    else if (printMe.num == 0)
(gdb) 
69	    else if(printMe.num < printMe.denom && printMe.num != 0)
(gdb) 
72	    else if(abs(printMe.num) > abs(printMe.denom))
(gdb) 
73	        out << printMe.num / printMe.denom << "+" << (printMe.num % printMe.denom) << "/" << printMe.denom << endl;
(gdb) 

Setting breakpoints, printing actual live runtime values, single stepping the code all tell you what's really going on.

Because there's nothing like seeing each line executed and you going yes, yes, yes, what!?
Each time your expectation differs from reality, then there is your bug.
You now have new knowledge about the problem, and clues to fix it.

I think .demon == -1 is a special case you also need to take care of.

Apr 23, 2020 at 12:53am
I cannot believe I did not think of denom == -1, now I just need to see how I am going to go about reading the data from the file using istream, thanks for the help.
Last edited on Apr 23, 2020 at 1:06am
Apr 23, 2020 at 2:15am
How could I go about reading the fraction from the istream? Would I need different if statements for the different situations of whether it is a normal or mixed number?
Last edited on Apr 23, 2020 at 2:15am
Apr 23, 2020 at 2:56am
bump
Apr 23, 2020 at 3:01am
I just came back to answer and noticed the bump and almost didn't answer. Best not to bump. Nobody likes a bumper. :-)

The prof demonstrates the use of peek() in main. It'll be useful for reading the fraction. Assuming you don't need to detect erroneous input, you could do something like this, using peek() to peek at the next char:

read an int
if the next char is a '+' then
    read an int, ignore the '/', and read an int
else if the next char is a '/' then
    ignore the '/', and read an int

You should be able to set num and denom from that.
Last edited on Apr 23, 2020 at 3:02am
Apr 23, 2020 at 3:07am
I was thinking to do an if statement in a function with the istream like this

1
2
3
4
5
6
7
8
9
10
11
istream& operator >> (std::istream &in, Fraction readMe)
{
        char c;

        if(c == '/' || c == '+')
        {
            in >> readMe.num >> "/" >> readMe.denom;
        }
         return in;

}

but I still keep receiving an error
Apr 23, 2020 at 3:11am
What is the value of c is that function?

in >> token is writing to the token.
You can't write to a value like "/".
You'd either need to call ignore() or write to a dummy value
1
2
char dummy_slash;
in >> readMe.num >> dummy_slash >> readMe.denom;

Last, your operator>> should take in the Fraction as a reference.
Last edited on Apr 23, 2020 at 3:14am
Apr 23, 2020 at 3:11am
That's no good since c contains garbage.
And you aren't going to have any luck trying to read something into "/"!
Also, readMe needs to be a reference.

Did you read my post?

Last edited on Apr 23, 2020 at 3:12am
Apr 23, 2020 at 3:15am
Yeah, I read it so scratch the way I used readMe and declare separate integer variables such as "num" and "denom".

Also I was trying to use a char because I saw that in my main file it had a char like variable such as '/'

I keep receiving an error such as
"client .cpp|85|undefined reference to `eof(std::basic_ifstream<char, std::char_traits<char> >&)'|"
Last edited on Apr 23, 2020 at 3:28am
Apr 23, 2020 at 4:01am
Just re read instructions given to us and we did have this as a guide:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
istream& operator >> (std::istream &in, Fraction readMe)
{
    int temp;
    in >> temp;
    
    if (in.peek() == '+')
    {
        
    
    }
     
    else if (in.peek() == '/')
    {
       
    } 
    
    else 
    {
       
    }

    return in;

}


I just do not know what is giving me the undefined reference error. I am very stuck and do not even have a clue on how to move forward.. I have tried looking at previous examples from other projects but nothing seems to be coming together to even get this working.
Last edited on Apr 23, 2020 at 5:13am
Apr 23, 2020 at 5:13am
https://www.cplusplus.com/reference/ios/basic_ios/eof/
> while (!eof(in))

It would be
while ( ! in.eof() )

It's a class method, not a function taking a stream as a parameter.
> "client .cpp|85|undefined reference to `eof(std::basic_ifstream<char, std::char_traits<char> >&)'|"
Apr 23, 2020 at 5:17am
Unfortunately I cannot change the client.cpp due to my instructors rules on this assignment so any small adjustments would result in a zero
Apr 23, 2020 at 5:19am
Well then go and beef at your tutor then for giving you crap code that won't even compile.

Apr 23, 2020 at 5:22am
salem c wrote:
It's a class method, not a function taking a stream as a parameter.

But even if it's changed to !in.eof() it's still not quite correct.
I suspect that the missing eof(istream&) function does something tricky to mitigate the design flaw (maybe peek forward, possibly past whitespace, for eof?).
BTW, eof(istream&) is prototyped at the top of the file.

A corrected version, using the usual !in.eof() :

1
2
3
4
5
6
7
8
9
    while (!in.eof()) {   /// usual eof()
        Fraction f;
        if(in.peek() == '/' || in.peek() == '*' || isalpha(in.peek()) ){
            in.ignore(200, '\n');   //skip this line, it's a comment
        } else {
            if (in >> f)  /// also need this
                cout << "Read Fraction = " << f << endl;
        }
    }

Last edited on Apr 23, 2020 at 5:25am
Apr 23, 2020 at 5:30am
OHHH OK OK OK, my error was that I was not paying attention to my multi-line comment on this error and had the bool commented out,

1
2
3
4
5
6
7
bool eof(ifstream& in)
{
	char ch;
	in >> ch;
	in.putback(ch);
	return !in;
}



I also have this segment as well

1
2
3
4
5
6
7
string boolString(bool convertMe) {
	if (convertMe) {
		return "true";
	} else {
		return "false";
	}
}
Last edited on Apr 23, 2020 at 5:36am
Apr 23, 2020 at 5:36am
Here is the updated client.cpp, I would like help for some guidance on having the fraction being read in fraction.cpp with the istream function *Will be provided below*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//client code - note namespace std and namespace cs10b_fraction (should be declared as a block in fraction.h and fraction.cpp)
// download and use frac_data.txt data file content for Basic Test section of client code
#include <iostream>
#include "fraction.h"
#include <fstream>
#include <cassert>
#include <string>
using namespace std;
using namespace cs10b_fraction;

void BasicTest();
void RelationTest();
void BinaryMathTest();
void MathAssignTest();
bool eof(/*inout*/ifstream& in);
string boolString(/*in*/bool convertMe);


int main()
{
    cout << "Project#2: Fraction class (ADT) client program to test CLASS INVARIANT\n";
    cout << "There are two data members used to represent the denominator and numerator\n";
    cout << "for each instance of a Fraction class object class.\n";
    cout << "The client code provides an interface to test correct operations on fraction  \n";
    cout << "objects that are negative, improper (larger numerator than denominator), \n";
    cout << "or whole numbers (denominator of 1).\n";
    cout << "Here is a list test type and order in which the tests will be conducted\n";
    cout << "1. BasicTest\n";
    cout << "2. RelationTest\n";
    cout << "3. BinaryMathTest\n";
    cout << "4. MathAssignTest\n\n";

    BasicTest();
    /*RelationTest();
    BinaryMathTest();
    MathAssignTest();*/

    cout << "\nProject#2 -Fraction class (ADT) testing now concluded.\n";
    cout << "Check output for correct results from the Fraction class (ADT) implementation.\n";

     return 0;
}

// Function provides the interface to test the following Fraction class member implementation algorithms
// Class constructor, a fraction reduction algorithm in simplify, and two nonmember friend ostream << and istream >> operator functions
void BasicTest()
{
    cout << "***********************************************************************\n";
    cout << "* Basic Test: Testing member constructor, simplify() and nonmember    *\n";
    cout << "* friend ostream << operator for basic Fraction object creation &     *\n";
    cout << "* printing(Fractions should be in reduced form, and as mixed numbers.)*\n";
    cout << "***********************************************************************\n";

    const Fraction fr[] = {Fraction(4, 8), Fraction(-15,21),
                           Fraction(10), Fraction(12, -3),
                           Fraction(), Fraction(28, 6), Fraction(0, 12)};

    for (int i = 0; i < 7; i++){
        cout << "Fraction [" << i <<"] = " << fr[i] << endl;
    }

    cout << "\n***********************************************************************\n";
    cout << "* Basic Test: Testing simplify() and nonmember friend istream >> and  *\n";
    cout << "* ostream << operators for reading and display of Fraction objects    *\n";
    cout << "* from data file                                                      *\n";
    cout << "***********************************************************************\n";

    string fileName;

    cout << "Enter file name with fraction data to read: ";
    cin >> fileName;

    ifstream in(fileName);

    while(!in)
    {
        cin.ignore(200, '\n');
        cout << fileName << " not found!" <<endl;
        cout << "Make sure the fraction data file to read is in the project folder." << endl;
        cout << "Enter file name with fraction data to read: ";
        cin >> fileName;
        in.open(fileName);
    }

        while (!eof(in)) {
        Fraction f;
        if(in.peek() == '/' || in.peek() == '*' || isalpha(in.peek()) ){
            in.ignore(200, '\n');   //skip this line, it's a comment
        } else {
            in >> f;
            cout << "Read Fraction = " << f << endl;
        }
    }
}


bool eof(ifstream& in)
{
	char ch;
	in >> ch;
	in.putback(ch);
	return !in;
}


string boolString(bool convertMe) {
	if (convertMe) {
		return "true";
	} else {
		return "false";
	}
}


Fraction.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/* USED FOR FUNCTIONS */
#include <iostream>
#include <cmath>
#include <cctype>
#include <cassert>
#include "fraction.h"
using namespace std;

namespace cs10b_fraction
{

void Fraction::Simplify()
//Pre:
//This function will reduce the two fractions
//after it has been transformed and output them
//correctly

//Post:
//The result of the two fractions after they are transformed
//are reduced
{
    //For loop that goes through and simplifies fraction
    for(int i = abs(num * denom); i > 1; i--)
    {
        if((num % i) == 0 && (denom % i) == 0)
        {
            num = num / i;
            denom = denom / i;
        }
    }
}

ostream& operator << (std::ostream &out, const Fraction printMe)
{

    if (printMe.denom == 1)
    {
        out << printMe.num << endl;
    }

    else if (printMe.num == 0)
    {
        out << printMe.num << endl;
    }

    else if(printMe.denom == -1)
        out << printMe.num / printMe.denom << endl;

    else if(printMe.num < printMe.denom && printMe.num != 0)
        out << printMe.num << "/" << printMe.denom << endl;

    else if(abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << "+" << (printMe.num % printMe.denom) << "/" << printMe.denom << endl;



   /* else if (abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << endl;

    else if (abs(printMe.num) > abs(printMe.denom))
        out << printMe.num / printMe.denom << "+" << (printMe.num % printMe.denom) << "/" << printMe.denom << endl; */

    return out;
}

istream& operator >> (std::istream &in, Fraction readMe)
{
    int temp;
    in >> temp;

    if (in.peek() == '+')
    {
        in >> readMe.num;
    }

    else if (in.peek() == '/')
    {
        in >> readMe.num;
        in.ignore();
        in >> readMe.denom;

    }

    else
    {
        in.ignore();

    }

    return in;

}

}
Last edited on Apr 23, 2020 at 5:37am
Pages: 12