I am attempting to exit a method which returns void after checking a condition (I realize this would be easier if I threw an exception, but I'm trying to avoid that for this project). I have the code below, which should return out of the if statement, if I am interpreting it correctly, but the entire method is still executing. Is there a problem in the code somewhere (I can post more if needed), or is there a better way to write this without exception handling?
void Rational::divide(Rational b) {
if (b.numerator == 0) {
cout << "Cannot divide by zero." << endl;
return;
} else if (b.numerator != 0) {
numerator = numerator * b.denominator;
denominator = denominator * b.numerator;
reduce();
}
}
EDIT: I've updated the code to reflect some suggestions; just to clarify, the if statement itself is executing correctly (if b is zero, I get the error message) - once the error message is printed, the remainder of the method continues to run.
EDIT 2: Updated with else if revision.
And that is what you are doing. You probably want to do something like this in your ifstatement: if((double)b.denominator == 0.f).
You should also be careful when comparing with floats or double due to the way they are represented in memory. It will almost never be exactly zero, so you should compare with an epsilon.
Related
Had a new problem with the while function. As easy as it sounds, I still can't wrap my head around it.
Like my last program, this one closes unexpectedly after the correct and wrong messages.
I want this to loop after entering a number, so that the program won't stop.
Thanks for the help, if any.
#include <iostream>
using namespace std;
int main()
{
int X = 0; //setting the first variable
int num; //setting the second
while (X == 0) //this should happen whenever X is equal to 0
{
cout << "Type a number bigger than 3. "; //output
X++; //This should increase X, so that the next while function can happen
}
while (X == 1) //again, since I increased x by one, (0+1=1 obviously) this should happen
{
cin >> num; //standard input
if (num > 3) //if function: if num is bigger than three, then this should happen
{
cout << "Correct! Try again!" <<endl; //output
X--; //Here I'm decreasing x by one, since it was 1 before, now it becomes 0. This should make the "while (X == 0)" part happen again, so that another number bigger than three can be entered
}
if (num <= 3) //if function: if num is lesser than or equal to 3, this should happen
{
cout << "Wrong! Try again!" <<endl; //output
X--; //This is supposed to work like the "X--;" before, repeating the code from "while (X==0)"
}
}
}
now it becomes 0. This should make the "while (X == 0)" part happen again
Nope. While loops don't magically take effect at any point during execution of the program. You only enter a while loop when you've reached it from code above. Programs are executed top-to-bottom, generally.
You would need a loop around the entire program if you want to keep going round and round. Those whiles you have now should probably be ifs.
Merge the two while loops into one, while(true).
Put each previous while body into an if state with the clause from the old while in it.
while(true) {
if (X==0) {
// the X==0- case
} else if (X==1) {
// the X==1 case
}
}
in order to end your loop, do a break;.
You have to think of C++ programs as a sequence of instructions, like a recipe. while just means a loop: you check the condition. If true, you run the body. After running the body, you check only that condition again, and run the body if true. Whenever the condition is false at the start or end of the body of the while (the {} enclosed code after it), you end the loop and proceed to the next one.
The first loop runs, finishes, then the second loop runs in your code. Once the first loop exits, you do not go back into it just because the condition becomes true.
Understanding flow control is one of the "hard" steps of learning to program, so it is ok if you find this tricky.
There are many improvements you can do your code beyond getting it working -- there is, actually, little need for X at all. But baby steps! Once you get it working, you can ponder "how could I remove the variable X?".
Before making such fundamental changes to your program, you should get it working, and save a copy of it so you can "go back" to the last working version.
You want to wrap all that code in it's own while loop:
while (true /* or something */)
{
while (X == 0) //this should happen whenever X is equal to 0
{
// ...
}
At least put your second while loop inside the first one to get it working as intended. Otherwise your program has no reason to go back again.
Nevertheless it's not a good design.
I'm looking at error testing and reporting techniques from function calls, especially when multiple functions are called. As an example of what I mean, for simplicity each function returns a bool:
success = false;
if (fnOne ())
{
if (fnTwo ())
{
if (fnThree ( ))
{
success = true;
}
else
{
cout << "fnThree failed" <<endl;
}
}
else
{
cout << "fnTwo failed" <<endl;
}
}
else
{
cout << "fnOne failed" <<endl;
}
I find with the above example (which I see everywhere) the code quickly becomes unreadable, especially when it calling code becomes multi-screen in height.
Currently my way of dealing with this in C++ (Including 'c' tag in case someone has a C technique which is smooth) I store a bool and a string in my object. The bool represents success/fail and the string represents a reason for the fail state. I call a function and if the function fails, the function internally sets the object into fail state and provides a string based reason. I'm still not 100% happy with this method... but its the best I have so far. Example of what it looks like:
void myobj::fnOne (void)
{
if (m_fluxCapacitorProngCount > 3)
{
setState (false, "myobj::fnOne - Flux capacitor has been breeding again");
}
}
void myobj::fnTwo (void)
{
if (m_answerToLifeUniverseAndEverything != 42)
{
setState (false, "myobj::fnTwo - Probability drive enabled?");
}
}
void myobj::setup (void)
{
// Ensure time travel is possible
if (valid())
{
fnOne ();
}
// Ensure the universe has not changed
if (valid())
{
fnTwo ();
}
// Error? show the reason
if (valid() == false)
{
cout << getStateReason () << end;
}
}
Where valid () returns true/false and getStateReason () returns the string provided in the function when the error occured.
I like that this grows without the need to nest the conditions, to me I find this more readable but I'm sure there are problems...
What is the best [cleanest] way to handle detecting and reporting multiple function call return conditions?
This code should be clearer than your first variant:
if (!fnOne ())
{
cout << "fnOne failed" <<endl;
return;
}
if (!fnTwo ())
{
cout << "fnTwo failed" <<endl;
return;
}
if (!fnThree ())
{
cout << "fnThree failed" <<endl;
return;
}
success = true;
In general, for C++ you can use exceptions for error handling.
If you really want one function to return a value that represents the success/failure of several other functions (and just that - not a generalized return value from each function, which would require some way of returning an array/tuple/vector of values), here's one approach:
int bigFunction()
{ int return_value = 0;
if (function1() != 0)
return_value |= (1 << 0);
if (function2() != 0)
return_value |= (1 << 1);
if (function3() != 0)
return_value |= (1 << 2);
// ....
return return_value;
}
The idea is to allocate one bit each in the return value to indicate success/failure of each sub-function. If your sub-functions have a small set of possible return values that you actually want to capture, you could use more than one bit per function - i.e. two bits would allow you four different values for that field.
On the other hand, something like this means you're probably either a) writing some pretty low-level code like a device driver or kernel or something or b) there is probably a better approach to solving the problem at hand.
Dealing with errors in your code (bugs) and errors arising out of user input is a huge topic on its own. The technique you employ depends on the complexity of your code and the expected life of the code. The error handling strategy you would employ for a homework project is less complex than the error handling strategy you would employ for a semester project, which will be less complex than the error handling strategy you would employ for an in-house project, which will be less complex than a project which will be widely distributed to clients.
Strategy 1: Write an error message and abort
The simplest error handling strategy, that you can employ in homework project, is write a message out to stdout and and then call abort().
void fun1(int in)
{
if (in < 0 )
{
printf("Can't work with a negative number.\n");
abort();
}
// Rest of the function.
}
Strategy 2: Set a global error code and return
The next level of error handling involves detecting a bad input and dealing with it without calling abort(). You could set a globally accessible error code to indicate the type of error. I would recommend using this approach for homework projects, semester projects, and projects that are exploratory in nature.
void fun2(int in)
{
if (in < 0 )
{
// Indicate that "fun2" came accross a NEGATIVE_INTEGER_ERROR.
setErrorCode(NEGATIVE_INTEGER_ERROR, "fun2");
return;
}
// Rest of the function.
}
void funUser(int in)
{
// Call fun2
fun2(in);
// If fun2 had any errors, deal with it.
if (checkErrorCode())
{
return;
}
// Rest of the function.
}
The next level of error handling involves detecting a bad input and dealing with it using other options. You could return an error code from the function. If you are using C++, you could throw an exception. Both these options are valid ways of dealing with large projects --- be they in-house or distributed for wider consumption. They are applicable to any project in which the user base is beyond the team of developers.
Strategy 3: Return an error code from the function
int fun3(int in)
{
if (in < 0 )
{
// Indicate that "fun3" came accross a NEGATIVE_INTEGER_ERROR.
return NEGATIVE_INTEGER_ERROR;
}
// Rest of the function.
}
void funUser(int in)
{
// Call fun3
int ecode = fun3(in);
// If fun3 had any errors, deal with it.
if (ecode)
{
return;
}
// Rest of the function.
}
Strategy 4: Throw an error code from the function (C++)
void fun4(int in)
{
if (in < 0 )
{
// Indicate that "fun4" came accross a NEGATIVE_INTEGER_ERROR.
throw NEGATIVE_INTEGER_ERROR;
}
// Rest of the function.
}
void funUser(int in)
{
// Call fun4. Be prepared to deal with the exception or let it be
// dealt with another function higher up in the call stack.
// It makes sense to catch the exception only if this function do
// something useful with it.
fun4(in);
// Rest of the function.
}
Hope this gives you enough background to adopt an appropriate error handling strategy for your project.
if ((!m_pMediaPage->PageLayer() || !m_pMediaPage->LoadState()) &&
!m_pMediaPage->m_bRequestList)
{
GetListInfo();
m_pMediaPage->m_bRequestList = TRUE;
}
GetListInfo() does not get executed when all values are 0.
PageLayer() and LoadState() return ints and m_bRequestList is an int.
Basically rewritten as this:
if ((!0 || !0) && !0) -or- if ((1 || 1) && 1)
I can only assume that the values being evaluated by the if statement aren't really as seen by the debugger.
I am using visual studio 2005 and put breakpoints on line 1 & 4 to examine the values and see if it executes into the if statement. I am not sure how else to debug this.
Like I said, each of the 3 values are 0 as viewed by the debugger when at breakpoint 1.
Functions in .h:
int PageLayer() {return m_iCurrentLayer;} - protected
BOOL LoadState() {return m_bLoadDone;} - protected
BOOL:
typedef int BOOL;
This conditional statement looks as if it would be executed if all values return from the different functions return zero. If the body of the function isn't executed, I would debug the problem as follows:
Log the values of all functions prior to the if-statement:
std::cout << "page-layer=" << !m_pMediaPage->PageLayer() << ' '
<< "load-state=" << !m_pMediaPage->LoadState() << ' '
<< "request-list=" << !m_pMediaPage->m_bRequestList << '\n';
Yes, the debugger should show these values as well but I have great faith in the values being printed to be the values actually evaluated.
If that doesn't give the necessary insight into what goes wrong, I would start breaking down the condition into separate parts and verify success at each level, e.g.:
if (!m_pMediaPage->PageLAyer()) {
std::cout << "page-layer is not set\n";\
}
if (!m_pMediaPAge->LoadState()) {
std::cout << "load-state is not set\n";
...
If this still doesn't give any insight, I'd start suspecting that the functions return funny values and I would verify that the different results are funny values and I would start looking at the output after preprocesing using the -E option.
You tagged the question as VS2005; do you have all relevant service packs installed to ensure you aren't running into some long-fixed compiler issue?
Secondly, the functions you've listed appear to be very simple setters (you might want to make them const, although that is unrelated to your problem).
You're stepping thru with the debugger, it might therefore be valuable to check your assertion that they are all zero:
bool plCond = (m_pMediaPage->PageLayer());
bool lsCond = (m_pMediaPage->LoadState());
bool rlCond = (m_pMediaPage->m_bRequestList);
bool getListInfoCond = ((!cond1 || !cond2) && !cond3);
if (getListInfoCond)
{
GetListInfo();
m_pMediaPage->m_bRequestList = TRUE;
}
If this fixes the problem, you either have a heisenbug or a stack/memory stomp.
If this doesn't fix the problem, it may home in on the cause.
If this DOES fix the problem, you may want to consult the assembly for the code and see if you have somehow tripped a compiler bug.
I have an assignment where I must read from a file and perform various calculations on it and write the answer to an output file. Everything was going great until I came to this step:
"Reread the file and compute the sum of the integers in the file as long as the sum does not exceed 1000. Use a flag controlled loop structure."
My code snippet is as follows:
dataFile2.close();
dataFile2.clear();
dataFile2.open("J:\\datafile2.txt");
sum = 0;
while(sum < 1000)
{
dataFile2 >> num;
sum = sum + num;
if(sum > 1000)
sum = sum - num;
}
answers << "The sum of the integers not exceeding 1000 is " << sum << endl;
cout << "The sum of the integers not exceeding 1000 is " << sum << endl;
return 0;
My variables have already been declared. when I take out the if statement the sum adds the last number and the sum then exceeds 1000. When the If statement is left in, the answers and cout statements are not executed and there are no compiler warnings or errors.
Any help on this would be greatly appreciated.
-ThePoloHobo
Since no one seems to want to give you a correct answer... (and
to be fair, it's hard to give a correct answer without actually
doing your work for you).
There are two issues in you code. The first is the requirement
that you use a flag. As I said in my comment, the idiomatic
solution would not use a flag, but there's no problem using one.
A flag is a boolean variable which will be tested in the
while, and will be set in a conditional in the loop, when you
find something that makes you want to leave the loop.
The second issue is that you are using num without checking
that the input has succeeded. You must check after the >>
operator. The idiomatic way of checking (and the only thing
that should ever be used by someone not experienced in the
language) is to treat the stream as if it were a boolean:
dataFile2 >> num;
if ( dataFile2 ) {
// Input succeeded...
} else {
// Input failed for some reason, maybe end of file
}
Since all operations on a stream return a reference to the
stream, it is usual to merge the test and the input:
if ( dataFile2 >> num ) {
// succeeded
} else {
// failed
}
(Personally, I find the idea of modifying state in the condition
of an if or a while horrible. But this idiom is so
ubiquitous that you should probably use it, for the simple
reason that that's what everyone expects.)
In pedagogical environments, it's probably acceptable to
consider any failure to be end of file, and just move the test
up into the while (except, of course, that you've been asked
to use a flag). In other contexts, you'll want to take into
account the fact that the failure could be due to a syntax error
in the input—someone inserted "abc" into the file where
you were expecting a number. There are a number of ways of
handling this, all of which are beyond the scope of what you are
trying to do, but be aware that after you've detected failure,
you can interogate the stream to know why. In particular, if
dataFile2.eof() is true, then the failure was (probably) due
to you having read all of the data, and everything is fine. (In
other words, failure to read a data is not necessarily an error.
It can be simply end of file.)
You don't seem to be using a flag variable, which could help in this case. Something like this should fix it:
sum = 0;
bool sumUnder1000 = true; //Or the C++ equivalent, I'm a bit rusty
while(sumUnder1000)
{
if(!dataFile2.good()){
sumUnder1000 = false; //We've reached end of file or an error has occurred
return;
}
dataFile2 >> num;
sum = sum + num;
else if(sum > 1000){
sum = sum - num;
sumUnder1000 = false;
}
}
Okay so I"m writing a program (in C++) that is supposed to take a number, go through it, find out if it's factors are prime, if so add that to a sum, and then output the sum of all of the imputed number's prime factors.
My program successfully seems to do this however it has 2 problems,
1) The number I am supposed to test to see the sum of the prime factors of this number (600851475143) but it's too big for an int. I'm not sure what other variable type to use, or which variable's types to change. I would really like a clear explanation on this if at all possible.
2) For some reason, when the program checks to see if 1 is a factor of the number, and then checks to see if 1 is prime, it says 1 is prime, even though the first step of the function for checking to see if it's prime is that if it's 1 then it isn't prime. I found a fix for this, by telling it to subtract 1 from the very last value for the sum of all prime factors. However, this is a fix, not really finding the problem. If someone could point out at least where the problem is I would appreciate it!
Here's the code, if you have questions, please ask!
#include <iostream>
using namespace std;
bool prime (int recievedvalue) { //starts a function that returns a boolean with parameters being a factor from a number
int j =1;
int remainderprime = 0;
bool ended = false;
while (ended == false){ //runs loop while primality is undetermined
if (recievedvalue == 1){ //if the recieved value is a 1 it isn't prime
//not prime
break; // breaks loop
return false;
}
remainderprime=recievedvalue%j; //gives a remainder for testing
if ((remainderprime==0 && j>2) && (j!=recievedvalue || j == 4)){ //shows under which conditions it isn't prime
ended=true;
//not prime
return false;
}
else if (j==1){
j++;
}
else if ( recievedvalue==2 || j==recievedvalue ){ // shows what conditions it is prime
ended = true;
//prime
return true;
}
else {
j++;
}
}
}
int multiple(int tbfactor){ //factors and then checks to see if factors are prime, then adds all prime factors together
//parameter is number to be factored
int sum = 0;
bool primetest = false;
int remainderfact;
int i=1;
while (i<=tbfactor){ //checks if a i is a factor of tbfactor
remainderfact=tbfactor%i;
if (remainderfact==0){ //if it is a factor it checks if it is a prime
primetest = prime(i);
}
if (primetest ==true){ //if it is prime it add that to the sum
sum += i;
primetest=false;
}
i++;
}
sum --; // for some reason it always ads 1 as a prime number so this is my fix for it
return sum;
}
int main()
{
int input;
int output;
cout << "Enter number to find the sum of all it's prime factors: ";
cin >> input;
output = multiple(input);
cout << output;
return 0;
}
I'm really new to this, like a few days or so, so I'm very unfamiliar with stuff right now so please explain easily for me! I look forward to your help! Thanks!
For 1), you need to use a larger datatype. A 64-bit integer should be enough here, so change your ints to whatever the 64-bit integer type is called on your platform (probably long, or maybe long long).
For 2), the problem appears to be that you have a break before your return false. The break causes the code to stop the while loop immediately and continues execution immediately after the loop. It doesn't appear that the return value is ever assigned in that case (which your compiler should be warning you about), so the actual value returned is effectively arbitrary.
While others have pointed out a problem with your data types, there's a few problems with the structure of the first function that immediately caught my eye. (BTW, your indentation is enraging.) Look at this stripped-down version:
bool prime (int recievedvalue) {
// ...
bool ended = false;
while (ended == false){
if (...){
break; // jumps _behind_ the loop
return false;
}
// ...
if (...) {
ended=true;
return false; // leaves function returning true
}
else if (...) {
// ...
}
else if (...) {
ended = true;
return true; // leaves function returning false
}
else {
// ...
}
}
// behind the loop
// leaves function returning random value
}
For one, every time you set the loop control variable ended, you leave the loop anyway using some other means, so this variable isn't needed. A while(true) or for(;;) would suffice.
Also, that break jumps behind the loop's body, but there isn't a statement there, so the code leaves the function without explicitly returning anything! That's invoking so-called Undefined Behavior. (According to the C++ standard, your program is, from this point on, free to do whatever it pleases, including returning random values (most implementations will do that), formatting your HD, invoking nasty Nasal Demons on you, or returning exactly what you expected, but only on Sundays.)
Finally, that break occurs right before a return false; which is therefor never reached. Actually your compiler should warn about that. If it doesn't, you're likely not compiling at the highest warning level. (You should turn this on. Always try to cleanly compile your code at the highest warning level.) If it does, learn to pay attention to compiler warnings. They are a very important tool for diagnosing problems during compilation. (Remember: Errors diagnosed during compilation need no testing and never make it to the customer.)
Use either a 64 bits number on a 64 bits system, or use a library that does arbitrary precision arithmetic
Remove the break before the return false. Because of the break, execution is resumed outside the loop and return false is never executed.
To store values larger than 4 bytes (the capacity of an int) you have a variety of options. Refer to this page for those options. As to why you're program is returning true for the check on whether or not 1 is prime, check out this section of code:
if (recievedvalue == 1){ //if the recieved value is a 1 it isn't prime
//not prime
break; // breaks loop
return false;
}
The break statement will exit and return false will never be reached. To solve the problem, remove the break statement.