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с или floats, если вы сделаете предположения о том, насколько большими будут ваши вычисления. то есть:

double processingFee = Math.Ceiling( Math.Round( 
    Settings.PaymentProcessingFeeInPercentage * prizesSum, 2 ) );
Другие вопросы по тегам