As some of you may have seen me experimenting with a program converting from Fahrenheit to Celsius and visa versa in Objective-C based off of console input and output. I'm just doing this to better learn the language and I think its a good way to demonstrate some of the things I've been exposed to.
So, anyway, I am looking to incorporate both the Kelvin and Rankine scales into my program, a good suggestion I'd like to take up on proposed by dreamlax.
Now, up until this point, my program has functioned relatively well for converting between Fahrenheit and Celsius, but if I need to convert between these 4 different scales, I'm going to have to work at it a different way in my opinion.
First off, I need to provide the end-user with the choice of their starting temperature, the temperature they want to convert from.
In order to do this, I need to prompt them with an NSLog or printf statement instructing them to do this.
Now, I would rather have them type out Fahrenheit, Celsius, Kelvin or Rankine, based upon which ever one they would like, rather than 0-3. Now, I don't think the scanf is capable, but if I'm wrong, I'd like to know if it either has this functionality, or this is another method I can take advantage of to add this to my program.
Next, I'm kind of lost. I obviously would need to instruct them to pick their target temperature, in other words, the temperature they want to convert to.
I need some help on a recommendation on how to organize this in my program.. Should I use only 1 class? Also, I guess I could set it up this way:
string baseTemp
string targetTemp
NSLog(@"Please type Fahrenheit, Celsius, Kelvin or Rankine to select your base temperature");
scanf or some other method here("string format specifier here" &baseTemp);
NSLog(@"Please type Fahrenheit, Celsius, Kelvin or Rankine to select your target temperature");
scanf or some other method here("string format specifier here" &targetTemp);
Now, I need a decision maker to decide if Fahrenheit == baseTemp and Celsius == targetTemp, then set up a certain formula accordingly.
This could get tedious, and I first off need that special decision maker, or just another simpler method.
Sorry for the probably quite awkward code, I'm trying to use what I've learned thus far here.
Any suggestions, tweaks, ideas and anything in between is greatly appreciated!
Thanks!!
UPDATE UPDATE: UPDATE:
The code for the class.h, class.m and main.m program files contain the final code, at least for this project, which dreamlax worked with me greatly to help us both achieve the goal I had. Thanks again dreamlax!!
class.h:
#import <Cocoa/Cocoa.h>
@interface Temperature : NSObject
{
double kelvin;
}
//Instance methods to convert argument to kevin
-(void) setFahrenheitValue: (double) f;
-(void) setCelsiusValue: (double) c;
-(void) setKelvinValue: (double) k;
-(void) setRankineValue: (double) r;
//Instance methods for extracting the kelvin value using any scale
-(double) fahrenheitValue;
-(double) celsiusValue;
-(double) kelvinValue;
-(double) rankineValue;
@end
class.m:
#import "class.h"
@implementation Temperature;
-(void) setFahrenheitValue: (double) f
{
kelvin = ((f + 459.67)*(5.0/9.0));
}
-(void) setCelsiusValue: (double) c
{
kelvin = (c + 273.15);
}
-(void) setKelvinValue: (double) k
{
kelvin = k;
}
-(void) setRankineValue: (double) r
{
kelvin = (r*(5.0/9.0));
}
-(double) fahrenheitValue
{
return ((kelvin*(9.0/5.0)) - 459.67);
}
-(double) celsiusValue
{
return (kelvin - 273.15);
}
-(double) kelvinValue
{
return (kelvin);
}
-(double) rankineValue
{
return (kelvin * (9.0/5.0));
}
@end
main.m:
#import <Cocoa/Cocoa.h>
#import "class.h"
int main(int argc, char *argv[])
{
int result;
int prompt;
double sourceTemp;
printf("Please choose a source temperature scale:\n[1] Fahrenheit\n[2] Celsius\n[3] Kelvin\n[4] Rankine\n\n");
result = scanf("%i", &prompt);
if (result != 1)
printf("I couldn't understand your input, I need only one number!");
else if (result == EOF)
printf("I apologize, I encountered an error when trying to read your input.");
else if (result == 1)
{
printf("\nNow, ple开发者_开发知识库ase enter the temperature you would like to convert:\n\n");
scanf("%lf", &sourceTemp);
Temperature *converter = [[Temperature alloc] init];
switch (prompt)
{
case 1:
//end-user chooses Fahrenheit
[converter setFahrenheitValue:sourceTemp];
break;
case 2:
//end-user chooses Celsius
[converter setCelsiusValue:sourceTemp];
break;
case 3:
//end-user chooses Kelvin
[converter setKelvinValue:sourceTemp];
break;
case 4:
//end-user chooses Rankine
[converter setRankineValue:sourceTemp];
break;
}
printf("\nNow, please choose a target temperature scale:\n[1] Fahrenheit\n[2] Celsius\n[3] Kelvin\n[4] Rankine\n\n");
scanf("%i", &prompt);
switch (prompt)
{
case 1:
//end-user chooses Fahrenheit
printf("%lf degrees Fahrenheit\n", [converter fahrenheitValue]);
break;
case 2:
//end-user chooses Celsius
printf("%lf degrees Celsius\n", [converter celsiusValue]);
break;
case 3:
//end-user chooses Kelvin
printf("%lf degrees Kelvin\n", [converter kelvinValue]);
break;
case 4:
//end-user chooses Rankine
printf("%lf degrees Rankine\n", [converter rankineValue]);
break;
}
}
}
Just an idea I'm trying to implement is to get the final prompt which displays the converted temperature to display like this:
Suppose the end-user selected Fahrenheit as his/her source temperature, wishing to convert 212 degrees into his/her target temperature scale of Celsius. The conversions should equal 100 degrees Celsius obviously, but I think the program would be better of displaying the result like this:
212 degrees Fahrenheit is 100 degrees Celsius.
Now, I've made the values that need to be replaced by variables in bold. I have the 212 and 100 values solved easily, because 100 has been there in the first place, and 212 can easily be remedied by replacing it with the string formatter of the sourceTemp variable.
Now, the Fahrenheit string is a bit different.
I have tried to establish something new in our original switch like so:
switch (prompt)
{
case 1:
//end-user chooses Fahrenheit
[converter setFahrenheitValue:sourceTemp];
sourceTempText = 1;
break;
case 2:
//end-user chooses Celsius
[converter setCelsiusValue:sourceTemp];
sourceTempText = 2;
break;
case 3:
//end-user chooses Kelvin
[converter setKelvinValue:sourceTemp];
sourceTempText = 3;
break;
case 4:
//end-user chooses Rankine
[converter setRankineValue:sourceTemp];
sourceTempText = 4;
break;
}
OK, so I have added to each different case, setting a new variable named sourceTempText to either 1-4, the same value that the end-user chose to pick his/her source temperature.
Now, here is how I tried to display the final prompt to the end-user with the final switch:
switch (prompt2)
{
case 1:
//end-user chooses Fahrenheit
printf("%lf degrees sourceTempText is %lf degrees Fahrenheit\n", sourceTemp, [converter fahrenheitValue]);
break;
case 2:
//end-user chooses Celsius
printf("%lf degrees sourceTempText is %lf degrees Celsius\n", sourceTemp, [converter celsiusValue]);
break;
case 3:
//end-user chooses Kelvin
printf("%lf degrees sourceTempText is %lf degrees Kelvin\n", sourceTemp, [converter kelvinValue]);
break;
case 4:
//end-user chooses Rankine
printf("%lf degrees sourceTempText is %lf degrees Rankine\n", sourceTemp, [converter rankineValue]);
break;
}
I am not sure now, if I can insert sourceTempText into the string like I have here, instead, maybe I have to use a string formatter, but I'm not sure. It should be an easy fix, I just wanted to throw it out here! :)
Hopefully the next project will be... GUI GUI GUI! xD
With regards to your class, one approach that I briefly touched on in your previous question could be:
It should store the value using only one temperature scale. Keep in mind that Rankine is to Fahrenheit what Kelvin is to Celsius. What I mean is that Rankine is simply Fahrenheit but with a different offset, and Kelvin is simply Celsius but with a different offset (Rankine and Kelvin both consider 0° to be absolute zero). Scientifically, Kelvin would be a good choice of base scale since it is the international standard for temperature measurements (USA, Burma and Liberia are the only countries that have not adopted the SI system). There are some pros and cons to using only one temperature scale:
There will be a loss of precision because you are converting twice (once to convert the source scale to kelvin, and then another conversion to convert to the user's desired scale)
However, the implementation of your class will be simpler because there is only one variable.
You only need one instance of your Converter class. When you read input from the command line, you tell the Converter class instance the measurement as well as the scale that the user chose. For example, your Converter interface could adopt the following methods:
@interface Temperature : NSObject { double kelvin; } - (void) setCelsiusValue:(double) c; // kelvin = (c + 273.15) - (void) setKelvinValue:(double) k; // kelvin = k - (void) setFahrenheitValue:(double) f; // kelvin = (f + 459.67) × 5⁄9 - (void) setRankineValue:(double) r; // kelvin = (f × 5/9) @end
All of these methods should convert the argument into the Kelvin scale.
Your class should also implement ways to extract the value using any scale. It could adopt the following methods for that purpose:
@interface Temperature : NSObject { double kelvin; } // include methods from above - (double) celsiusValue; // return kelvin - 273.15 - (double) kelvinValue; // return kelvin - (double) fahrenheitValue; // return kelvin × 9⁄5 − 459.67 - (double) rankineValue; // return kelvin × 9/5 @end
Each of these methods should convert the Kelvin value into the relevant scale using the appropriate formula.
With regards to user interaction, typically NSLog
is used only for logging information about your application during runtime (for example, to inspect what an object's value is or to determine the point of execution in your application). For asking questions it is usually more mainstream to use printf
.
You could print out a menu like this:
Please choose a source temperature scale:
[1] Celsius
[2] Kelvin
[3] Fahrenheit
[4] Rankine
Then print out another menu for the target temperature scale, and then ask the user for the source temperature measurement. Generally you should not ask a user to type out a full word because it is easier to mistype than a simple number. There's also a special programming construct called a switch
. It has some caveats but works nicely with multi-choice question/answers. Once you have read the user's input using scanf
, you can do this:
int prompt;
double sourceTemp;
// use scanf to read values into prompt and sourceTemp variables
Temperature *converter = [[Temperature alloc] init];
switch(prompt)
{
case 1: // the user chose celsius
[converter setCelsiusValue:sourceTemp];
break; // if you don't break, it will execute all other cases
case 2: // user chose kelvin
[converter setKelvinValue:sourceTemp];
break;
case 3:
[converter setFahrenheitValue:sourceTemp];
break;
case 4:
[converter setRankineValue:sourceTemp];
break;
}
// prompt the user again here to determine the target temperature scale
// use the same menu again and read the user's input into the prompt variable
case (prompt)
{
case 1: // user wants to convert to celsius
printf("%f degrees C\n", [converter celsiusValue]);
break;
case 2: // user wants kelvin
printf("%f degrees K\n", [converter kelvinValue]);
break;
case 3:
printf("%f degrees F\n", [converter fahrenheitValue]);
break;
case 4:
printf("%f degrees R\n", [converter rankineValue]);
break;
}
With regards to scanf
, it does two things. Firstly, it scans input into the provided variables, and secondly it returns the number of items successfully scanned. For example:
int result;
int first;
int second;
printf("Please type two numbers: ");
result = scanf("%d %d", &first, &second);
If scanf
successfully read two numbers, then result
should equal 2. If it is equal to 2, then you can be certain that first
and second
contain good data, you can be certain that scanf
has scanned the input successfully. Similarly, if you only ask scanf
to read one number, then if result
is equal to 1 then it successfully read that one number.
If result
is 1, then it means that it only scanned one number, and then encountered a problem. For example, if the user has typed “100 abc”, scanf
will only be able to read one number, but we've asked for two. In this case, it will return 1 to tell us that it has only scanned one integer.
If result
is 0, then it means that scanf
was unable to scan anything that matches what we asked for (if the user entered “abc abc” for example).
Lastly, result
will be EOF
(end-of-file) if there was no data to read.
So, it is important to check the return value of scanf
calls to make sure that the user has entered something valid. If the result is 0, you know the user has entered something invalid, and if the result is EOF
then there was a problem reading any data at all. So, we could have this setup:
int result;
int first;
int second;
printf("Please type two numbers: ");
result = scanf("%d %d", &first, &second);
if (result == 0)
printf("I couldn't understand what you gave me, I need numbers!\n");
else if (result == 1)
printf("I was only able to read one number!\n");
else if (result == EOF)
printf("Whoops, there was some problem trying to read your input\n");
else if (result == 2) // scanf was able to read two numbers
printf("Great! The sum of those two numbers is: %d\n", first + second);
精彩评论