Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accurate percentage in C++

Tags:

c++

Given 2 numbers, where A <= B say for example A = 9 and B = 10, I am trying to get the percentage of how smaller A is compared to B. I need to have the percentage as an int e.g. if the result is 10.00% The int should be 1000.

Here is my code:

int A = 9;
int B = 10;

int percentage = (((1 - (double)A/B) / 0.01)) * 100;

My code returns 999 instead of 1000. Some precision related to the usage of double is lost.

Is there a way to avoid losing precision in my case?

like image 332
DragonSlayer Avatar asked Jul 19 '14 05:07

DragonSlayer


2 Answers

Seems the formula you're looking for is

int result = 10000 - (A*10000+B/2)/B;

The idea is to do all computations in integers and delaying division.

To do the rounding half of the denominator is added before performing the division (otherwise you get truncation in the division and thus upper rounding because of 100%-x)

For example with A=9 and B=11 the percentage is 18.18181818... and rounding 18.18, the computation without the rounding would give 1819 instead of the expected result 1818.

Note that the computation is done all in integers so there is a risk of overflow for large values of A and B. For example if int is 32 bit then A can be up to around 200000 before risking an overflow when computing A*10000.

Using A*10000LL instead of A*10000 in the formula will trade in some speed to raise the limit to a much bigger value.

like image 68
6502 Avatar answered Oct 22 '22 04:10

6502


Offcourse there may be precision loss in floating point number. Either you should use fixed point number as @6502 answered or add a bias to the result to get the intended answer. You should better do

assert(B != 0);
int percentage = ((A<0) == (B<0) ? 0.5 : -0.5) + (((1 - (double)A/B) / 0.01)) * 100;

Because of precision loss, result of (((1 - (double)A/B) / 0.01)) * 100 may be slightly less or more than intended. If you add extra 0.5, it is guaranteed to be sligthly more than intended. Now when you cast this value to an integer, you get intended answer. (floor or ceil value depending whether the fractional part of the result of equation was above or below 0.5)

like image 45
Mohit Jain Avatar answered Oct 22 '22 04:10

Mohit Jain