ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 3253

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Процессоры Pentium используют небольшой трюк, который несколько снижает уш занную неприятность,— при работе они применяют специальный формаа в котором для числа с плавающей точкой выделяется 80 бит. При округлении тако| го числа к 64-битовому почти всегда получается результат, который вы ожидаете.

Скорость вычислений

Процессоры х86, использующиеся на старых компьютерах под управление]! Windows, выполняли действия над целыми числами существенно быстрее, чем над чис| лами с плавающей точкой. В настоящее время эта проблема так остро не стоит.

Отношение скоростей работы процессора Pentium III при простом (пожалуй, слиш] ком простом) тесте, состоящем в 300000000 сложений и вычитаний целых чисел и чисем с плавающей точкой, оказалось равным примерно 3 к 1. То есть вместо одного сложешя d o u b l e можно сделать три сложения i n t . (Вычисления с применением умножения и делений могут привести к другим результатам.)

Ограниченность диапазона

В прошлом переменные с плавающей точкой могли представлять значительно боль­ ший диапазон чисел, чем целые. Сейчас диапазон представления целых чисел существ венно вырос — стоит вспомнить о типе l o n g .

Даже простой тип f l o a t способен хранить очень большие числа, но числа значащих цифр у него ограничено примерно шестью. Например, 12345678 9F означает то же, что и 123456000F . (О том, что такое F в приведенных заган сях, вы узнаете немного позже.)

Как уже объяснялось в предыдущих разделах, и целые, и десятичные числа имеют свои недостатки. Переменным с плавающей точкой присущи проблемы, связанные с во­ просами округления из-за недостаточной точности представления, целые переменные не могут представлять числа с дробной частью. Бывают ситуации, когда совершенно необ­ ходимо иметь возможность получить лучшее из обоих миров, а именно числа, которые:

•S подобно числам с плавающей точкой, способны иметь дробную часть;

Sподобно целым числам, должны представлять точные результаты вычислений — т.е. 12.5 должно быть равно 12.5, и ни в коем случае не 12.500001.

К счастью, в С# есть такой тип чисел, называющийся d e c i m a l . Переменная типа d e c i m a l в состоянии представлять числа от 10"28 до 1028 — вполне достаточный диапа­ зон значений! И все это делается без проблем, связанных с округлением.

О б ъ я в л е н и е п е р е м е н н ы х т и п а decimal

Переменные типа d e c i m a l объявляются и используются так же, как и переменные других типов:

64

Часть II. Основы программирования в С#


decimal

ml;

//

Хорошо

decimal m2 = 100 ;

//

Лучше

decimal

m3 = 100M;

//

Идеально

Объявление ml выделяет память для переменной ml без ее инициализации. Пока вы не присвоите значение этой переменной, оно будет неопределенным. В этом нет особой проблемы, так как С# не позволит вам использовать переменную без начального при­ своения ей какого-либо значения.

Второе объявление создает переменную т2 и инициализирует ее значением 100. В этой ситуации неприятным моментом оказывается то, что 100 имеет тип i n t . Поэтому С# вы­ нужден конвертировать i n t в d e c i m a l перед инициализацией. К счастью, С# понимает, чего именно вы добиваетесь, и выполняет эту инициализацию для вас.

Лучше всего использовать такое объявление, как объявление переменной тЗ с кон­ стантой 10ОМ типа decimal . Буква М в конце числа указывает, что данная константа имеет тип decimal, так что никакого преобразования не требуется.

Сравнение д е с я т и ч н ы х , ц е л ы х ч и с е л и чисел с плавающей т о ч к о й

Создается впечатление, что числа типа d e c i m a l имеют лишь одни достоинства и ли­ шены недостатков, присущих типам i n t и double . Переменные этого типа обладают широким диапазоном представления и не имеют проблем округления.

Однако у чисел decimal есть свои неприятности. Во-первых, поскольку они имеют дробную часть, они не могут использоваться в качестве счетчиков, например, в циклах, о ко­ торых пойдет речь в главе 5, "Управление потоком выполнения".

Вторая проблема не менее серьезна, и заключается в том, что вычисления с этим ти­ пом чисел гораздо медленнее, чем с простыми целыми числами или даже с числами с плавающей точкой. В уже упоминавшемся тесте с 300000000 сложений и вычитаний работа с числами d e c i m a l примерно в 50 раз медленнее работы с числами i n t . Это от­ ношение становится еще хуже для более сложных операций. Кроме того, большинство математических функций, таких как синус или возведение в степень, не имеют версий для работы с числами decimal .

Понятно, что числа типа d e c i m a l наиболее подходят для финансовых приложений, где исключительно важна точность, но само количество вычислений относительно невелико.

Логичен ли логический tnun?

И наконец, о переменных логического типа. Тип b o o l имеет только два значения — true и false . Это не шутка — целый тип переменных придуман для работы только с двумя значениями.

Ранее программисты на С и С++ использовали нулевое значение переменной типа i n t для обозначения f a l s e и ненулевое — для обозначения t r u e . В С# этот фокус не проходит.

Переменная типа b o o l объявляется следующим образом: bool thisIsABool = t r u e ;

Нет никаких путей для преобразования переменных b o o l в другой тип переменных (даже если бы вы могли это делать, это бы не имело никакого смысла). В частности, вы

Глава 3. Объявление переменных-значений

65


не можете

преобразовать b o o l

в s t r i n g

(чтобы f a l s e стало

в i n t (чтобы, скажем, f a l s e превратилось в 0) или " f a l s e " ) .

Программа, которая в состоянии заниматься только вычислениями, могла бы устроить разве что математиков, страховых агентов и военных (да-да— первые вычислительные машины были созданы для расчета таблиц артиллерийских стрельб). Однако в большинст­ ве приложений программы должны работать не только с цифрами, но и с буквами.

С# рассматривает буквы двумя различными путями — как отдельные символы типа c h a r и как строки символов типа s t r i n g .

Т и п char

Переменная типа c h a r способна хранить только один символ. Символьная константа выглядит как символ, окруженный парой одинарных кавычек:

c h a r с = ' а' ;

Вы можете хранить любой символ из латинского алфавита, кириллицы, арабского, иврита, японских катаканы и хираганы и массы японских, китайских или корейских ие­ роглифов.

Кроме того, тип c h a r может использоваться в качестве счетчика, т.е. его можно применять в циклах, о которых вы узнаете в главе 5, "Управление потоком выполнения". У символов нет никаких проблем, связанных с округлением.

Переменные типа c h a r не включают информации о шрифтах, так что в пере­ менной c h a r может храниться, например, вполне корректный иероглиф, но при выводе его без использования соответствующего шрифта вы увидите на экране только мусор.

С п е ц и а л ь н ы е с и м в о л ы

Некоторые символы являются непечатными в том смысле, что вы ничего не увидите при выводе их на экран или на принтер. Наиболее очевидным примером такого символа является пробел ' 1 (кавычка, пробел, кавычка). Другие символы не имеют буквенного эквивалента — например, символ табуляции. Для указания таких символов С# использу­ ет обратную косую черту, как показано в табл. 3.3.

66

Часть II. Основы программирования в С#

Тип string

Еще одним распространенным типом переменных является s t r i n g . Приведенные да­ лее примеры показывают, как объявляются и инициализируются переменные этого типа.

// Объявление с отложенной инициализацией string s o m e S t r i n g l ;

someStringl = "Это строка" ;

// Инициализация при объявлении string someString 2 = "Это строка" ;

Константа типа s t r i n g , именуемая также строковым литералом, представляет собой набор символов, окруженный двойными кавычками. Символы в строке могут включать специальные символы, показанные в табл. 3.3. Строка не может быть перенесена на но­ вую строку в исходном тексте на С#, но может содержать символ новой строки, как по­ казано в следующем примере:

// Неверная запись строки

string someStrin g = "Это строка

иэто строка" ;

//А вот так - верно

string someStrin g = "Это строка\пи эт о строка" ;

При выводе на экран при помощи вызова C o n s o l e . W r i t e L i n e вы увидите текст, размещенный в двух строках:

Это строка и это строка

Строка не является ни перечислимым типом, ни типом-значением — в процессоре не существует встроенного типа строки. К строкам применим только один распространенный оператор — оператор сложения, который просто объединяет две строки в одну, например: string s = "Это предложение . " + " И эт о тоже. " ;

Приведенный код присваивает строке s значение: "Это предложение . И эт о тоже ."

Строка без символов, записанная как "" (пара двойных кавычек), является корректной строкой для типа s t r i n g , и называется пустой строкой. Пустая строка отличается от нулевого символа ' \ 0 ' и от строки, содержащей любое количество пробелов (" ") .

Кстати, все остальные типы данных в этой главе — типы-значения (value types). Строковый тип типом-значением не является.

Все инструкции С# должны быть реализованы как машинные команды процессо­ р а — процессора Intel в случае PC. Эти процессоры также имеют собственную концепцию переменных. Например, процессор Intel содержит восемь внутренних хранилищ, именуемых регистрами, каждый из которых может хранить одно зна­ чение i n t . Не вдаваясь в детали функционирования процессора, можно сказать, что все типы, описываемые в данной главе, за исключением decima l и s t r i n g , являются встроенными для процессора. Таким образом, существует машинная

Глава 3. Объявление переменных-значений

67


команда, суть которой в следующем: прибавить один i n t к другому. Имеется I аналогичная команда и для сложения d o u b l e .

Кроме того, переменные описанных типов (опять же, за исключением s t r i n g ) I имеют фиксированную длину. Переменные типа с фиксированной длиной всегда за-1 нимают одно и то же количество памяти. Так что при присваивании а = Ь С# может! поместить значение b в а без каких-либо дополнительных мер, разработанных для I типов переменной длины. Эта характеристика дает этим типам переменных имя ти-1

пы-значения.

Типы i n t , d o u b l e , b o o l и их "близкие родственники" наподобие беззнаково-1 го i n t являются встроенными типами. Встроенные типы переменных и тип I d e c i m a l известны также как типы-значения. Тип s t r i n g не относится ни I к тем ни к другим.

Типы, о которых речь пойдет в главе 6, "Объединение данных — классы и массивы", определяемые программистом и известные как ссылки, не являются ни встроенными, ни типами-значениями. Тип s t r i n g является ссылочным типом, хотя компилятор С# рас­ сматривает его специальным образом в силу его широкой распространенности.

Сравнение string и char

Хотя строки имеют дело с символами, тип s t r i n g существенно отличается от типа c h a r . Понятно, что имеются некоторые тривиальные отличия. Так, символ помещается в одинарные кавычки, а строка — в двойные. Кроме того, тип c h a r — это всегда один символ, так что следующий код не имеет смысла — ни в плане сложения, ни в плане

конкатенации:

 

c h a r c l =

' а ' ;

c h a r

с 2 =

' Ь 1 ;

c h a r

с З = c l + с 2 ;

На самом деле этот код почти компилируем, но его смысл существенно отли­ чается от того, который мы ему приписываем. С# преобразует cl и с2 в значе­ ния типа i n t , представляющие собой числовые значения соответствующих символов, после чего складывает полученные значения. Ошибка возникает при попытке сохранить полученный результат в с З , так как при размещении значе­ ния типа i n t в переменной меньшего размера c h a r данные могут быть поте­ ряны. В любом случае, эта операция не имеет смысла.

С другой стороны, строка может быть любой длины. Таким образом, конкатенация двух строк вполне осмысленна:

s t r i n g s i

=

" а " ;

 

s t r i n g s 2

=

" b " ;

 

s t r i n g s 3

=

s i + s 2 ;

/ / Р е з у л ь т а т — " a b "

В качестве части своей библиотеки С# определяет целый ряд строковых операций, которые будут описаны в главе 9, "Работа со строками в С#".

68

Часть II. Основы программирования в С#