Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

cybrscot

macrumors 6502
Original poster
Dec 7, 2010
282
0
Somewhere in Southeast Asia
This is my new problem, #3 from my book. My pseudo ideas are below it.

Code:
//Write a program that asks a user to enter
//a fraction, then converts the fraction to lowest
//terms:
// Enter a fraction: 6/12
//In lowest terms: 1/2
//Hint: To convert a fraction in lowest terms, first compute 
//the GCD of the numerator and denominator.  Then divide both the
//numerator and denominator by the GCD.

#include <stdio.h>

main ()

{

This is similar to the last program. I figure I will

1) calculate the GCD like before, with the same method.
2) after I get the GCD, I will divide both the original numerator and denominator by the GCD, and store into an intermediate variable

then, print f(%d/%d, intermediateVariable1, intermediateVariable2)

That simple?
 
Wirelessly posted (Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5)

Seems fine. Be careful about the input as a fraction and validating it.

B
 
I would just be weary of edge cases. If a user enters 62/0, don't crash. If a user enters 20/10, decide if you want to express this as 2/1 or just 2. If a user enters 0/95, decide if you want to show 0, 0/1, etc. It's probably outside of the scope, but you could also decide to deal with improper fractions by expressing a whole part and fractional part after reduction to make it proper.

-Lee
 
then, print f(%d/%d, intermediateVariable1, intermediateVariable2)

Suggestion: give some thought to naming things.
It can make a big difference in clarity, not just to others who might read your code, but to yourself when thinking about the design and the code.

Example:
intermediateVariable1 -> reducedNumerator
intermediateVariable2 -> reducedDenominator

I chose the prefix reduced because converting a fraction to lowest terms is called "reducing a fraction".

Similarly for the unshown input variables: inputNumerator, inputDenominator.
 
Why store in some kind of temp variable? Is there any particular reason you would need to have access to the original fraction and not the reduced fraction?

your printf statement would be just as good with printf("%d/%d", origNumerator/gcd, origDenomenator/gcd)
 
Why store in some kind of temp variable? Is there any particular reason you would need to have access to the original fraction and not the reduced fraction?

your printf statement would be just as good with printf("%d/%d", origNumerator/gcd, origDenomenator/gcd)

This is a personal pet peeve of mine.

It's easier and clearer to use holding variables that are named as chown33 suggests for three reasons.

  1. it makes the code easier to read and understand when you or someone else come back to it.
  2. it clearly separates out the computation and output steps (model, view) so that you can more easily change the way you model or view (e.g. printf -> GUI)
  3. it allows you to more easily build on and re-use code. For example as lee1210's suggestion to extend the code to output mixed fractions instead when the fraction is improper

B
 
This is a personal pet peeve of mine.

It's easier and clearer to use holding variables that are named as chown33 suggests for three reasons.

  1. it makes the code easier to read and understand when you or someone else come back to it.
  2. it clearly separates out the computation and output steps (model, view) so that you can more easily change the way you model or view (e.g. printf -> GUI)
  3. it allows you to more easily build on and re-use code. For example as lee1210's suggestion to extend the code to output mixed fractions instead when the fraction is improper

B

Well to be frank, I kind of expect this to be modeled as something like one of these. (not just a printf statement)
Code:
//immutable fraction
@interface Fraction : NSObject
{
	int numerator;
	int denominator;
}
@end
@implementation Fraction
- (id) initWithNumerator: (int) n andDenominator: (int) d {
	self = [super init];
	if (self) {
		numerator = n;
		denominator = d;
		if (denominator == 0) {
			return nil;
		}
	}
	return self;
}
- (Fraction *) reduce {
	int gcd = [self gcd]; // not defined
	if (gcd == 1) { return [[self retain] autorelease]; }
	return [[[Fraction alloc] initWithNumerator: numerator/gcd andDenominator: denominator/gcd] autorelease];
}
@end
Code:
// mutable fraction
@interface Fraction : NSObject
{
	int numerator;
	int denominator;
}
@end
@implementation Fraction
- (id) initWithNumerator: (int) n andDenominator: (int) d {
	self = [super init];
	if (self) {
		numerator = n;
		denominator = d;
		if (denominator == 0) {
			return nil;
		}
	}
	return self;
}
- (void) reduce {
	int gcd = [self gcd]; // not defined
	numerator /= gcd;
	denominator /= gcd;
}
@end
 
Code:
	return [[[Fraction alloc] initWithNumerator: numerator/gcd andDenominator: denominator/gcd] autorelease];

Personally, I still wouldn't do it that way.

Code:
        int reducedNumerator   =  numerator/gcd;
        int reducedDenominator = denominator/gcd;
	return [[[Fraction alloc] initWithNumerator: reducedNumerator andDenominator: reducedDenominator] autorelease];

It's just MHO. (EDIT: I'd actually probably allocate the reduced fraction separately first and use "return reducedFraction").

B
 
Last edited:
Wirelessly posted (Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5)

Seems fine. Be careful about the input as a fraction and validating it.

B



On the last problem we did, originally when asking the user to enter two numbers I did scanf (%d,%d, m, n) and asked the user to separate with a comma, But then I figured out I was having a problem with that comma in scanf, so I opted for scanf (%d%d, m, n)

That being the case, how do I get the user to enter a fraction? Specifically the / character? I can't do ("%d/%d", m, n) can I? I think it's natural that if I ask for a fraction, the user will automatically wish to input the / symbol. If I learned how to do this before, I've forgotten.

Thanks
Scott
 
On the last problem we did, originally when asking the user to enter two numbers I did scanf (%d,%d, m, n) and asked the user to separate with a comma, But then I figured out I was having a problem with that comma in scanf, so I opted for scanf (%d%d, m, n)

That being the case, how do I get the user to enter a fraction? Specifically the / character? I can't do ("%d/%d", m, n) can I? I think it's natural that if I ask for a fraction, the user will automatically wish to input the / symbol. If I learned how to do this before, I've forgotten.
Try it. See what happens.

Also read the reference doc for scanf, see if it says anything special about slashes or commas or nothingatall between input specifics.
http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man3/scanf.3.html

This is called "testing your approach", and is an important part of developing a design.

I'm curious how you'd use "%d%d" to distinguish between, say "1/234" and "12/34" and "123/4" since all would have the identical input "1234". So you might also want to go back and review the notes from your past project on what worked and what didn't. If you didn't take notes, then review the message thread, and consider whether you might benefit by keeping notes of what doesn't work and why, or what does work and why.
 
Try it. See what happens.

Also read the reference doc for scanf, see if it says anything special about slashes or commas or nothingatall between input specifics.
http://developer.apple.com/library/mac/#documentation/darwin/reference/manpages/man3/scanf.3.html

This is called "testing your approach", and is an important part of developing a design.

I'm curious how you'd use "%d%d" to distinguish between, say "1/234" and "12/34" and "123/4" since all would have the identical input "1234". So you might also want to go back and review the notes from your past project on what worked and what didn't. If you didn't take notes, then review the message thread, and consider whether you might benefit by keeping notes of what doesn't work and why, or what does work and why.


Yeah it says

"Everything else matches only itself. Scanning stops when an input character does not match such a format character. Scanning also stops when an input conversion cannot be made"

Which is what I thought, but I swear the comma thing wasn't working for me, it wouldn't compile until I changed %d,%d to %d%d, hmm, maybe I did something else wrong. I will try to allow the / in the scanf again, and use the printf to instruct the user to include it. Good link by the way.

Thanks
Scott

Got it, thanks!
scanf ("%d/%d", &m,&n) ;


I think before I did ("%d"/"%d", &m, &n) ;
 
Last edited by a moderator:
Which is what I thought, but I swear the comma thing wasn't working for me, it wouldn't compile until I changed %d,%d to %d%d, hmm, maybe I did something else wrong.

Unless you happened to save the non-working version, there's no way to know what it was.

Also, "not compile" is different from "not run". I find it hard to believe that "%d,%d" in a literal string won't compile. It's a simple enough test to try:
Code:
#include <stdio.h>
int main()
{
  int a,b;
  scanf( "%d,%d", &a, &b );
  printf( "a: %d, b: %d\n", a, b );
}
In fact, you should get in the habit of writing little exploratory programs that exercise only one part of whatever larger question you're working on. Writing simpler programs to help you write more complex programs is an important step. Writing is a tool. Programs are tools. You'll write better programs by writing more programs better.


Got it, thanks!
scanf ("%d/%d", &m,&n) ;


I think before I did ("%d"/"%d", &m, &n) ;

You should break down exactly what the second one is saying, and analyze why it doesn't work.
 
Here is my current code, i've commented it a lot. I'm to the point that it gives me the GCD (greatest common denominator) after the loop. Which I need to use to divide the users original numerator and original denominator to get the "reduced" fraction in "simplest terms. But I keep getting output of 0/0.
What is wrong?

Code:
//Write a program that asks a user to enter
//a fraction, then converts the fraction to lowest
//terms:
// Enter a fraction: 6/12
//In lowest terms: 1/2
//Hint: To convert a fraction in lowest terms, first compute 
//the GCD of the numerator and denominator.  Then divide both the
//numerator and denominator by the GCD.

#include <stdio.h>

main ()

{
	int m, n, modResult, userNum, userDenom;
	
	printf ("Enter a fraction (include the / character): ") ;
	scanf ("%d/%d", &m,&n) ;
	
	userNum = m;     //stored orig user input value into intermediate varaibles
	userDenom = n;
	
	switch (n) {   //prints however still gives floating point error after print
		case 0 : printf ("Invalid input, no zero's in denominator!\n") ;
				 break;
	}
	
	
	//if (n =< 0)   ***this didn't work, so I used the switch above instead***
	//	printf ("Invalid input, no zero's or negatives in denominator!\n") ;
	
	modResult = m % n;
	while (modResult != 0) {
	m = n;
	n = modResult;
	modResult = m % n;
	}
	
	//at this point, after loop we know that n is the greatest common denominator
	//(the GCD) so below I declared two intermediate variables, then divided the userNum/n
	//to get the lowestNum, then divided the userDenom/n to get the lowestDenom, then
	//the printf explains the rest.




        //the below computations I also tried within the loop, and got the same 
        //result as 0/0.  How do I capture that loop output and  use it to do
        //calculations, other than just a printf??  The usernum and userdenom
        //are the original m,n values, and n is the GCD, but I assume their 
       //putting their results into lowestNum and lowestDenom, which are 
       //printing as 0/0.
	
	int lowestNum, lowestDenom;  //intermediate variables
	(userNum / n) == lowestNum;     
	(userDenom / n) == lowestDenom;
	
	printf ("The fraction in it's lowest terms are: %d/%d\n", lowestNum, lowestDenom) ;
	
	
	return 0 ;
	}
 
What is wrong?

Code:
(userNum / n) == lowestNum;     
(userDenom / n) == lowestDenom;

Its the old == and = confusion again.

That code compares (userNum / n) to lowestNum, then ignores the result. You've also got them the wrong way round. The variable you want the value assigned to should be on the left of the = sign.
 
Its the old == and = confusion again.

That code compares (userNum / n) to lowestNum, then ignores the result. You've also got them the wrong way round. The variable you want the value assigned to should be on the left of the = sign.

You're right that worked! Thanks, Actually I wasn't even thinking of "storing" the value of the division into those operands, (I know that the = requires the value of the right operand to be stored into the left operand) I guess I kept telling myself that those operations "equal" the variable I chose, then I printf'd the two variables.

Okay, okay. got it (for now) This really is a language. Got to keep speaking it and surrounding myself in it everyday, as much as possible, to retain it. Like a foreign language, the goal is to not have to translate your native language into the "foreign" language in your mind. The goal here is the same, learn to think in the language, then speak in the language. The only way to do that is keep going and going, and going, everyday! Eventually it sinks in.

That's why I make sure I do this EVERY day. I don't want to skip a day for any reason. I speak English everyday and that comes easy, C will come easy only if I treat it the same way.
 
Firstly I apologize for assuming you were working in Objective-C, I remember there being a very similar example in one of the Obj-C books I've read using Fraction objects as the building blocks for Obj-C.

The variable name 'n' to represent denominator is one of the most confusing naming schemes I've ever come across.

Your euclidean algorithm
Code:
	modResult = m % n;
	while (modResult != 0) {
	m = n;
	n = modResult;
	modResult = m % n;
	}

Should probably be written into a separate function, and would remove the need to store the users original inputs more than once (because the function would get its own copy to work with and then return the GCD)

Your if (n =< 0) didn't work because there is no =< operator, only <= which would do what you intended. (though it doesn't halt the rest of the program, just prints an error)


Code:
int lowestNum, lowestDenom;  //intermediate variables
	(userNum / n) == lowestNum;     
	(userDenom / n) == lowestDenom;
These lines are wrong for to reasons, 1) == is a comparator like != and <=
2) assignment follows towards the left, so it should be
lowestNum = (userNum / n);
 
Code:
	//if (n =< 0)   ***this didn't work, so I used the switch above instead***
	//	printf ("Invalid input, no zero's or negatives in denominator!\n") ;

There isn't an operator named =<. The operator's name is <=. You can't arbitrarily switch things around and expect them to work.

When something doesn't work, I think you should spend a little more time on looking into why it doesn't work. You'll never understand what's wrong until you take the time to learn why it's wrong. Start by carefully reading the compiler error message. Then look at your book for examples that do work.
 
Firstly I apologize for assuming you were working in Objective-C, I remember there being a very similar example in one of the Obj-C books I've read using Fraction objects as the building blocks for Obj-C.

The variable name 'n' to represent denominator is one of the most confusing naming schemes I've ever come across.

Your euclidean algorithm
Code:
	modResult = m % n;
	while (modResult != 0) {
	m = n;
	n = modResult;
	modResult = m % n;
	}

Should probably be written into a separate function, and would remove the need to store the users original inputs more than once (because the function would get its own copy to work with and then return the GCD)

Your if (n =< 0) didn't work because there is no =< operator, only <= which would do what you intended. (though it doesn't halt the rest of the program, just prints an error)

Thanks, yeah I'm still very green, been at this for about a month and a half now, still making stupid mistakes. I don't understand when you say I could make a separate function, not quite there yet!

There isn't an operator named =<. The operator's name is <=. You can't arbitrarily switch things around and expect them to work.

When something doesn't work, I think you should spend a little more time on looking into why it doesn't work. You'll never understand what's wrong until you take the time to learn why it's wrong. Start by carefully reading the compiler error message. Then look at your book for examples that do work.

Yeah ,stupid mistakes. I guess my mind isn't functioning correctly now as it's after 4am! I use my book as much as possible, After working on the same code for 2-3 days, or a single sitting for 3 - 4 hours I guess maybe I become a little careless? I'm not sure. It's not the same code per se, but trying to solve a single problem within that code for such a long time that wears me out. On most things, I've often spent countless hours writing and re-writing trying to get it to work (as I'm new at this) Honestly I think I'm doing pretty good for 6 weeks of studying C. I like what I know so far.
 
Last edited by a moderator:
Yeah ,stupid mistakes. I guess my mind isn't functioning correctly now as it's after 4am!

Know when to stop. Know when to start again.

I used to stay up until 4 am programming, too. And not just in school, for my real job. Then I noticed a pattern: I was spending half the next day, and sometimes even longer, simply fixing the bonehead bugs I'd introduced while programming late at night. It wasn't that the code was completely wrong, but it was wrong enough that it didn't really work correctly. That's when I learned about stopping before doing damage that I'd have to fix later. I wrote less code, and spent less time at it, yet was making better progress on meeting deadlines. Shocking but true.
 
Know when to stop. Know when to start again.

I used to stay up until 4 am programming, too. And not just in school, for my real job. Then I noticed a pattern: I was spending half the next day, and sometimes even longer, simply fixing the bonehead bugs I'd introduced while programming late at night. It wasn't that the code was completely wrong, but it was wrong enough that it didn't really work correctly. That's when I learned about stopping before doing damage that I'd have to fix later. I wrote less code, and spent less time at it, yet was making better progress on meeting deadlines. Shocking but true.

A corollary to this:
Program when you're in the best frame of mind to if at all possible. I'm guessing you were up until 4am banging your head against something, not "in the zone". There are times when 4am is the perfect time to be programming. There are times that 7am or 4pm are when you are in just the right frame of mind. Working a long time on something is rarely as productive as working on it at the right time. I've spent days on something when I just wasn't in the zone for whatever reason, and was able to bang out the solution in an hour or two once I was. The previous effort wasn't a total loss, and probably helped some, but I would give a lot for a few more hours of "zone" time a week.

-Lee
 
^^To add to that, if you're banging your head against a wall of code, stop for a while. Many times, the answer will come to you when you're not actively thinking about it and away from the computer.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.