При закрытии подписчики были переданы в рассылку "Тайны создания и продвижения сайтов в Интернете" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
Информационный Канал Subscribe.Ru |
Здравствуйте, уважаемые подписчики! Для тех, кто только подписался, хочу сказать что эта рассылка (как следует из названия) о профессиональном программировании на .NET и C#. Я рассказываю, как правильно использовать средства .NET и решать поставленные задачи. Также, рассматриваются сопутствующие вопросы: методологии разработки, инструменты разработчика, сертификация специалистов, поиск работы и подготовка к собеседованию, логические задачи. Более подробно о тематике рассылки вы можете узнать, прочитав первый выпуск (в архиве).
Как Вы думаете, какой результат получится в результате выполнения этого кода:
Console.WriteLine(Math.Round(3.5));
Console.WriteLine(Math.Round(4.5));
Если Вы думаете, что получится 4 и 5, то ошибаетесь. В обоих случаях результатом будет 4. Тот же самый результат Вы получите и в Visual Basic 6.0. В .NET статический метод Round() класса Math округляет половину к ближайшему четному. В школе же нас учили, что половина всегда округляется в большую сторону. Поэтому многие (и я в том числе) очень удивляются, узнав о таком "неправильном" округлении. Часто незнание этого факта может привести к неправильным расчетам, если алгоритмы преполагают "обычное" округление.
Что же это такое? Очередной баг Microsoft? Вовсе нет! Просто существует несколько способов округления.
Простейший случай - когда цифры после заданной точности просто отбрасываются (округляем до целого):
3.9 округляется до 3
-3.9 округляется до -3
Это, так называемое, симметричное округление, когда число округляется только
по абсолютной величине, без учета знака.
В .NET симметричное округление в меньшую сторону производится простым привидением
к целому:
Console.WriteLine((int)3.9); // 3
Console.WriteLine((int)-3.9); // 3
С учетом знака -3.9 округляется до -4. Метод Floor() класса Math производит несимметричное округление:
Console.WriteLine(Math.Floor(3.9)); // 3
Console.WriteLine(Math.Floor(-3.9)); // -4
Несимметричное округление до ближайшего большего или равного целого выполняет метод Ceiling() класса Math:
Console.WriteLine(Math.Ceiling(3.1));
Console.WriteLine(Math.Ceiling(-3.1));
Заметьте, что Floor() и Ceiling() округляют всегда до целого.
Но чаще всего приходится округлять не в меньшую или большую сторону, а к ближайшему числу (с заданной точностью). В этом случае погрешность будет меньшей. Главный вопрос, который возникает в этом случае - как округлять половину?
Это привычное нам округление, когда половина округляется в большую сторону:
3.5 округляется до 4
4.5 округляется до 5
Как и в предыдущих случаях, можно рассматривать симметричное и несимметричное арифметическое округление.
Если складывать много чисел, округляя .5 всегда в большую сторону, то возникнет перекос, который будет тем больше, чем больше чисел мы складываем. Банковское округление позволяет минимизировать этот перекос. В этом случае половина округляется к ближайшему четному. Метод Round() класса Math реализует именно банковское округление. В качестве параметра он принимает округляемое значение и, возможно, точность, до которой необходимо выполнить округление. Если точность не указана, то округление выполняется до целого.
Понятно, что если преобладают четные или нечетные числа, то даже банковское округление создаст перекос. В этом случае можно применить, так называемое, случайное округление, когда половина округляется в большую или меньшую сторону по случайному закону. Однако, суммирование одних и тех же данных при таком округлении может давать разные результаты.
В этом случае .5 округляется попеременно то в большую сторону, то в меньшую.
Что же делать, если надо произвести арифметическое округление? К сожалению, Microsoft не реализовала соответствующий метод в классе Math (так же, как и для случайного и попеременного округлений). Но выход, конечно, есть.
Во первых, это класс SqlDecimal из пространства имен System.Data.SqlTypes со статическим методом Round:
Console.WriteLine(SqlDecimal.Round(3.5m, 0)); // 4
Console.WriteLine(SqlDecimal.Round(4.5m, 0)); // 5
Это отличие связано с тем, что Round из Sql Server выполняет математическое округление.
Во вторых, можно самостоятельно написать метод для математического (и не только) округления. Например, вот реализация на C# для симметричного арифметического округления.
public static double Round(double value, int digits)
{
double scale = Math.Pow(10.0, digits);
double round = Math.Floor(Math.Abs(value) * scale + 0.5);
return (Math.Sign(value) * round / scale);
}
Я предпочитаю поместить несколько перегрузок приведенной реализации (для float, double, decimal) в некоторый служебный класс и использовать их вместо Math.Round() (мне пока не приходилось реализовывать задачи, требующие банковского округления).
Реализацию описанных алгоритмов округления на Visual Basic 6.0 можно найти
здесь: http://support.microsoft.com/default.aspx?scid=kb;en-us;196652
Сначала, ответы на задачи из предыдущего выпуска. Т.к. их текст немного длинноват, я не буду повторять их условия здесь, как я делал это раньше. Те, кто не читал предыдущий выпуск, могут ознакомиться с условием задачи, прочитав его в архиве рассылки. Напомню лишь, что речь идет о задачах из книги головоломок "Принцесса или тигр?".
Ответы:
1. Нам известно, что надпись на одной из табличек истинна, а на другой ложна. Возможно ли, чтобы утверждение, написанное на первой табличке, было истинным, а на второй - ложным? Конечно же, нет, поскольку, если первая табличка говорит нам правду, то тогда надпись на второй табличке также должна быть верной, то есть если принцесса находится в комнате I, а тигр сидит в комнате II, то это заведомо означает, что в одной из комнат находится принцесса, а в другой тигр. Но поскольку не может оказаться так, чтобы первое утверждение было истинным, а второе ложным, то ясно, что истинной должна быть вторая надпись, а ложной - первая. Далее, поскольку второе утверждение является истинным, то это означает, что в одной из комнат действительно находится принцесса, а в другой сидит тигр. Теперь, поскольку первая надпись лжет, то, значит, тигр должен сидеть в комнате I, a принцесса в комнате II. Следовательно, узник должен выбрать вторую комнату.
2. Если надпись II ложна, то принцесса находится в комнате I. Значит, принцесса присутствует хоть в одной из комнат, так что утверждение на табличке I истинно. Поэтому невозможно, чтобы сразу две надписи оказались ложными. Это означает, что оба приведенных утверждения истинны (ведь, согласно условию, они одновременно либо оба истинны, либо оба ложны). Таким образом, тигр сидит в комнате I, а принцесса находится в комнате II; значит, узнику опять следует выбрать вторую комнату.
3. В тот раз король, по всей видимости, пребывал в весьма благодушном настроении,
поскольку в обеих комнатах оказалось по принцессе. Убедимся в этом следующим
образом.
Надпись на табличке I означает, что хотя бы одно из двух утверждений верно:
в комнате I сидит тигр; в комнате II находится принцесса. (При этом не исключено,
что обе возможности осуществляются одновременно.)
Далее, если утверждение на табличке II ложно, то, значит, тигр сидит в комнате
I, а тогда первая табличка говорит правду (поскольку выполняется первое из приведенных
на ней утверждений). Однако из условий задачи мы знаем, что не может случиться
так, чтобы надпись на одной из табличек оказалась истинной, а на другой ложной.
Следовательно, поскольку утверждение II истинно, то надписи на обеих табличках
одновременно должны быть истинными. Теперь, поскольку на табличке II истинное
утверждение, то в комнате I находится принцесса. Это означает также, что первый
из вариантов на табличке I невозможен, но поскольку по меньшей мере один из
этих вариантов обязательно выполняется, то это должен быть именно второй вариант.
Таким образом, в комнате II также находится принцесса.
Сегодня я продолжаю историю о тиграх и принцессах:
День второй
- Вчера мы сваляли дурака, - сказал король своему министру. -
Все трое выкрутились! Ладно, сегодня у нас еще пятеро, и я придумаю для них
кое-что похлеще.
- Блестящая идея, ваше величество! - поддержал
министр.
И во всех испытаниях этого дня относительно левой
комнаты (комната I) король говорил вот что:
- Если в этой комнате находится
принцесса, то утверждение на табличке истинно, если же тигр, то
ложно.
В правой же комнате (комната II) все было наоборот:
утверждение на табличке ложно, если в комнате находится принцесса, и истинно,
если в комнате сидит тигр. Ну и опять же, вполне может статься, что в обеих
комнатах находятся принцессы или в них сидит по тигру, либо, наконец, в одной
комнате пребывает принцесса, а в другой - тигр.
4. Четвертое испытание.
Объявив эти правила следующему узнику, король указал на две новые таблички:
I В обеих комнатах находятся принцессы |
II В обеих комнатах находятся принцессы. Какую из комнат следует выбрать на этот раз узнику? |
5. Испытание пятое.
Условия те же, а таблички вот какие:
I По крайней мере в одной из комнат находится принцесса |
II Принцесса - в другой комнате |
6. Испытание шестое.
Этой задачкой король особенно гордился, равно как и следующей за ней.
I Что ни выберешь - все едино |
II Принцесса - в другой комнате |
Как должен поступить узник?
7. Испытание седьмое.
Теперь на табличках было написано:
I Что выбрать - большая разница |
II Лучше выбрать другую комнату |
8. Испытание восьмое.
- На дверях же нет никаких табличек! - воскликнул
следующий узник.
- Совершенно верно, - заметил король. - Их только что
изготовили и не успели повесить.
- Так как же мне выбирать? - спросил
узник.
- А вот эти таблички, - ответил король.
В этой комнате сидит тигр |
В обеих комнатах сидят тигры |
- Очень мило, - обеспокоился узник,а какую
куда?
Король призадумался.
- А тебе это знать вовсе не
обязательно, - сказал он наконец. - Задача решается и так. Только не забудь,
конечно, - добавил он, - что если принцесса в левой комнате, то утверждение на
табличке у этой двери будет истинным, а если там тигр, то ложным. Для правой же
комнаты - все наоборот.
Каково решение задачи в этом
случае?
На этом все. Желаю приятного программирования.
Subscribe.Ru
Поддержка подписчиков Другие рассылки этой тематики Другие рассылки этого автора |
Подписан адрес:
Код этой рассылки: comp.soft.prog.gurudotnet |
Отписаться
Вспомнить пароль |
В избранное | ||