Я не знаю, почему Потолок ведет себя как в ниже изображения
Почему processingFee! = Настройки. PaymentProcessingFeeInPercentage * prizesSum?
Изображение представления в полном размере
сопроводительный текст http://img514.imageshack.us/img514/3950/csharpceilingproblem.png
Ваш процент не на самом деле 0,05. Это значение , близкое к 0,05 ... и, вероятно, немного больше 0,05. Таким образом, если его умножить на 2600, вы получите значение чуть больше 130,0 ... которое затем будет «потолком» до 131,0.
Используя небольшой инструмент, который я написал недавно (доступен на этой странице о двоичных типах с плавающей запятой .NET), похоже, что фактическое значение float
, наиболее близкое к 0,05, составляет 0,0500000007450580596923828125. Для двойников это 0,05000000000000000277555756156289135105907917022705078125.
Мораль истории: не используйте float
для подобных вещей - используйте десятичное
. Или, если вы просто пытаетесь представить процентное соотношение, если на самом деле может иметь точность только до одного процента, используйте целочисленное значение 0–100.
Если вы используете числа с плавающей запятой в крупной банковской операции, не позволяйте мне размещать мои деньги в вашем банке. Используйте десятичных знаков или целых чисел наименьшего общего знаменателя, т. Е. Центов.
Однако вы можете использовать Math.Round
, чтобы помочь вам использовать double
s или float
s, если вы делаете предположения о том, насколько велики ваши вычисления получите. то есть: [
double processingFee = Math.Ceiling( Math.Round(
Settings.PaymentProcessingFeeInPercentage * prizesSum, 2 ) );
Это результат представления задействованных чисел с плавающей запятой. См. Википедию . Вероятно, 0,05 имеет представление с бесконечной базой 2 как двойное, поэтому значение Math.Ceiling, которое фактически видит Math.Ceiling, может быть немного больше 130.
Вы видите неточность плавающей точки.
Фактическое представление 0,05
по основанию 2 немного больше, чем 0,05
, поэтому произведение немного больше, чем 130,0
.
Следовательно, Math.Ceiling
округляется в большую сторону.
Измените float
s и double
s на десятичное
.
Это связано с тем, что внутренний формат хранения числа с плавающей запятой по своей природе неточен, когда число представлено в десятичном виде. На Stack Overflow есть много-много вопросов по этому поводу.
Число, которое вы возвращаете, вероятно, примерно равно 130.000000000000001, поскольку числа в ваших вычислениях не могут быть представлены точно как двоичное число с плавающей запятой.
IMHO, вероятно, это как-то связано с точностью с плавающей запятой. Другими словами, 2600 × 0,05 дает 130,0000 ... 001, а не 130.
Что, если вы попытаетесь сначала округлить результат, чем вызвать Math.Ceiling
?
В моем компиляторе, когда я ищу значение умножения, оно говорит 130.00000193715096, так что результат math.ceiling в порядке. Проблема заключается в ограниченной точности типа данных float.
Попробуйте использовать вместо него 'double', если это возможно.