Ускорение работы в Internet Explorer 7

24 августа Microsoft выпустил IE7 Release Candidate 1. Исправлены баги, найденные в Beta 3, которой я пользовался уже около 2 месяцев и был очень доволен. Если вы еще не поставили себе IE7 - самое время это сделать. Для ускорения и большего удобства в работе привожу здесь список клавиатурных комбинаций для управления IE7, так как привычное Shift + Left Click открывает ссылку в новом окне (как и раньше, но хочется в новой вкладке (tab), поэтому я первое время пользовался контекстным меню).

Работа с вкладками

  • Открыть ссылку в новой вкладке, оставшись в текущей - Ctrl+Click или средняя кнопка мыши (колесико). Второй вариант особенно удобен
  • Открыть ссылку в новой вкладке, сделав ее активной - Ctrl+Shift+Click
  • Открыть новую вкладку, сделав ее активной - Ctrl+T
  • Переключение между вкладками - Ctrl+Tab / Ctrl+Shift+Tab
  • Закрыть текущую вкладку (если больше нет вкладок, то закрывает окно) - Ctrl+W
  • Открыть URL из адресной строки в новой вкладке, сделав ее активной - Alt+Enter
  • Переключиться на N-ую вкладку - Ctrl+N, где N цифра от 1 до 8
  • Переключиться на последнюю вкладку - Ctrl+9
  • Закрыть все вкладки - Ctrl+Alt+F4
  • Открыть превью вкладок (quick tabs) - Ctrl+Q

Увеличение (zoom)

  • Увеличить на 10% - Ctrl+(+) или Ctrl+колесико мыши вверх
  • Уменьшить на 10% - Ctrl+(-) или Ctrl+колесико мыши вниз
  • Восстановить первоначальный размер (100%) - Ctrl+0

Поиск

  • Перейти в строку поиска на тулбаре - Ctrl+E
  • Выполнить поиск в новой вкладке - Alt+Enter
  • Открыть меню выбора поисковых сервисов - Ctrl+Down Arrow

Закладки, фиды и история

  • Открыть закладки - Ctrl+I
  • Открыть истоию - Ctrl+H
  • Открыть RSS фиды - Ctrl+J

Разное

  • Если нажать и отпустить клавишу Alt, появится привычное меню (эту функцию можно отключить в настройках)
  • Комбинация Shift+колесико мыши вверх/вниз позволяет переходить вперед/назад, но, в отличие от кнопок на панели страницы загружаются из памяти. Эта комбинация может позволить спасти набранный текст на предыдущей форме, сабмит которой не прошел по каким-либо причинам
  • Закрыть неактивную закладку - клик средней кнопкой мыши на заголовке
  • Добавить новые поисковые сервисы можно на странице http://www.paranomad.com/ie7SearchProvider/

Permalink | Комментарии (1) | Post RSSRSS comment feed

Самый задаваемый на собеседованиях вопрос по программированию на .NET

Что любят спрашивать на собеседованиях? Вот перечень самых популярных вопросов:

"Почему вы хотите сменить работу?"
"Почему вы хотите работать в нашей компании?"
"Какую зарплату вы хотите получать?"

К сожалению, на эти вопросы нет однозначного ответа. Вы просто должны перед походом на собеседование подготовить наиболее красивый ответ на эти вопросы и надеяться, что он понравится HR менеджеру. Тогда вы попадете на следующий этап собеседования - собеседование с техническим специалистом. И, почти наверняка, он спросит: "Чем отличается структура от класса в .NET?". Несмотря на очевидную избитость вопроса его очень любят задавать. Вот поэтому я решил разложить этот вопрос по полочкам, чтобы вы, дорогие мои читатели, могли без запинки ответить на этот вопрос.

Для начала хочу уточнить пару моментов.

.NET поддерживает два вида типов: размерный (value) и ссылочный (reference). Переменные размерного типа непосредственно содержат данные, а переменные ссылочного типа содержат ссылку на область памяти, содержащую данные. При этом, память под ссылочные переменные всегда выделяется в куче, а память под размерные, обычно, в стеке. Как известно, в .NET для освобождения неиспользуемой памяти в куче используется сборщик мусора. Особенностью стека является то, что память в нем освобождается автоматически (без каких-либо накладных расходов). Таким образом, уничтожение ссылочных объектов путем сборки мусора менее эффективно, чем размерных.

Другой важный момент - это упаковка (boxing) и распаковка (unboxing). При упаковке размерного типа происходит выделение области памяти в куче и копирование значения размерного типа в эту область. Упакованный размерный тип обладает свойствами ссылочного. Распаковка - обратный процесс, в результате которого упакованный размерный тип копируется на стек. Благодаря упаковке любой размерный тип может интерпретироваться как ссылочный и, как следствие этого, любой размерный тип может использоваться вместо object. Важно понимать, что упаковка и распаковка требуют дополнительных затрат памяти и времени. Поэтому следует избегать этих операций в большом количестве.

Теперь вернемся к нашему вопросу. Отличие структуры от класса в .NET:

  1. Структура является размерным типом, а класс - ссылочным.
  2. Все структурные типы неявно наследуются от System.ValueType, они не бывают абстрактными и всегда неявно запечатаны (sealed)
  3. При присваивании переменных структурного типа, создается копия данных
  4. Объявления полей структуры не могут иметь инициализаторов
  5. Различная интерпретация this для структуры и класса
  6. Структура не может содержать конструктор без параметров
  7. Структура не может содержать деструктор
  8. Для ссылочных типов значение по умолчанию - null
  9. При конвертировании между ссылочным и размерным типами происходит упаковка и распаковка

Не страшно, если вы не сможете вспомнить все различия. Главное помнить и понимать главные:
1 - следствием этого является то, что экземпляр класса создается в куче, а структуры, обычно (но не всегда) на стеке
3 - это должно быть очевидно
4 является следствием 6, т.к. код инициализации полей неявно вставляется во все конструкторы
6 является следствием оптимизации использования структур по скорости
Особенности 8 для структур и 9 рассмотрим ниже более подробно, т.к. именно на них любят акцентировать внимание на собеседовании.

Рассмотрим такой пример:

1. public struct MyStruct
2. {
3.     public int m1;
4.     public string s1;
5. }
6. ...
7. MyStruct ms1;
8. MyStruct ms2 = new MyStruct();
9.  
10. Console.WriteLine(ms1.m1);
11. Console.WriteLine(ms2.m1);
12. ...
13.  

В чем отличие между объявлениями в строках 7 и 8? Некоторые считают, что в первом случае (строка 7) объект создается на стеке, а во втором (строка 8) происходит упаковка и объект создается в куче. На самом деле это не так. В обоих случаях объект создается на стеке. Разница в том, что в строке 7 будет создан неинициализированный объект, а в строке 8 инициализированный. Поля ms2 будут содержать значения по умолчанию (0 для m1 и null для s1), а поля ms1 неопределены. Поэтому в строке 10 возникнет ошибка компиляции.

Теперь рассмотрим нюансы, связанные с упаковкой и распаковкой. Как известно, размерные типы могут наследоваться от интерфейсов (имплиментировать интерфейсы). Часто спрашивают, будет ли производиться упаковка при приведении размерного типа к интерфейсу. Правильный ответ - да, будет, т.к. интерфейс является ссылочным типом.
Рассмотрим пример:

1. int i = 1;
2. Console.WriteLine(i.ToString());
3. Console.WriteLine(((IFormattable)i).ToString());
4. Console.WriteLine("{0}", i);
5.  

Размерный тип int имплиментирует интерфейс IFormattable, содержащий метод ToString(). Так как метод ToString() является частью класса int, а компилятор знает, что это размерный тип и, следовательно, виртуальный метод ToString() не может быть переопределен (т.к. структурный тип является запечатанным), компилятор вставляет непосредственный вызов метода в строку 2 и упаковки не происходит. В строке 3 происходит упаковка, т.к. i приводится к интерфейсу IFormattable. Теперь вы сами можете сказать, что происходит в строке 4: неявное приведение к интерфейсу IFormattable и вызов метода ToString(), что, также, приводит к упаковке.

И еще один момент. Массивы являются ссылочными типами, но могут содержать размерные. Где же будет размещен, например, массив целых чисел? В куче, причем целые числа будут неупакованными.

Для более детального изучения этого материала рекомендую книгу Джефри Рихтера.

Permalink | Комментарии (1) | Post RSSRSS comment feed

Лучшая книга по программированию на .NET

Джеффри Рихтер "Программирование на платформе Microsoft .NET Framework" Джеффри Рихтер "Программирование на платформе Microsoft .NET Framework"

Внимание! Вышло новое издание этой книги, написанное по .NET Framework 2.0 - читать обзор. 

Рекомендую всем, кто еще не читал книгу Джеффри Рихтера "Программирование на платформе Microsoft .NET Framework" (Jeffrey Richter, Applied Microsoft .NET Framework Programming), прочитать ее. Да, она написана по бета-версии 1.0, а на подходе уже третья версия фреймворка, но материал, изложенный в книге, является фундаментальным и, практически, не устарел.

Второе издание (картинка слева) было полностью раскуплено и некоторое время книгу было невозможно найти в продаже. К счастью, в конце 2005 года вышло третье издание (картинка справа). По содержанию оба издания одинаковы.

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

Аннотация

В книге подробно описано внутреннее устройство и функционирование общеязыковой исполняющей среды (CLR) Microsoft .NET Framework. Подробно изложена развитая система типов .NET Framework и разъясняются способы управления типами исполняющей средой. Хотя примеры в книге написаны на С#, представленные в ней концепции относятся ко всем языкам, ориентированным на
работу с .NET Framework. Книга ориентирована на разработчиков любых видов приложений на платформе .NET Framework: Windows Forms, Web Forms. Web-сервисов, консольных приложений, служб и пр. Предполагается знакомство читателя с основными концепциями объектно-ориентированного программирования и знание языков программирования.

Рецензии

«Время, потраченное Джеффри на работу с командой разработчиков .NET Framework, не пропало зря — перед вами замечательная содержательная книга».
Эрик Раддер (старший вице-президент отделения разработки и продвижения платформ, Microsoft)

«Джефф работал непосредственно с ребятами, создававшими CLR, и написал лучшую книгу о ее внутреннем устройстве».
Дэннис Энжелайн (ведущий менеджер программы, Microsoft)

«Весь свой многолетний опыт Windows-программирования Джефф употребил, чтобы объяснить, как работает .NET Framework, почему мы построили ее именно так и как ее наилучшим способом использовать».
Брэд Адамс (ведущий менеджер программы, Microsoft)

«Джефф Рихтер с присущим ему талантом понятно, подробно и точно объяснять сложный материал описывает такие новые области, как язык С#, .NET Framework и общеязыковая исполняющая среда .NET. Эту книгу должен иметь каждый, кто хочет разбираться в этих важнейших новых технологиях».
Джим Миллер (ведущий менеджер программы, Microsoft)

«Это лучшая книга об общеязыковой исполняющей среде. Глава о сборщике мусора CLR просто бесподобна. Джефф не только излагает теорию, но и рассматривает детали, которые должен знать каждый разработчик, имеющий дело с .NET».
Махеш Пракрия (ведущий менеджер программы, Microsoft)

«Эта книга — точное, глубокое и при этом вполне читабельное исследование общеязыковой исполняющей среды. Одна из тех редких книг, в которой автор предвидит вопросы читателя и дает ответ в следующем абзаце. Написано превосходно».
Джим Хогг (менеджер программы, Microsoft)

«Так же, как "Программирование для Windows" стала настольной книгой Win32-программистов, "Программирование на платформе Microsoft .NET Framework" обещает быть тем же для программистов .NET Framework. Она уникальна в своем подходе "снизу вверх" к объяснению концепций .NET Framework. Объясняя читателю низкоуровневые концепции CLR, Джефф дает ему базу, необходимую для создания основательных, защищенных и эффективных приложений».
Стивен Пратшнер (менеджер программы, Microsoft)

«Джефф Рихтер - ЧЕЛОВЕЧИЩЕ!»
Аноним (менеджер программы, Microsoft)

«Меня не волнует, о чем здесь говорится; если Джеффри написал книгу, я лечу ее покупать и ставлю на полку рядом с другими его компьютерными книгами».
Арлен Рихтер (мама Джеффа)

«Это единственная книга по .NET Framework, которую я когда-либо читала».
Кристин Трэйс (жена Джеффа)

«Мяу!»
Макс (кот Джеффа)

«Если мне суждено написать единственную книгу по .NET Framework, то это именно она».
Джеффри Рихтер (собственной персоной)

Содержание (названия глав)

ЧАСТЬ I
ОСНОВЫ MICROSOFT .NET FRAMEWORK
Глава 1 Архитектура платформы разработки .NET Framework
Глава 2 Компоновка, упаковка, развертывание
и администрирование приложений и типов
Глава 3 Совместно используемые сборки

ЧАСТЬ II
РАБОТАЕМ С ТИПАМИ И ОБЩЕЯЗЫКОВОЙ
ИСПОЛНЯЮЩЕЙ СРЕДОЙ
Глава 4 Основы типов
Глава 5 Элементарные, ссылочные и размерные типы
Глава 6 Общие операции над объектами

ЧАСТЬ III
ПРОЕКТИРОВАНИЕ ТИПОВ
Глава 7 Члены типов и доступ к ним
Глава 8 Константы и поля
Глава 9 Методы
Глава 10 Свойства
Глава 11 События

ЧАСТЬ IV
ВАЖНЕЙШИЕ ТИПЫ
Глава 12 Обработка текста
Глава 13 Перечислимые типы и битовые флаги
Глава 14 Массивы
Глава 15 Интерфейсы
Глава 16 Специализированные атрибуты
Глава 17 Делегаты

ЧАСТЬ V
УПРАВЛЕНИЕ ТИПАМИ
Глава 18 Исключения
Глава 19 Автоматическое управление памятью (сбор мусора)
Глава 20 Хостинг CLR, домены приложения и отражение

Permalink | Комментарии (2) | Post RSSRSS comment feed

Логические тесты на собеседованиях

В предыдущей версии блога я уже писал про прикольный логический тест.

Сегодня хочу продолжить эту тему, т.к. вчера знакомый прислал аналогичный тест, предлагавшийся на каком-то собеседовании (ему, в свою очередь, прислал другой знакомый, так что повествование от N-го лица):

Сегодня знакомый был на собеседовании в одной уважаемой (и уважающей себя) компании.
Получил на руки вот такой вот тест на логическое мышление, надо было ответить на 12 вопросов.
Я так понял, главная идея теста проверить человека на стрессоустойчивость, потому что знакомому очень хотелось встать, порвать листочки, дать в лицо hr-щику, поклониться и уйти. Я сам ответил верно на все вопросы, но меня, скорее всего спасло то, что, среди прочего, я по диплому имею право преподавать логику в учебных заведениях.
Мне объяснили так, если человек отвечает правильно на все 12 вопросов - это шоколад, а не сотрудник.
Меньше 6 - у этого человека вообще туго с логикой.

Внимание:

Тест на логическое мышление. Используйте только ту информацию, которая имеется в тексте вопроса, не полагайтесь на свой жизненный опыт.

1. Некоторые улитки являются горами. Все горы любят кошек.
Значит, все улитки любят кошек.
а) правильно
б) неправильно

2. Все крокодилы умеют летать. Все великаны являются крокодилами.
Значит, все великаны могут летать.
а) правильно
б) неправильно

3. Некоторые головки капусты - паровозы. Некоторые паровозы играют на рояле.
Значит, некоторые головки капусты играют на рояле.
a) правильно
б) неправильно

4. Две поляны никогда не похожи одна на другую. Сосны и ели выглядят совершенно одинаково.
Значит, сосны и ели не являются двумя полянами.
а) правильно
б) неправильно

5. Никто из людей не может стать президентом, если у него красный нос. У всех людей нос красный.
Значит, никто из людей не может стать президентом.
а) правильно
б) неправильно

6. Все вороны собирают картины. Некоторые собиратели картин сидят в птичьей клетке.
Значит, некоторые вороны сидят в птичьей клетке.
a) правильно
б) неправильно

7. Только плохие люди обманывают или крадут. Катя - хорошая.
а) Катя обманывает
б) Катя крадет
в) Катя не крадет
г) Катя обманывает и крадет
д) ни одно из вышеперечисленных

8. Все воробьи не умеют летать. У всех воробьев есть ноги.
а) без ног воробьи не могут летать
б) некоторые воробьи не имеют ног
в) все воробьи, у которых есть ноги, не могут летать
г) воробьи не могут летать, потому что у них есть ноги
д) воробьи не могут летать и у них нет ног
е) ни одно из вышеперечисленных

9. Некоторые люди - европейцы. Европейцы имеют три ноги.
а) люди с двумя ногами не являются европейцами
б) европейцы, которые являются людьми, иногда имеют три ноги
в) европейцы с двумя ногами иногда являются людьми
г)Людей не европейцев, с тремя ногами не бывает
д)Люди имеют три ноги потому что они европейцы
е)ни одно из вышеперечисленных

10. Цветы - это зеленые звери. Цветы пьют водку.
а) все зеленые звери пьют водку
б) все зеленые звери являются цветами
в) некоторые зеленые звери пьют водку
г) Зеленые звери не пьют водку
д) зеленые звери не являются цветами
е)ни одно из вышеперечисленных

11. Каждый квадрат круглый. Все квадраты красные.
а) бывают квадраты с красными углами
б) бывают квадраты с круглыми углами
в) бывают круглые красные углы
г) углы и квадраты - круглые и красные
д) ни одно из вышеперечисленных

12. Хорошие начальники падают с неба. Плохие начальники могут петь.
а) Плохие начальники летят с неба вниз.
б) Хорошие начальники, которые умеют летать - могут петь.
в) некоторые плохие начальники не могут петь.
г) некоторые хорошие начальники -плохие, так как они умеют петь.
д) ни одно из вышеперечисленных

 

Ответы смотрите в комментариях.

Permalink | Комментарии (35) | Post RSSRSS comment feed

Вызывать ли Dispose у DataSet

Надеюсь, что все знают, зачем предназначен интерфейс IDisposable и для чего надо вызывать метод Dispose этого интерфейса. Однако, хочу очень кратко напомнить, на случай, если кто-то забыл (если кто-то слышит про Dispose впервые, то советую почитать соответствующую литературу).

Итак, если .NET класс не является оболочкой для неуправляемого ресурса (например, connection к базе данных, handle файла и т.п.), то программисту не надо заботиться о его уничтожении. Для этого предназначен сборщик мусора. Если же класс использует неуправляемые ресурсы, то необходим механизм их освобождения. Для этого предназначен интерфейс IDisposable и его метод Dispose. Этот метод следует вызывать для освобождение неуправляемых ресурсов. Кроме того, как правило, переопределяется метод Finalize (для C# это делается созданием метода с синтаксисом деструктора), в котором, также, происходит освобождения неуправляемых ресурсов на случай, если явно вызвать Dispose забыли. Явный вызов Dispose намного предпочтительнее, так как, во-первых, Finalize вызывается сборщиком мусора, который может начать работу через довольно длительное время, во-вторых, объекты, для которых вызывается Finalize, помещаются в специальную очередь завершения и существуют до следующей сборки мусора (т.е. занимают память дополнительное время). В методе Dispose, кроме освобождения неуправляемых ресурсов, вызывается GC.SuppressFinalize(), который сообщает сборщику мусора, что вызывать Finalize для этого объекта не надо.

Весь этот механизм очень подробно описан в книге Джефри Рихтера.

В принципе, если класс имплементирует IDisposable, то надо вызывать Dispose. Это однозначно для таких классов, как SqlConnection и SqlDataReader. Однако, насчет DataSet часто возникают вопросы.

Итак, DataSet имплементирует интерфейс IDisposable. Следовательно, правильно было бы вызывать метод Dispose при завершении работы с датасетом.

Для чего нужен Dispose? Для освобождения неуправляемых ресурсов. Память, занимаемая объектом, освобождается сборщиком мусора независимо от вызова Dispose. А какие неуправляемые ресурсы использует датасет? Никаких. Дело в том, что имплементация IDisposable достается ему в наследство от MarshalByValueComponent.

Что же делает Dispose в случае датасета? Вызывает GC.SuppressFinalize(), который сообщает сборщику мусора, что метод Finalize вызывать не надо. Больше ничего.

Значит, если мы не вызовем Dispose, ничего плохого не произойдет, т.к. никаких неуправляемых ресурсов освобождать не надо? Не совсем так. Дело в том, что тогда сборщик мусора вызовет метод Finalize и переместит объект в очередь завершения, что продлит время жизни объекта до следующей сборки мусора.

Получается, что сторонники вызова Dispose правы. Но давайте рассмотрим DataTable. Он, тоже, наследуется от MarshalByValueComponent. Если следовать нашей логике, необходимо вызывать Dispose и для каждого DataTable в DataSet. Я не знаю никого, кто так делает. А вы? Вызывать Dispose для DataSet и не вызывать для DataTable, как минимум, нелогично, т.к. объектов DataTable больше.

Что же делать? Вызывать или не вызывать? Не вызывать! Дело в том что в конструкторах DataSet и DataTable вызывается GC.SuppressFinalize() и, следовательно, сборщик мусора не будет вызывать Finalize!

Permalink | Комментарии (1) | Post RSSRSS comment feed

BlogJet vs Windows Live Writer (WLW) - part 2

BlogJet существует уже относительно давно, WLW появился на днях. Решил сегодня посмотреть, про какой продукт найдется больше страниц:

http://www.google.com/search?hl=en&q=BlogJet&btnG=Search
- about 357,000

http://www.google.com/search?hl=en&lr=&q=%22Windows+Live+Writer%22&btnG=Search
- about 2,890,000

С гигантом конкурировать трудно. Я бы на месте Дмитрия уже думал над новой идеей.

Пара ссылок на блоги по теме:

Как помочь BlogJet'у
Windows Live Writer

Permalink | Комментарии (0) | Post RSSRSS comment feed

BlogJet vs Windows Live Writer

Некоторое время назад я наткнулся на блог Дмитрия Честных. Автор часто пишет хорошие заметки и дает полезные ссылки.

Кроме блога, Дмитрий является автором популярной программы BlogJet, предназначенной для создания записей в блогах. Лично я так и не успел посмотреть эту программу, т.к. стоит она недешево, а использовать кряк нехотелось. Но, по отзывам других блоггеров, димин BlogJet не имел себе равных, несмотря на наличие бесплатных аналогов. По слухам, чуть ли не половина сотрудников Microsoft купила себе эту программу. Естественно, в Microsoft не могли не заметить такую большую статью расходов и следствием этого стал выпуск Windows Live Writer - конкурента BlogJet. Интерфейсом и возможностями обе программы схожи, но у Windows Live Writer есть одно огромное преимущество, которое при прочих примерно равных возможностях ставит его вне конкуренции - он совершенно бесплатен!

Немногие, наверное, помнят, что когда-то давно, до появления Internet Explorer браузер Netscape был платным. После появления Internet Explorer, Netscape, тоже, стал бесплатным, но это ему не помогло. Теперь, подобная участь ждет и BlogJet. Трудно конкурировать с хорошим бесплатным продуктом.

Я сочувствую Диме, но как пользователь я рад, что могу пользоваться Windows Live Writer бесплатно (пишу этот пост в нем).

Очень интересно наблюдать дальнейшее развитие событий. Сейчас Дмитрий обвиняет Microsoft в плагиате и говорит, что "почти круглосуточно пишу BlogJet 2.0". Это, действительно, похоже на агонию, как пишут тут.

Посмотрим, что из этого получится. На мой взгляд возможны такие варианты:

  • BlogJet 2.0 будет на порядок лучше Windows Live Writer и деньги снова польются рекой в карман Дмитрия. Я считаю такой ход событий маловероятным - всетаки у гиганта больше возможностей, чем у одинокого разработчика.
  • Деньги не польются, но какой-то старый конкурент Microsoft захочет купить BlogJet, чтобы сделать его бесплатным. В этом есть определенный резон, т.к. при первом запуске Windows Live Writer сразу предлагает создать блог на Windows Live Spaces, а потом предлагает установить тулбар для IE. Для того же Гугла несколько десятков тысяч за BlogJet - копейки.
  • Дмитрий сделает BlogJet бесплатным и попробует заработать на рекламе.

Лично я предпочел, чтобы Дмитрий избавился от BlogJet и занялся другим проектом. Очень интересно узнать, BlogJet - это просто везение или автор действительно талантлив.

Дополнительные ссылки по теме:

Windows Live Writer
BlogJet
Интервью с архитектором Windows Live Writer

Permalink | Комментарии (0) | Post RSSRSS comment feed

Почему Round "раундит" "не правильно" или все про округление в .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 реализует именно банковское округление. В качестве параметра он принимает округляемое значение и, возможно, точность, до которой необходимо выполнить округление. Если точность не указана, то округление выполняется до целого.

Случайное округление

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

Попеременное (alternate) округление

В этом случае .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

Добавлено 25.10.2005

В .NET 2.0 метод Round() класса Math имеет перегрузки с параметром mode типа MidpointRounding, определяющим, как будет округляться половина. MidpointRounding может принимать два значения:

  • AwayFromZero - половина округляется к ближайшему числу, которое дальше от нуля (т.е обыкновенное математическое симметричное округление).
  • ToEven - округление половины к ближайшему четному - единственная текущая реализация Round(). Естественно, если параметр mode не задан, по умолчанию используется ToEven (для совместимости).

Permalink | Комментарии (0) | Post RSSRSS comment feed

Старые материалы

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

Permalink | Комментарии (0) | Post RSSRSS comment feed

Новый движок сайта

Поддавшись всеобщей тенденции, я решил сделать главной страницей сайта блог. Прежний движок сайта, DotNetNuke, хотя и имел модуль для блога, но был не очень функциональным в этом плане. Теперь сайт работает на движке CommunityServer.

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

Также, выражаю признательность технологическому партнеру Parking.ru - провайдеру виртуального и выделенного хостинга на платформе Windows® за предоставленную техническую поддержку сайта.

Permalink | Комментарии (0) | Post RSSRSS comment feed
Реклама
TNX.net - уникальный международный сервис для вебмастеров и оптимизаторов

Подписка
toodoo Читать в Яндекс.Ленте Добавить в Google Reader или Homepage

Статистика
]]>
  • PR0CY.com - сервис проверки доменов
  • BlogMemes.ru
]]>





]]>

]]>