Please note that your formula is incorrect, as it skips the +0.5 required to round to the nearest.
So, I will proceed from this corrected formula:
(unsigned long long)( ((double)partialSize)/((double)totalSize) * 100.0 + 0.5);
As I mentioned in the comments, the direct method, although simple, does not guarantee proper rounding of the results. So your intuition is right in the sense that it is not bulletproof.
In the vast majority of cases, it will still be correct, but there will be a small set of borderline cases when it will be incorrectly rounded. Regardless of whether it is up to you. But the direct method is usually sufficient for most purposes.
Why this may be unsuccessful:
There are 4 rounding levels. (fixed from 2, which I mentioned in the comments)
- Throws 64-bit โ 53-bit
- Separation
- Multiply by 100.
- The final.
Whenever you have multiple sources of rounding, you suffer from the usual sources of floating point errors.
Examples of counters:
Although this is rare, I will give a few examples where a straightforward formula will give an incorrectly rounded result:
850536266682995018 / 3335436339933313800 // Correct: 25% Formula: 26% 3552239702028979196 / 10006309019799941400 // Correct: 35% Formula: 36% 1680850982666015624 / 2384185791015625000 // Correct: 70% Formula: 71%
Decision:
I canโt think of a pure 100% bulletproof solution other than using arbitrary precision arithmetic .
But in the end, do you really need it to always be perfectly rounded?
EDIT:
For smaller numbers, here is a very simple solution, which is rounded by 0.5 :
return (x * 100 + y/2) / y;
This will work until x * 100 + y/2 overflows.
@ Daniel Fisher's answer has a more complete solution for other rounding actions. Although it should not be too difficult to change it to get along smoothly.