Double Over Precision - objective-c

Apologies if this has been asked already - not sure what to search for.
Simple bit of code:
double x = 4505;
double y = 1000;
double z = 1000000;
double result = (x * y) / z;
Answer should be 4.505; but I get:
result = 4.5049999999999999
The values of x, y and z could be anything, and sometimes I need that level of precision in the result but I can't see why this is happening.
The Question is how to I remove the rounding error so that I can re-run further calculations on the decimal value without getting erroneous results and at the same time maintain high level of precision for numbers that need it.

It's simply a Floating Point Rounding Error. Also there is this.
If you want result rounded to 3 decimal places, then use:
result = floor(result * 1000.0) / 1000.0;
or just during presentation:
NSLog(#"result = %.3f", result);

Related

Gps distance between two points

I am developing a Meter app (in android). I am calculating distance between two points by formula (in back ground)
double calculateDistancs(double lat1, double long1, double lat2,
double long2) {
double earthRadius = 6371000; // meters
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(long2 - long1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLng / 2)
* Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
float dist = (float) (earthRadius * c);
return dist;
}
I am not getting same and accurate distance between my home to metro station .
Provide other approach if available in android.
So second option is use google api for getting rout distance bn two latlong but in this case it will hit api many times.I want t know which approach is best.
I am getting different latlong at same place, may some one please make me understand for this.
The problem most probably is not caused by the function you posted.
Probably you are summing up jumping gps locations.
Just summing up the distance from one location to the other is not sufficient, especially at low speeds, like walking speed.
However there are weak points in the formula:
float dist = (float) (earthRadius * c);
You are always using double, and then downgrade to the lower precision float, but return the double. This is makes no sense.
Fix that with:
double dist = earthRadius * c;

Objective-C: floorf( ) returns wrong value

Here is the code:
float passedPrice = 2.953;
float placed = 1000.0; //3 decimals
NSLog("%f", placed); // Gives 2953;
float withNoFractions = floorf(passedPrice * placed);
The value stored in withNoFractions is 2952! It shall be 2953. What is really strange is that it works some time.
Many decimal floating point fractions cannot be represented as exact fractions in binary, so they have to be approximated. 2.953 is being approximated as something like 2.95299999. When you multiply by 1000, the result is 2952.99999, and when you get the floor of this, it's 2952.
To solve this, you can either use round() instead of ffloorf(), or you can add 0.5 before calling ffloorf():
float withNoFractions = floorf(passedPrice * placed + 0.5);

Round Numbers Evenly

How do I round numbers up or down depending on the value in object C.. for example.
Lets say the number is 143 - I would want to round down to 140
but if the number is 146 - I would want to round up to 150
any suggestions?
Assuming 145 should round to 150 (that's the standard in science and technology), the formula is:
x_rounded = ((x + 5)/10)*10;
More generally, when rounding to the nearest n, it's
x_rounded = ((x + n/2)/n)*n;
It comes from the fact that integer division always rounds down.
For negative numbers, it's slightly more tricky.
EDIT: also assuming it's all integers. With floats/doubles, better use the C math library, as division works differently. Like this:
#include <math.h>
x_rounded = floor((x+5)/10) * 10;
Round value x to precision p, where 0 < p < infinite. (f.ex. p=0.25, 0.5, 1, 2, 3, 10,…)
float RoundTo(float x, float p)
{
float y = 1/p;
return int((x+(1/(y+y)))*y)/y;
}
float RoundUp(float x, float p)
{
float y = 1/p;
return int((x+(1/y))*y)/y;
}
float RoundDown(float x, float p)
{
float y = 1/p;
return int(x*y)/y;
}
The lround function will round a float to the nearest integer. You can fairly easily get it to round to a multiple of 10 by dividing the number by 10, rounding, then multiplying by 10.
in code:
10 * lround(x / 10.0);
I would think the simplest solution would be to include math.h and use the round() function.
For rounding floats to nearby integer values, check out the C functions floorf(), ceilf() and roundf().
For rounding integers to (say), the closest multiple of ten, the formula given by Seva should work...
This will definitely solve your worries.
- (int) roundToNearest5:(int) value
{
return (value+(5-(value%5));
}

calculations in Objective-C

Could anyone explain to me why this keeps returning 0 when it should return a value of 42? it works on paper so i know the math is right I'm just wondering as to why it isn't translating across?
int a = 60;
int b = 120;
int c = 85;
int progress;
progress = ((c-a)/(b-a))*100;
NSLog(#"Progess = %d %%",progress);
It's because your math is all using integers.
In particular, your inner expression is calculating 25 / 60, which in integer math is zero.
In effect you have over-parenthesised your expression, and the resulting order of evaluation is causing integer rounding problems.
It would have worked fine if you had just written the formula so:
progress = 100 * (c - a) / (b - a);
because the 100 * (c - a) would first evaluate to 2500, and would then be divided by 60 to give 41.
Alternative, if any one (or more) of your variables a, b, or c were a float (or cast thereto) the equation would also work.
That's because an expression in which either operand is a float will cause the other (integer) operand to be promoted to a float, too, at which point the result of the expression will also be a float.
c - a will give you 25
b - a will give you 60
Since a, b, and c are all integers, meaning they can't be decimals. Therefore, by doing (c-a)/(b-a), you will get 0, instead of 0.41666666 because in integer division, anything after the decimal point will get cut off, leaving the number before the decimal point.
To make it work the way you wanted it to, you should try casting (c-a) and (b-a) to either double or float:
progress = ((float)(c-a) / (float)(b-a)) * 100;
or
progress = ((double)(c-a) / (double)(b-a)) * 100;
a,b and c are ints. When you calculate ((c-a)/(b-a)), the result is also an int; the real value is a decimal (0.42), but an int can't take a decimal number, so it rounds to 0, which is multiplied by 100 to get 0.
Because (c - a) / (b - a) is computed using integer math.
To fix, cast to a float before dividing:
progress = (int)((((float)(c - a)) / ((float)(b - a))) * 100);

Calculate download percentage in Objective C

I got stuck with a problem that looked pretty easy but i cant make it work.
I'm making a simple download manager for OSX using objective C. As part of the app im trying to calculate the percentage of the current download. im trying to use this code but it wont work for me
long double precent = (bytesDownloaded/downloadSize) * 100;
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
The bytesDownloaded and downloadSize are long long.
Can someone please advise,
thanks
To get the correct answer, you must cast the values to long double.
long double precent = ((long double)bytesDownloaded/(long double)downloadSize);
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
Is the denominator an int, change it to a floating point? Try:
long double precent = (bytesDownloaded/(downloadSize * 1.0));
NSLog(#"precnt %Lf",precent);
NSLog(#"Downloadedbyret: %lld", bytesDownloaded);
To get % complete you need to multiply by 100.
long double precent = (bytesDownloaded/downloadSize) * 100.0;
if the values bytesDownloaded and downloadSize are int you will need to cast them to a floating point value.
Or if integers multiple the dividend by 100 first:
(bytesDownloaded * 100) / downloadSize;