Objective C - What is wrong with this great circle distance calculation? - objective-c

I am trying to do the great circle distance calculation. As you should be able to glean, the Location class has the properties listed in the calculation.
- (NSNumber *)greatCircleDistanceFrom:(Location *)other
{
// Unpack all the NSNumbers into doubles so we can manipulate them
double selfCosRadLat = [self.cosRadLat doubleValue];
double otherCosRadLat = [other.cosRadLat doubleValue];
double selfRadLng = [self.radLng doubleValue];
double otherRadLng = [other.radLng doubleValue];
double selfSinRadLat = [self.sinRadLat doubleValue];
double otherSinRadLat = [other.sinRadLat doubleValue];
// Multiplying by 3959 calculates the distance in miles.
double d = acos(selfCosRadLat
* otherCosRadLat
* cos(selfRadLng - otherRadLng)
+ selfSinRadLat
* otherSinRadLat
) * 3959.0;
return [NSNumber numberWithDouble:d];
}
Half the time I run my unit test, I get the right value. The other half, I get 6218.78265778.

Make sure that your incoming Location value isn't nil or 0,0. It seems like the reason you'd get a constant like that is because it is doing the math as if it were at 0°,0°. Are you 6218 miles from approximately west Africa? If so, your function is working great, but the method calling it isn't providing real values some of the time.

Related

Round double in Objective-C

I want to round a double to one decimal place in Objective-C.
In Swift I can do it with an extension:
public extension Double {
/// Rounds the double to decimal places value
func rounded(toPlaces places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}
However, apparently you cannot call extensions on primitives from Objective-C so I can't use the extension.
I would be happy to do the rounding either on the double directly or as a string, however, neither of the following is working:
double mydub = 122.12022222223322;
NSString *axtstr = [NSString stringWithFormat:#"%2f", mydub]; //gives 122.120222
double rounded = (round(mydub*10)) / 10.0; //gives 122.100000
How do I convert 122.12022222223322; into 122.1?
You need to put a decimal between the % and 2f
[NSString stringWithFormat:#"%.2f", mydub];
double mydouble = 122.12022222223322;
NSString *str = [NSString stringWithFormat:#"%.2f", mydouble];
// = #"122.12"
.. will not round mydouble. Instead it will only apply format to the output as string.
double d = 122.49062222223322;
NSString *dStr = [NSString stringWithFormat:#"%.f %.1f %.2f %.3f", d, d, d, d];
// = #"122 122.5 122.49 122.491"
As Objective-C shares the language rules from C you can round safely with
#include <math.h>
double rounded = round(mydouble);
// = 122.000000
of course you can shift comma with multiplication and dividing the power of ten you want.
double commashifted = round(mydouble*100.0)/100.0;
// = 122.120000;
If you are really into Objective-C Classes to do same in deluxe have a look into 'NSDecimal.h' in the Foundation Framework.
Last but not least you can do the same with C as you did with swift.
double roundbycomma(int commata, double zahl) {
double divisor = pow(10.0, commata);
return round(zahl * divisor) / divisor;
}

Double division loses decimal places in objective-c

What do I have to do to have more than just one decimal place when dividing floats and doubles.
The code is:
double *dbl; //In fact this is a parameter of the function
double *kg;
double total = 41.2;
*dbl = *kg * 1000.0l / total;
In my case, *kg = 2485 and total = 41.2. So, the result should be someting like 60315.5339805. However, I only get 60315.5. What do I have to do in order not to lose the rest of the decimal digits.
I know I can use NSNumber, but when I convert to double using doubleValue, I always get 60315.5.
Thank you in advance.
This works fine for me:
- (void) myFunc:(double *)dbl
{
double kg = 2485;
double total = 41.2;
*dbl = kg * 1000.0l / total;
}
- (void)viewDidLoad
{
[super viewDidLoad];
double d;
[self myFunc:&d];
NSLog(#"%lf",d);
}

double to int (or long, long long) conversion sometimes is not good

I am trying to convert quite big double number to int (or long or long long), but have some difficulties. Almost always it converts good, but not sometimes:
My code:
double price = 12345678.900000;
double hundredNumber = price * 100;
NSNumber *number = [NSNumber numberWithDouble:hundredNumber];
int tempNumber = [number intValue];
All goes good, until tempNumber. it logs out 1234567889, but it should be 1234567890 (...89 - ...90)
Does anyone know why it could happen and how to convert correctly?
P. S. I am trying to implement backspace to value (e.x. 123.45, after that it should be 12.34). Maybe anyone had implemented something like this?
You're always going to get the risk of rounding errors if you're using floating point numbers.
Why not always store prices as a long long?
i.e. instead of £5.50, store 550p. That way you will never have any rounding issues at all.
As commented, I would be careful with the roundings, because of the possible errors.
One possible solution is to work with doubles like Google does with coordinates in Android: multiplying them by 1E6. If you operate with integers then you'll safe much more CPU cycle than operating with doubles. Try this out:
double priceDouble = 33.f / 34.f;
NSLog(#"double: %f", priceDouble);
NSInteger priceInteger = (NSInteger)(priceDouble * 1E6);
NSLog(#"int: %d", priceInteger);
NSNumber * priceNumberWithDouble = [NSNumber numberWithDouble:priceInteger];
priceDouble = [priceNumberWithDouble doubleValue];
NSLog(#"double: %f", priceDouble);
NSNumber * priceNumberWithInteger = [NSNumber numberWithInteger:priceInteger];
priceInteger = [priceNumberWithInteger integerValue];
NSLog(#"int: %d", priceInteger);
double test = ((double)priceInteger)/1E6;
NSLog(#"Test: %f",test);
My output is the following:
double: 0.970588
int: 970588
double: 970588.000000
int: 970588
Test: 0.970588

speed up this Standard Deviation method

I have this method to calculate the standard deviation of an array of NSNumber integers, given a mean. The calculation uses NSDecimals to retain the highest resolution. This is currently demanding many cpu cycles, any help to speed it up while retaining the resolution required is appreciated! Thank you.
-(NSDecimal)standardDeviationOf:(NSMutableArray *)array withMean:(NSDecimal)mean {
if (![array count]) return CPTDecimalFromInt(0);
NSDecimal sumOfSquaredDifferences = CPTDecimalFromInt(0);
for (NSNumber *number in array) {
NSDecimal valueOfNumber = CPTDecimalFromInt([number intValue]);
NSDecimal difference = CPTDecimalSubtract(valueOfNumber, mean);
sumOfSquaredDifferences = CPTDecimalAdd(sumOfSquaredDifferences, CPTDecimalMultiply(difference, difference));
}
return CPTDecimalFromDouble(
sqrt(
CPTDecimalDoubleValue(sumOfSquaredDifferences) / [[NSNumber numberWithInt:[array count]] doubleValue]
)
);
}
An NSDecimal has 38 digits of precision, whereas double has roughly 16 digits of precision. But at the end of your loop, when you convert sumOfSquaredDifferences to double for the sqrt function, all the extra precision you had in the NSDecimal is "lost". You might as well perform the arithmetic of your inner loop using double, which should be much faster than NSDecimal:
double sumOfSquaredDifferences = 0;
double valueOfMean = [mean doubleValue];
for (NSNumber *number in array) {
double valueOfNumber = [number intValue];
double difference = valueOfNumber - valueOfMean;
sumOfSquaredDifferences += difference * difference;
}
return CPTDecimalFromDouble(sqrt(sumOfSquaredDifferences /
double([array count])));

NSNumber decimal to C primitive value?

I want to convert a decimal NSNumber to an int or other form which I can do math with. Here's the annotated code for my project:
NSNumber *Left = [left valueForOutputKey:#"Y"];
This line gets a Quartz Composer Outlet, usually with a value around 0.512.
Basically, I want to multiply this by 10, and then do some operations like greater than and less than to see which range it is in.
Since it looks like you're dealing with a fractional component, you want to convert it to a float or a double to perform your operations, depending on how big you expect that value to be. A float should be fine unless you're dealing with ridiculously large or precise numbers. Here's how it would look, for example:
float lValue = [[left valueForOutputKey:#"Y"] floatValue];
lValue *= 10;
if (lValue < 10) {
// do whatever
}
else if (lValue > 50) {
// do whatever
}
Then to store the value back in your outlet or whatever, you pack it back into a NSNumber:
NSNumber *newValue = [NSNumber numberWithFloat:lValue];
[left setValue:newValue forKey:#"Y"];
You may have to convert newValue into a string to display it in a control, just use [newValue stringValue] to do that.
Use one of the methods of NSNumber:
int leftInt = [Left intValue];
float leftFloat = [Left floatValue];
double leftDouble = [Left doubleValue];