С# Math.Ceiling ошибка или нет?
Я не знаю, почему Ceiling ведет себя как на рисунке ниже
Почему processFee!= Настройки .PaymentProcessingFeeInPercentage * prizesSum?
Просмотр изображения в полном размере
alt text http://img514.imageshack.us/img514/3950/csharpceilingproblem.png
Ответы
Ответ 1
Ваш процент фактически не равен 0,05. Это значение, близкое к 0,05... и, вероятно, чуть более 0,05. Таким образом, когда он умножается на 2600, вы получаете значение чуть более 130.0... которое затем "потолочно" до 131.0.
Используя небольшой инструмент, который я написал некоторое время назад (доступный из эта страница о бинарных типах с плавающей запятой .NET), он выглядит как фактический float
значение, самое близкое к 0,05, составляет 0,0500000007450580596923828125. Для двухлокальных, это 0.05000000000000000277555756156289135105907917022705078125.
Мораль истории: не используйте float
для такого рода вещей - используйте decimal
. Или, если вы просто пытаетесь представить процент, если это действительно так, чтобы быть точным до одного процента, используйте целочисленное значение 0-100.
Ответ 2
Это результат представления чисел с плавающей запятой. См. википедию. Вероятно, 0.05 имеет бесконечное представление base 2 как двойное, поэтому значение Math.Ceiling на самом деле может быть немного больше 130.
Ответ 3
Вы видите неточность точки с плавающей точкой.
Фактическое представление base-2 0.05
немного больше, чем 0.05
, поэтому продукт немного меньше, чем 130.0
.
Поэтому Math.Ceiling
округляется.
Измените свои float
и double
на decimal
.
Ответ 4
Это связано с тем, что формат внутренней памяти для числа с плавающей запятой является по сути неточным, когда число представлено десятичным. Есть много и много вопросов об этом в Stack Overflow.
Число, которое вы возвращаете, вероятно, что-то вроде 130.000000000000001, поскольку числа в вашем расчете не могут быть представлены точно как двоичный номер с плавающей запятой.
Ответ 5
IMHO, это, вероятно, что-то связано с точностью с плавающей запятой. Другими словами, 2600 × 0,05 дает 130,0000... 001, а не 130.
Что делать, если сначала попытаться округлить результат, чем вызвать Math.Ceiling
?
Ответ 6
В моем компиляторе, когда я просматриваю значение умножения, он говорит 130.00000193715096, поэтому результат math.ceiling в порядке. Проблема заключается в ограниченной точности типа данных float.
Попробуйте вместо этого использовать "double", если это возможно.
Ответ 7
Если вы используете числа с плавающей запятой в крупной банковской операции, не позволяйте мне плавать деньги в вашем банке. Используйте десятичные числа или целые числа наименьшего общего знаменателя, т.е. Центы.
Однако вы можете использовать Math.Round
, чтобы помочь вам использовать double
или float
s, если вы делаете предположения о том, насколько велики ваши расчеты. то есть:.
double processingFee = Math.Ceiling( Math.Round(
Settings.PaymentProcessingFeeInPercentage * prizesSum, 2 ) );