I'm making an app for iPhone using obj-c that finds side lengths and angles for triangles. Part of the app uses the Pythagorean Theorem.
NSNumber *pySidea = [NSNumber numberWithInteger:[[sideA text] integerValue]];
NSNumber *pySideb = [NSNumber numberWithInteger:[[sideB text] integerValue]];
NSNumber *pySidec = [NSNumber numberWithInteger:[[sideC text] integerValue]];
int pyAside = [pySidea intValue];
int pyBside = [pySideb intValue];
int pyCside = [pySidec intValue];
if ([aSide length] = 0) {
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
sideCstring = #"_anserSidec";
}
sideA, sideB and sideC are the sides of a triangle using a text field. I don't get an error for any part except
if ([aSide length] = 0) {
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
sideCstring = #"_anserSidec";
}
where I get "Expected identifier". Thanks for any help.
This line:
NSString *finalAnserc = [sqrtf(powf(pyAside, 2) + powf(pyBside, 2))];
Seems to be wanting to create a string, but doesn't do anything except some arithmetic inside square brackets, which isn't valid syntax. I think you want something like:
float answer = sqrtf(powf(pyAside, 2) + powf(pyBside, 2));
NSString *finalAnswer = [[NSNumber numberWithFloat:answer] stringValue];
Calling powf() to square a number is a bit heavy-handed, too. You could just write:
float answer = sqrtf(pyAside*pyAside + pyBside*pyBside);
As Nithin notes in his answer, you have a logical error with your if statement too - you want to be using == probably.
Check your 'if' condition , it should be if([aSide length] == 0)
Remember two equal (=) signs...
Related
I need to know whatever an int64_t has decimals, and how many. This should be placed in if-else-statement. I tried this code, but it causes the app to crash.
NSNumber *numValue = [NSNumber numberWithInt:testAnswer];
NSString *string = [numValue stringValue];
NSArray *stringComps = [string componentsSeparatedByString:#"."];
int64_t numberOfDecimalPlaces = [[stringComps objectAtIndex:1] length];
if (numberOfDecimalPlaces == 0) {
[self doSomething];
} else {
[self doSomethingElse];
}
Your question doesn't make a lot of sense; you are creating the NSNumber object from an int so it will never have decimal places, as an int cannot store them. The reason your code is crashing is that it assumes that the array of components is always at least 2 elements long (as you use objectAtIndex:1).
This is better, though still not that good:
NSString *answer = ...; // From somewhere
NSArray *stringComps = [answer componentsSeparatedByString:#"."];
if ([stringComps count] == 0) {
[self doSomething];
} else if [stringComps count] == 1) {
[self doSomethingElse];
} else {
// Error! More than one period entered
}
This still isn't a very good test as it only tests if a period (.) has been entered, not a valid number.
I have a plist file that I am reading out a measurement, but some of the measurements are fractions such as 6 3/8". I formatted them that way because it's easier to find that on a tape measure than it is to find 6.375". My problem is now I want to do a conversion to metric on the fly and it isn't reading in the fraction part of the number. My current code is this.
cutoutLabel.text = [NSString stringWithFormat:#"%.2f mm. %#", [[[sizeDict valueForKey:Sub_Size] objectForKey:#"Cutout Dimensions"]floatValue] * 25.4, [temp objectAtIndex:2]];
Thanks.
That's what I ended up doing.
NSArray *temp = [[[sizeDict valueForKey:Sub_Size] objectForKey:#"Cutout Dimensions"] componentsSeparatedByString:#" "];
if ([temp count] > 2) {
NSArray *fraction = [[temp objectAtIndex:1]componentsSeparatedByString:#"/"];
convertedFraction = [[fraction objectAtIndex:0]floatValue]/[[fraction objectAtIndex:1]floatValue];
}
You can get the numerator and denominator as follows:
NSRange slashPos = [fraction.text rangeOfString:#"/"];
NSString * numerator = [fraction.text substringToIndex:slashPos.location];
NSString * denominator = [fraction.text substringFromIndex:slashPos.location+1];
You should take more care than this,
check that your range is of length 1 and make sure that the string has characters after the "/" character. But if you know you are feeding this code a fraction string it should work in your case
The idea is in place, but you will also need to apply the same logic first to separate the whole number from you fraction. Apply the same logic, searching for a #" " and then find the numerator and denominator
Building on Ian's answer and trying to be a little more complete (since his example was for a whole number and fractional part with an inch character (6 3/8"), I suggest the following method (it also works if there are spaces before the whole number:
// Convert a string consisting of a whole and fractional value into a decimal number
-(float) getFloatValueFromString: (NSString *) stringValue {
// The input string value has a format similar to 2 1/4". Need to remove the inch (") character and
// everything after it.
NSRange found = [stringValue rangeOfString: #"\""]; // look for the occurrence of the " character
if (found.location != NSNotFound) {
// There is a " character. Get the substring up to the "\"" character
stringValue = [stringValue substringToIndex: found.location];
}
// Now the input format looks something like 2 1/4. Need to convert this to a float value
NSArray *temp = [stringValue componentsSeparatedByString:#" "];
float convertedFraction = 0;
float wholeNumber = 0;
for (int i=0; i<[temp count]; i++) {
if ([[temp objectAtIndex:i] isEqualToString:#""]) {
continue;
}
NSArray *fraction = [[temp objectAtIndex:i]componentsSeparatedByString:#"/"];
if ([fraction count] > 1) {
convertedFraction = [[fraction objectAtIndex:0]floatValue]/[[fraction objectAtIndex:1]floatValue];
}
else if ([fraction count] == 1) {
wholeNumber = [[fraction objectAtIndex:0] floatValue];
}
}
convertedFraction += wholeNumber;
return convertedFraction;
}
If I have formatting for a textfield like:
//Formats the textfield based on the pickers.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSString *result = [feetArray objectAtIndex:[feetPicker selectedRowInComponent:0]];
result = [result stringByAppendingFormat:#"%#ft", [feetArray objectAtIndex:[feetPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:0]]];
result = [result stringByAppendingFormat:#"%#", [inchArray objectAtIndex:[inchesPicker selectedRowInComponent:1]]];
result = [result stringByAppendingFormat:#" %#in", [fractionArray objectAtIndex:[fractionPicker selectedRowInComponent:0]]];
myTextField.text = result;
}
Which display's in the textfield like 00ft 00 0/16in How can I change that all to inches with decimal? I'll need to take the ft, and multiply by 12 = variable.Then add that to inches, as well as take my fraction 1/16 and divide that by 16 to get my decimal value and then add that to the inches so it shows like 1234.0625 in order to make my calculation. Can someone help me accomplish this? Thank you in advance!
NSString * theString = RiseTextField.text;
NSString * feetString = [theString substringWithRange:NSMakeRange(0, 2)];
NSString * inchesString = [theString substringWithRange:NSMakeRange(5, 2)];
NSUInteger rangeLength = ([theString length] == 14) ? 1 : 2;
NSString * fractionString = [theString substringWithRange:NSMakeRange(8, rangeLength)];
double totalInInches = [feetString doubleValue] * 12 + [inchesString doubleValue] + [fractionString doubleValue] / 16;
You can easily get the number that you want by doing the calculations with the numbers you have there. Once you've got the actual number, you should use a NSNumberFormatter to present it with the desired amount of decimals and format.
This should solve your problem. Or did you need help converting the strings to numbers so that you can add them together?
How do I format a float to string so that if the user enters a number that has 2 or less decimal places then it is formatted to have 2 decimal places, but if the user enters a float that has 2 or more decimal places then all decimal places are shown. e.g.
4.1 => 4.10
1 => 1.00
1.358484 => 1.358484
So therefore the formatting is to 2 decimal places or more if needed.
Hope I made sense.
Try something like this.
BOOL requiresExtraPrecision (double num) {
double roundedToHundredth = round(num * 100.0) / 100.0;
double diff = num - roundedToHundredth;
if (diff < 0) diff = 0.0 - diff;
if (diff < 0.0000001) {
return NO;
} else {
return YES;
}
}
NSString *formatted (double num) {
if (requiresExtraPrecision(num)) {
return [NSString stringWithFormat:#"%F", num];
} else {
NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
[formatter setMaximumFractionDigits:2];
[formatter setMinimumFractionDigits:2];
return [formatter stringFromNumber:[NSNumber numberWithDouble:num]];
}
}
As #Carl wrote in a comment to the question, the hard part is deciding when a double needs all of its precision. In this code, I'm assuming that if the double is "close enough" to a rounded number (within a millionth), then we should just display the rounded number.
You might decide to make it stricter (a billionth?) but you'll always have to use some kind of approximation, because some decimals can't be stored precisely as a float. Even though the user may have typed "0.1" at input time, that information is lost when the number is stored as a float.
So, given that you'll have a float that's extremely close to a decimal but not exactly right, you'll have to decide when you think the float is "close enough" to the decimal.
If you need absolute precision (if you're working with money!) then you should consider using an NSDecimal or an NSDecimalNumber instead of a float.
this could work for you:
NSNumber *aFloat = [NSNumber numberWithFloat:1.2]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
NSString *finalString;
if (dot.location != NSNotFound) {
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
if (decimals.length<1){ // ends with "."
finalString = [numberString stringByAppendingString:#"00"];
}else if (decimals.length<2){ // ends with ".n"
finalString = [numberString stringByAppendingString:#"0"];
}else { // 2 or more decimals: no changes
finalString = numberString;
}
}else { // no decimals
finalString = [numberString stringByAppendingString:#".00"];
}
NSLog(#"______._____finalString:%#", finalString );
EDIT (more flexible, it works with variable numbers of decimals):
NSNumber *aFloat = [NSNumber numberWithFloat:1.1235]; //try 1.234 ; 1.23 ; 1.2 ; 1. ; 1
NSString *numberString = [aFloat stringValue];
NSRange dot;
dot = [numberString rangeOfString:#"."];
if (dot.location == NSNotFound) { // no decimals, add a dot
numberString = [numberString stringByAppendingString:#"."];
NSLog(#"__added dot___ numberString:%#", numberString );
}
dot = [numberString rangeOfString:#"."];
NSString *decimals = [numberString substringFromIndex:dot.location + dot.length];
// int initialDecimals = decimals.length;
int numberOfDecimalsTerget = 2;
for (int initialDecimals = decimals.length; initialDecimals<numberOfDecimalsTerget; initialDecimals++) {
numberString = [numberString stringByAppendingString:#"0"];
}
NSLog(#"__END_._____numberString:%#", numberString );
I have a method that gets called any time a control on my view changes and should update a UILabel. It has two UITextFields and two UISliders. First I check to see if either of the UITextFields are empty and if so, advise that they need to be filled in. Otherwise I get the difference between the UITextFields' values and generate a couple of floats to use in my NSStrings.
I get a warning that message is not used and I get an error about the NSStrings (can't remember now exactly what - I'm not at my Mac...)
And even when I chopped the messages down to something simple that worked, when delta == 0, it does the delta <= 0 message.
Oh, and the strings don't put the values in where the % signs are, they just print the % signs.
I've been hacking at this too long and need help...
- (void)updateAdvice {
if ([chlorineSourceField.text isEqualToString:#""] || [poolVolumeField.text isEqualToString:#""]) {
NSString *message = [[NSString alloc] initWithString:#"Enter a chlorine source and pool volume."];
}
else {
int delta = [targetLabel.text intValue] - [startingLabel.text intValue];
float chlorineAmount = delta * [poolVolumeField.text intValue] * chlorineConstant;
float percentRemove = (1 - ([targetLabel.text floatValue] / [startingLabel.text floatValue]));
float gallonsRemove = percentRemove * [poolVolumeField.text intValue];
if (delta == 0) {
NSString *message = [[NSString alloc] initWithString:#"No adjustments necessary. You're on target"];
}
if (delta >= 0) {
NSString *message = [[NSString alloc] initWithFormat:#"To increase FC by %dppm, add %3.1f oz of %#.", delta, chlorineAmount, chlorineSourceField.text];
}
if (delta <= 0) {
NSString *message = [[NSString alloc] initWithFormat:#"You're above target already. Replace %d%% or %d gallons of water - or just wait for it to come down.", percentRemove*100, gallonsRemove];
}
}
adviceLabel.text = message;
[message release];
}
You are missing the else part, thus all three if statements are being evaluated consecutively. If delta == 0, it will satisfy all three if statements. Thus, the last allocation will overwrite the previous two. (And you'll be leaking memory)
Also, your message variable is scoped as local to the if block it's declared into. You might want to move the message declaration at the function level scope.
As far as % not working, you are using the instance initializer initWithFormat with the syntax for the class initializer stringWithFormat. initWithFormat takes the parameters for the formatted string in a separate parameter - arguments:. (Btw, it also requires locale:)
As far as the message variable goes, it's scoped so it can't be used outside the if/else statement in which it is declared. You want to declare it before the if statement, so you can use it outside of the if statement. So something like this:
- (void)updateAdvice {
NSString *message = nil;
if ([chlorineSourceField.text isEqualToString:#""] || [poolVolumeField.text isEqualToString:#""]) {
message = [[NSString alloc] initWithString:#"Enter a chlorine source and pool volume."];
}
else {
int delta = [targetLabel.text intValue] - [startingLabel.text intValue];
float chlorineAmount = delta * [poolVolumeField.text intValue] * chlorineConstant;
float percentRemove = (1 - ([targetLabel.text floatValue] / [startingLabel.text floatValue]));
float gallonsRemove = percentRemove * [poolVolumeField.text intValue];
if (delta == 0) {
message = [[NSString alloc] initWithString:#"No adjustments necessary. You're on target"];
}
if (delta >= 0) {
message = [[NSString alloc] initWithFormat:#"To increase FC by %dppm, add %3.1f oz of %#.", delta, chlorineAmount, chlorineSourceField.text];
}
if (delta <= 0) {
message = [[NSString alloc] initWithFormat:#"You're above target already. Replace %d%% or %d gallons of water - or just wait for it to come down.", percentRemove*100, gallonsRemove];
}
}
adviceLabel.text = message;
[message release];
}