I do not know why Ceiling behave like in the below image
Why is processingFee != Settings.PaymentProcessingFeeInPercentage * prizesSum ?
I do not know why Ceiling behave like in the below image
Why is processingFee != Settings.PaymentProcessingFeeInPercentage * prizesSum ?
This is a result of the floating point representation of the numbers involved. See the wikipedia. Probably 0.05 has an infinite base 2 representation as a double, so the value Math.Ceiling actually sees might be slightly larger than 130.
You're seeing floatng-point imprecision.
The actual base-2 representation of 0.05
is a tiny bit more than 0.05
, so the product is a tiny bit more than 130.0
.
Therefore, Math.Ceiling
is rounding up.
Change your float
s and double
s to decimal
.
This is due to the internal storage format for a floating point number being inherently inexact when the number is represented in decimal. There are many, many questions on this on Stack Overflow.
The number you are returning is probably something like 130.000000000000001 since the numbers in your calculation can't be represented exactly as a binary floating point number.
IMHO, it's probably something to do with floating point precision. In other words, 2600 × 0.05 gives 130.0000...001 rather than 130.
What if you try to round the result first, than call Math.Ceiling
?
Your percentage isn't actually 0.05. It's a value close to 0.05... and probably a little bit more than 0.05. Thus when it's multiplied by 2600, you're getting a value just over 130.0... which is then being "ceilinged" to 131.0.
Using a little tool I wrote a while ago (available from this page about .NET binary floating point types) it looks like the actual float
value closest to 0.05 is 0.0500000007450580596923828125. For doubles, it's 0.05000000000000000277555756156289135105907917022705078125.
Moral of the story: don't use float
for this sort of thing - use decimal
. Or if you're just trying to represent a percentage, if it's okay to actually be only accurate to one percent, use an integer value 0-100.
In my compiler, when i lookup the multiply value, it says 130.00000193715096, so the math.ceiling result is ok. The problem is the limited precision of the float data type.
Try using 'double' instead, if it is possible.
If you use floating point numbers in a large banking operation, don't let me float my money in your bank. Use decimals, or integers of the least common denominator, i.e. cents.
You could however, use a Math.Round
, to help you use double
s or float
s, if you make assumptions about how large your calculations will get. i.e.:
double processingFee = Math.Ceiling( Math.Round(
Settings.PaymentProcessingFeeInPercentage * prizesSum, 2 ) );