I am probably missing something obvious (still learning about Objective-C!) but for some reason one of my NSString variables has a null value in my if statement and I don't know why?
I have even output to NSLog and I still can't see why it's behaving like this.
Basically, the user enters an amount in a text field (itemWeight) and this if statement validates the input and displays an alert according to the result. The problem only seems to be when 0.751 is entered, if you enter any other amount (0.750, 0.749, 0.752, 0.753 and so on) it works as expected.
Relevant code samples as follows...
.h file:
#property (strong, nonatomic) IBOutlet UITextField *itemWeight;
.m file:
NSString *rawWeightText = itemWeight.text;
float convertedWeightText = rawWeightText.floatValue;
NSString *weightMessage;
if (convertedWeightText <= 0.750)
{
weightMessage = #"under 0.750";
}
else if (convertedWeightText >= 0.751)
{
weightMessage = #"0.751 or over";
}
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: #"Error"
message: weightMessage
delegate: nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
Any ideas where I'm going wrong/what I've forgotten to do would be much appreciated, thank you!
Looking at the condition of your if-else if code does not have the range of from 0.750 to 0.751.
floating-point values must be careful to compare. you should consider about 0.751 possibility 0.75099999...
the following loop, the result is 99.999046, not 100. Continue to add more accuracy is poor.
float a= 0.1f;
float result = 0.f;
for(int i = 0; i<1000; i++)
{
result += 0.1f;
}
printf("result:%f", result); //99.999046
So, In General, Comparison of these expressions is not recommended.
if (result == expectedResult)
Writing the following method is recommended to compare.
bool AlmostEqualRelative(float A, float B, float maxRelativeError)
{
if (A == B)
return true;
float relativeError = fabs((A - B) / B);
if (relativeError <= maxRelativeError)
return true;
return false;
}
For more information, please read here
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
also, you must read this wiki:
http://en.wikipedia.org/wiki/Floating_point
http://en.wikipedia.org/wiki/Denormal_number
Decimal values often can't be exactly represented in binary. When the user enters 0.751, its likely that the actual float that you get back is slightly smaller, like 0.750999942. Try logging the value to see what's going on.
You are not the first programmer who is surprised by the actual behavior of floating point numbers.
In fact it is more a problem with binary decimal numbers, then the floating point details.
Try to convert 0.751, which has only 3 digits in the fractional part, into a binary number and you'll see.
To make it short, 0.751 is represented as a binary exponent of -1 and a mantissa of 1.10000000100000110001001 in a float (float only has 23+1 bits of precision for the mantissa).
That is, in decimal, an exponent of -1 and a mantissa of 1.5019999742507935.
Therefore 2^-1 * 1.5019999742507935 = 0.7509999871254 and it does not pass the test in the if.
Related
In my code, I'm dealing with an NSString that contains an NSNumber value. This NSNumber value could possibly be a repeating decimal number (e.x. 2.333333333e+06) that shortens to "2.333333" in a string format. It could also be a terminating number (e.x. 2.5), negative, or irrational number (2.398571892858...) (only dealing with decimals here)
I need to have a way to figure out if there are the repeating numbers in the string (or the NSNumber, if necessary). In my code, I would have no way to know what the repeating number would be, as it's a result of computations started by the user. I have tried this for loop (see below) that doesn't work the way I want it to, due to my inexperience with string indexing/ranges/lengths.
BOOL repeat = NO; //bool to check if repeating #
double repNum, tempNum; //run in for loop
NSString *repeating = [numVal stringValue]; //string that holds possible repeating #
for (int i = 3; i <= [repeating length]-3; i++) { //not sure about index/length here
if (i == 3) {
repNum = [repeating characterAtIndex:i];
}
tempNum = [repeating characterAtIndex:i];
if (tempNum == repNum) {
repeat = YES;
} else {
repeat = NO;
}
}
This code doesn't work as I'd like it to, mainly because I also have to account for negative dashes in the string and different amounts of numbers (13 1/3 vs. 1 1/3). I've used the modffunction to separate the integers from the decimals, but that hasn't worked well for me either.
Thank you in advance. Please let me know if I can clarify anything.
EDIT:
This code works with the finding of different solutions for polynomials (quadratic formula). Hope this helps put it into context. See here. (Example input)
NSNumber *firstPlusSolution, *secondMinusSolution;
NSString *pValueStr, *mValueStr;
firstPlusSolution = -(b) + sqrt(square(b) - (4)*(a)*(c)); //a, b, c: "user" provided
firstPlusSolution /= 2*(a);
secondMinusSolution = -(b) - sqrt(square(b) - 4*(a)*(c));
secondMinusSolution /= 2*(a);
pValueStr = [firstPlusSolution stringValue];
mValueStr = [secondMinusSolution stringValue];
if ([NSString doesString:pValueStr containCharacter:'.']) { //category method I implemented
double fractionPart, integerPart;
fractionPart = modf(firstPlusSolution, &integerPart);
NSString *repeating = [NSString stringWithFormat:#"%g", fractionPart];
int repNum, tempNum;
BOOL repeat = NO;
//do for loop and check for negatives, integers, etc.
}
if ([NSString doesString:mValueStr containCharacter'.']) {
//do above code
//do for loop and check again
}
Use C. Take the fractional part. Convert to a string with a known accuracy. If length of string indicates that last digits are missing, then it does not repeat. Use NSString-UTF8String to convert a string. Get rid of the last digit (may be rounding or actual floating point arithmetic error). Use function int strncmp ( const char * str1, const char * str2, size_t num ) to perform comparison within the string itself. If the result is 8 characters long and the last 2 characters match the first 2 characters, then shall the first 6 characters be considered repeating?
Assuming that fraction knowledge your desire:
• Possibility 1: Use fractions. Input fractions. Compute with fractions. Output fractions. Expand upon one of the many examples of a c++ fraction class if necessary and use it.
• Possibility 2: Choose an accuracy which is much less than double. Make a fraction from the result. Reduce the fraction allowing rounding based upon accuracy.
I suggest use not optimal but easy to write solution
Create NSMutableDictionary that will contain number as key and count of occurrence as value.
You can use componentsSeparatedByString: if numbers in string delimited by known symbol
In loop check valueForKey in dictionary and if need increase value
Last step is analyzing our dictionary and do anything you need with numbers
Im trying to create a Binary to Decimal calculator and I am having trouble doing any sort of conversion that will actually work. First off Id like to introduce myself as a complete novice to objective c and to programming in general. As a result many concepts will appear difficult to me, so I am mostly looking for the easiest way to understand and not the most efficient way of doing this.
I have at the moment a calculator that will accept input and display this in a label. This part is working fine and I have no issues with it. The variable that the input is stored on is _display = [[NSMutableString stringWithCapacity:20] retain];
this is working perfectly and I am able to modify the data accordingly. What I would like to do is to be able to display an NSString of the conversion in another label. At the moment I have tried a few solutions and have not had any decent results, this is the latest attempt
- (NSMutableString *)displayValue2:(long long)element
{
_str= [[NSMutableString alloc] initWithString:#""];
if(element > 0){
for(NSInteger numberCopy = element; numberCopy > 0; numberCopy >>= 1)
{
[_str insertString:((numberCopy & 1) ? #"1" : #"0") atIndex:0];
}
}
else if(element == 0)
{
[_str insertString:#"0" atIndex:0];
}
else
{
element = element * (-1);
_str = [self displayValue2:element];
[_str insertString:#"0" atIndex:0];
NSLog(#"Prima for: %#",_str);
for(int i=0; i<[_str length];i++)
_str = _display;
NSLog(#"Dopo for: %#",_str);
}
return _str;
}
Within my View Controller I have a convert button setup, when this is pressed I want to set the second display field to the decimal equivalent. This is working as if I set displayValue2 to return a string of my choosing it works. All I need is help getting this conversion to work. At the moment this bit of code has led to "incomplete implementation" being displayed at the to of my class. Please help, and cheers to those who take time out to help.
So basically all you are really looking for is a way to convert binary numbers into decimal numbers, correct? Another way to think of this problem is changing a number's base from base 2 to base 10. I have used functions like this before in my projects:
+ (NSNumber *)convertBinaryStringToDecimalNumber:(NSString *)binaryString {
NSUInteger totalValue = 0;
for (int i = 0; i < binaryString.length; i++) {
totalValue += (int)([binaryString characterAtIndex:(binaryString.length - 1 - i)] - 48) * pow(2, i);
}
return #(totalValue);
}
Obviously this is accessing the binary as a string representation. This works well since you can easily access each value over a number which is more difficult. You could also easily change the return type from an NSNumber to some string literal. This also works for your element == 0 scenario.
// original number wrapped as a string
NSString *stringValue = [NSString stringWithFormat:#"%d", 11001];
// convert the value and get an NSNumber back
NSNumber *result = [self.class convertBinaryStringToDecinalNumber:stringValue];
// prints 25
NSLog(#"%#", result);
If I misunderstood something please clarify, if you do not understand the code let me know. Also, this may not be the most efficient but it is simple and clean.
I also strongly agree with Hot Licks comment. If you are truly interested in learning well and want to be an developed programmer there are a few basics you should be learning first (I learned with Java and am glad that I did).
I'm trying to calculate the appropriate height for a UITableViewCell and a UIImageView by using the following method that gets called:
-(void)ratioCalculator
{
picH = image.size.height;
picW = image.size.width;
NSLog(#"%d = width %d = height", picW, picH);
picRatio = (picW/picH);
NSLog(#"%F", picRatio);
imageViewH = (260/picRatio);
NSLog(#"%d int", imageViewH);
return;
}
The thing is, when it gets called, the picRatio = (picW/picH); doesn't seem to be happening as the console says this:
2012-11-18 21:56:48.787 Name[5374:c07] 640 = width 360 = height
2012-11-18 21:56:48.788 Name[5374:c07] 1.000000
2012-11-18 21:56:48.788 Name[5374:c07] 260 int
The 1.000000 is the float picRatio and the 260 is the imageViewH. Obviously this means the incorrect heights are used for both the UITableViewCell and the UIImageView which are calculated like this:
else {
[self ratioCalculator];
return (imageViewH + 20);
}
and
- (void)showImage:(UIImage *)theImage
{
self.imageView.image = theImage;
self.imageView.hidden = NO;
[self ratioCalculator];
self.imageView.frame = CGRectMake(10, 10, 260, imageViewH);
self.photoLabel.hidden = YES;
}
As stupid a question as this probably is, why isn't this simple division working? Again, sorry if this is a stupid question, but it has me stumped. I feel like I'm going slightly mad.
Any help would be greatly appreciated,
Regards,
Mike
picRatio = ((float)picW/(float)picH);
Objective-c needs the proper iVar type assignment before dividing.
When you divide 2 integers, the output isn't a float, but an integer.
So 640/360 = 1.777 and this is treated as an integer, so the decimal value is ignores, which gives you the 1, you are getting.
If you do what I wrote, will actually produce a float, and give you the 1.777 output.
What you are missing is to cast the integers to float in order to make a float division
picRatio = (picW/picH); // gives an int division if picW and picH are declared integers
picRatio = (float)(picW)/picH; // gives you a floating point division
Since no one is posting an official answer, I thought I'd do so to help anyone in a similar position. The comments on my question put me on the right track, and after further investigations I discovered that the compiler calculates the output based on the types of the operands. Therefore, if all the operands are ints, it casts an int to the destination, regardless of if it's a float or not. Solution: make at least one of your operands a float.
Hope this helps anyone in a similar position.
Maybe this is a dumb question, but I really can't get it. For some reason float values in my program get rounded up during the assignment statement.
Here is the code:
Float64 time,test;
for( Shot *sh in _arrayOfShots)
{
time = sh.bFrameTime;
// right here time variable gets value rounded up to 2 decimal places
// for example: if sh.bFrameTime = 81.919998 => time = 81.92
NSNumber *num = [NSNumber numberWithFloat:time];
test = [num floatValue];
[edgeTime addObject:num];
}
// this is my Shot object structure
#interface Shot : NSObject
{
int bFrame;
int eFrame;
Float64 bFrameTime;
}
If anyone knows how to deal with this, please give me hint!
Thank you!
81.919998 => time = 81.92
is not "rounded up to two decimal places". The difference in the two is 0.000002, a change in magnitude of 0.0000000244, or about 8 decimal places. If your source value is single-precision float then it only has 7 decimal places of accuracy. (But you didn't show the declaration of that so we can't tell.)
The difference could also have to do with how you displayed the two values, as NSLog does a modicum of rounding.
Add an if statement where you check if the rounded number is larger than the initial number, if so subtract it by 1
I am trying to implement the code snippet below. However I am unable to get my expected results. For example if my disanceFromLoc = 0.16, I am still getting my output as 0.16 km.
Is there something wrong with the way I am comparing the value? object is of 'NSNumber' class (defined it as double in core data)
if ([object.distanceFromLoc doubleValue] < 0)
{
cell.detailTextLabel.text = [[NSString alloc] initWithFormat:#"Approx. Distance: %0.2f m", [object.distanceFromLoc doubleValue]*1000];
}
else
{
cell.detailTextLabel.text = [[NSString alloc] initWithFormat:#"Approx. Distance: %0.2f km", [object.distanceFromLoc doubleValue]];
}
Thanks!
Zhen Hoe
I believe you mean to compare to one, not zero.
As it stands, you're checking if your distanceFromLoc is negative, which (presumably) never happens with a regular distance. Instead, you should be checking if you're closer than 1km (i.e. < 1), at which point you can multiply by 1000 and convert to meters.