Double division loses decimal places in objective-c - 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);
}

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;
}

Objective-C: Flooring to 3 decimals correctly

I am trying to floor a float value to the third decimal. For example, the value 2.56976 shall be 2.569 not 2.570. I searched and found answers like these:
floor double by decimal place
Such answers are not accurate. For example the code:
double value = (double)((unsigned int)(value * (double)placed)) / (double)placed
can return the value - 1 and this is not correct. The multiplication of value and placed value * (double)placed) could introduce something like: 2100.999999996. When changed to unsigned int, it becomes 2100 which is wrong (the correct value should be 2101). Other answers suffer from the same issue. In Java, you can use BigDecimal which saves all that hassels.
(Note: of course, rounding the 2100.9999 is not an option as it ruins the whole idea of flooring to "3 decimals correctly")
The following code should work:
#include <stdio.h>
#include <math.h>
int main(void) {
double value = 1.23456;
double val3;
val3 = floor(1000.0 * value + 0.0001) * 0.001; // add 0.0001 to "fix" binary representation problem
printf("val3 is %.8f; the error is %f\n", val3, 1.234 - val3);
}
this prints out
val3 is 1.23400000; the error is 0.000000
If there are any residual errors, it comes about from the fact that floating point numbers cannot necessarily be represented exactly - the idea behind BigDecimal and things like that is to work around that in a very explicit way (for example by representing a number as its digits, rather than a binary representation - it's less efficient, but maintains accuracy)
I had to consider a solution involving NSString and it worked like a charm. Here is the full method:
- (float) getFlooredPrice:(float) passedPrice {
NSString *floatPassedPriceString = [NSString stringWithFormat:#"%f", passedPrice];
NSArray *floatArray = [floatPassedPriceString componentsSeparatedByString:#"."];
NSString *fixedPart = [floatArray objectAtIndex:0];
NSString *decimalPart = #"";
if ([floatArray count] > 1) {
NSString *decimalPartWhole = [floatArray objectAtIndex:1];
if (decimalPartWhole.length > 3) {
decimalPart = [decimalPartWhole substringToIndex:3];
} else {
decimalPart = decimalPartWhole;
}
}
NSString *wholeNumber = [NSString stringWithFormat:#"%#.%#", fixedPart, decimalPart];
return [wholeNumber floatValue];
}
For example, the value 2.56976 shall be 2.569 not 2.570
Solution is has simple as that :
double result = floor(2.56976 * 1000.0) / 1000.0;
I don't know why you search complication... this works perfectly, doesn't need to pass by some unsigned int or other + 0.0001 or whatever.
Important note :
NSLog(#"%.4f", myDouble);
Actually do a round on your variable. So it's improper to believe you can floor with a %.Xf

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

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

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.

Odd behavior with NSUInteger - can't convert to float properly

Here is my situation. Its driving me nuts:
I have an NSMutableArray with a count value of 517. I have a double value that is my multiplier.
double multiplier = 0.1223;
double result = [myArray count] * multiplier; // 63 even (wrong!)
In fact it should be 63.2291. If I go:
double result = [myArray count] * 0.1223; // 63.2291 (right!)
or..
double result = 517 * multiplier; // 63.2291 (right!)
Does this make any sense to anyone?
Addendum:
here is my actual function:
- (double) getValueForPercentage:(double)percVal
{
int adjustedCount = [originalData count] - 1;
double final = percVal * (double)adjustedCount;
return final;
}
I never get any digits beyond the decimal point when I do this. It does however work if I get rid of the "-1", a-la:
- (double) getValueForPercentage:(double)percVal
{
int adjustedCount = [originalData count];
double final = percVal * (double)adjustedCount;
return final;
}
Of course, I need to have the -1.
Second addendum:
Another interesting thing I noted was, if I pass a hard-coded number to this function it works fine, but if I pass the double value that I need to use, it fails:
int pointCount = [srcData getDayCount];
for (int i = 0; i < pointCount; i++) {
double progress = (double)i/(double)(pointCount - 1);
double satv = [srcData getValueForPercentage:progress];
// satv is always a number without any digits beyond the decimal
}
Well, when I started to have these issues i looked around a bit and found no reason or explanation.
What I do now is make everything become an NSNumber and then call doubleValue on it. This should yield the results you're looking for:
NSNumber * pointCount = [NSNumber numberWithUnsignedInt: [srcData getDayCount]];
for (NSInteger i = 0; i < [pointCount intValue]; i++) {
NSNumber * count = [ NSNumber numberWithInt: i ];
double progress = [count doubleValue]/[pointCount doubleValue] - 1.0;
double satv = [srcData getValueForPercentage:progress];
// satv is always a number without any digits beyond the decimal
}
Hope it helps.