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