Ветцштайн Петр

Блог программиста

Что не так с Math.Ceiling()?

 
 
Голосов:   160

 

Я всегда любил C# очень удобный, нативный и в целом очень красивый язык программирования, но так вышло что я ушел в сторону php, JavaScript и прочих веб технологий. К C# я не подходил очень давно, но вот недавно пришлось разбираться в коде давно написанной программы.

Это программа для продажи ювелирных изделий, реально крутится в 5 магазинах. Всех все устраивало, и если б не один педантичный кассир, мы бы никогда не узнали всю глубину падения Microsoft.

Оказывается программа при введении скидки в редких случаях добавляла лишний рубль. К примеру изделие ценой в 660 при скидке в 45% должно стоить 363, а на картинке видно что программа выдает 364 рубля.



Оказалось что лишний рубль добавляется только тогда, когда после скидки получается целое число, но это как говорится необходимое но недостаточное условие. )))


Проблема в стандартном методе Math.Ceiling. Давайте разберем код:


Чтобы получить цену со скидкой в 45% я умножаю 0.55 на цену. И получаем правильный результат 363!

В ювелирном магазине все цены без копеек, только в рублях, поэтому надо применять округление. Округление должно быть в большую сторону, поэтому обычный Math.Round не подойдет. Используем Math.Ceiling и тут начинается мистика. При округлении метод Math.Ceiling прибавил к целому числу единицу, но это происходит не всегда, вот другой пример где Math.Ceiling работает правильно:


Почему так происходит мне так и не удалось разобраться, в документации про это ничего не говорится, и мне так кажется это косяк микрософта. Если я ошибаюсь поправьте меня в коментах.



P.S.

Продолжая тему паранормальных явлений хочу поделится наблюдением странного поведения переменных разного типа при сравнениях. Буду краток, ниже приведен код, почему так у меня нет идей, подскажите в комментариях.


    double a = 0.55 * 660;  // Получается целое число 363
    if ((float)a < a) { /* Выполнится */ }  
  
    double b = 363;
    if ((float)b < b) { /* Не выполнится */ }  

    double c = 0.55 * 660;  // Получается целое число 363
    if (c < c) { /* Не выполнится */ }


P.P.S.

Кажется я понял в чем проблема, все дело в том что конечные дроби в десятичной системе счисления иногда оказываются бесконечными в двоичной. Как известно компьютер работает в двоичной системе счисления, именно поэтому я решил перевести десятичное число 0,55 в двоичное. Перевел и получил бесконечную дробь. Мне кажется вся магия происходит из-за этой особенности.




7                14.08.2014


Комментарии:


  • sdsd

    https://dl.dropboxusercontent.com/u/41504851/123456.pdf

    20.08.2014 15:51

  • sfsf

    https://dl.dropboxusercontent.com/u/41504851/const.pdf

    21.08.2014 15:13

  • sdf

    https://yadi.sk/i/G8tOuu5waAV4y

    21.08.2014 15:20

  • Дмитрий

    Смешно. А в официальную документацию от Microsoft никак нельзя было посмотреть? http://msdn.microsoft.com/ru-ru/library/zx4t0t48(v=vs.110).aspx

    09.09.2014 14:42

  • 123

    https://dl.dropboxusercontent.com/u/41504851/%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%B0%D1%82%D0%BE%D1%80%D1%8B%20%D0%B4%D0%BB%D1%8F%20%D0%BE%D1%84%D0%B8%D1%81%D0%B0%20%D0%B8%20%D0%B2%D0%B8%D0%BD%D0%B4%D1%8B.zip

    06.02.2015 17:09

  • jh

    https://dl.dropboxusercontent.com/u/41504851/481516.zip

    06.02.2015 17:10

  • Daikatana

    Ужасный код ) вы не знаете шарп, честно. И ООП похоже тоже. По проблеме, вы бы разобрались с типами данных в .нет, все таки есть спец типы для денежных операций. И наверно паттерны бы не мешало получить.

    23.07.2016 00:29


Введите ник:


Введите e-mail:


Введите комментарий:


Очистить все поля




Самые популярные статьи

В процессе написания очередной программы на C# столкнулся с проблемой создания ZIP-архива. Нужно было упаковать сформированный файл отчета в архив для дальнейшей отправки по почте. Сейчас попытаюсь как можно проще описать процесс создания архива с помощью простой подключаемой библиотеки "SharpZipLib" (Скачать можно с оф.сайта, как в виде скомпилированой библиотеки, так и исходный код). Итак, создаем новое приложение Windows Forms. Кидаем на форму лейбл (label1), текстовое поле (textBox1) и.....

23610  5460 Читать полностью >>>
Сегодняшний пост будет довольно короткий, но при этом раскроет основы работы Skype API. Для работы нам понадобится библиотека Skype4COM. К сожалению в разделе для разработчиков (developer.skype.com) нет нормальной документации для работы с данной библиотекой, так же как и нет примеров кода на C#. Меньше слов, больше дела! Распаковываем архив и регистрируем dll в системе: Пуск => Выполнить => "regsvr32 D:\Skype4COM.dll" где D:\Skype4COM.dll - путь dll. В студии создаем новый проект и объявляе.....

1070  1711 Читать полностью >>>
Я всегда любил C# очень удобный, нативный и в целом очень красивый язык программирования, но так вышло что я ушел в сторону php, JavaScript и прочих веб технологий. К C# я не подходил очень давно, но вот недавно пришлось разбираться в коде давно написанной программы. Это программа для продажи ювелирных изделий, реально крутится в 5 магазинах. Всех все устраивало, и если б не один педантичный кассир, мы бы никогда не узнали всю глубину падения Microsoft. Оказывается программа при введении с.....

160  7 Читать полностью >>>
Вы задавались вопросом, как написать парсер на C#? Думаю ни для кого не секрет, что парсер это синтаксический анализатор. Рано или поздно все кто занимаются программированием, сталкиваются с необходимостью написания синтаксического анализатора. И-так парсер, который разберем в данной статье предназначен для облегчения SEO оптимизации сайта. Очень удобно было бы знать на какой позиции находится оптимизируемы сайт по тому или иному запросу. Это полезно для анализа уже проделанной SEO оптимизац.....

148  385 Читать полностью >>>
Моей основной ОС является MAC OS. Мне необходимо было установить VirtualBox и установить в ней, в качестве гостевой ОС Ubuntu Server без графической оболочки. Настроить Ubuntu в качестве LAMP сервера и установить Apache, Mysql, phpMyAdmin. Также настроить общую папку между основной и гостевой ОС. Ниже представлена инструкция как это сделать. Скачиваем VirtualBox для MAC OS X Скачиваем Ubuntu Server 64-bit (без графической оболочки) Устанавливаем VirtualBox и Ubuntu. В разделе «Выбор пр.....

100  1 Читать полностью >>>

Архив статей

    Статей нет!
      Статей нет!
        Статей нет!

        Статистика