Подтвердить что ты не робот

С# Math.Ceiling ошибка или нет?

Я не знаю, почему Ceiling ведет себя как на рисунке ниже

Почему processFee!= Настройки .PaymentProcessingFeeInPercentage * prizesSum?

Просмотр изображения в полном размере

alt text http://img514.imageshack.us/img514/3950/csharpceilingproblem.png

4b9b3361

Ответ 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 ) );