В.В. Кулямин - Технологии программирования. Компонентный подход (1133554), страница 45
Текст из файла (страница 45)
внутри блока или выражения,помеченных ключевым словом unchecked), товычисления производятся в арифметике поподходящему модулю 2n.Если же эти действия производятся в checkedконтексте (т.е. внутри блока или выражения,помеченных модификатором checked), топереполнение приводит к созданиюисключения.По умолчанию действия, производимые в ходевыполнения, происходят в unchecked контексте,а действия, которые выполняются надконстантами во время компиляции — в checkedконтексте. При этом создание исключения вовремя компиляции приводит к выдачесообщения об ошибке.Любые целочисленные типы можно явно приводить друг к другу, а неявные преобразованияпереводят из меньших типов в большие, если при этом нет перехода от типа со знаком кбеззнаковому (обратный переход возможен).149В обоих языках целочисленным типом считается и тип char, чьими значениями являются 16битные символы (от '\u0000' до '\uffff'). Для него определен тот же набор операций, нопреобразования между ним и другими типами по умолчанию не производятся (явныепреобразования возможны).Типы чисел с плавающей точкойПредставление типов значений с плавающей точкой, float и double, а также операции с ними,соответствуют стандарту на вычисления с плавающей точкой IEEE 754 (он же —IEC 60559) [11,12].
Согласно этому стандарту значение такого типа состоит из знакового бита,мантиссы и экспоненты (у значения float 23 бита отводятся на мантиссу и 8 на экспоненту, уdouble — 52 бита на мантиссу и 11 на экспоненту).Помимо обычных чисел значения обоих типов включают -0.0 (кстати, написав так, выполучите обычный 0.0, поскольку этот текст будет воспринят как константа 0.0, к которойприменен унарный оператор -; единственный способ получить -0.0 — конвертировать его битовоепредставление — в шестнадцатеричном виде для типа float он представляется как 0x80000000, адля double — 0x8000000000000000), положительные и отрицательные бесконечности (для типаfloat это 0x7f800000 и 0xff800000, а для double — 0x7ff0000000000000 и 0xfff0000000000000),а также специальное значение NaN (Not-A-Number, не число; оно может быть представлено любымизначениями, у которых экспонента максимальна, а мантисса не равна 0).Для значений с плавающей точкой определены следующие операции.•==, != — сравнения на равенство и неравенство.
В соответствии с IEEE 754 NaN не равнони одному числу, в том числе самому себе. -0.0 считается равным 0.0.•<, <=, >, >= — сравнения на основе порядка. +∞ больше, чем любой обычное число и -∞,а -∞ меньше любого конечного числа. NaN несравнимо ни с одним числом, даже с самимсобой — это значит, что любая указанная операция возвращает false, если один из ееоперандов — NaN. -0.0 считается равным, а не меньше, чем 0.0.•+, -, *, /, % — сложения, вычитание, умножение, деление, взятие остатка по модулю, атакже соответствующие операции присваивания с одновременным выполнением одного изэтих действий. Все эти операции действуют согласно IEEE 754, кроме операциивычисления остатка, которая реализована так, чтобы при всех конечных a и b (b != 0)выполнялось a%b == a – b*n, где n — самое большое по абсолютной величине целоечисло, не превосходящее |a/b|, знак которого совпадает со знаком a/b.
По абсолютнойвеличине a%b всегда меньше b, знак a%b совпадает со знаком a.Согласно стандарту IEEE 754 все арифметические операции определены для бесконечныхаргументов «естественным» образом: 1.0/0.0 дает +∞, -1.0/0.0 дает -∞, 0.0/0.0 — NaN,конечное x в сумме с +∞ дает +∞, а +∞+(-∞) — NaN. Если один из операндов NaN, торезультат операции тоже NaN.•++, -- — увеличение и уменьшение на единицу. Для бесконечностей и NaN результатприменения этих операторов совпадает с операндом.В Java в классах java.lang.Float иjava.lang.Double есть константы, равныемаксимальному конечному значению типа,минимальному положительному значению типа,положительной и отрицательнойбесконечностям и NaN.-23127Float.MAX_VALUE = (2-2 )·2-149Float.MIN_VALUE = 2-591023Double.MAX_VALUE = (2-2 )·2-1074Double.MIN_VALUE = 2Бесконечности и NaN в обоих случаяхВ C# соответствующие классы System.Single иSystem.Double также хранят эти значения ввиде констант MaxValue, Epsilon,PositiveInfinity, NegativeInfinity и NaN.150называются POSITIVE_INFINITY,NEGATIVE_INFINITY и NaN.В C# есть еще один тип для представлениячисел с плавающей точкой — decimal (типобертка для него называется System.Decimal).Значения этого типа представляются 128битами, из которых один используется длязнака, 96 — для двоичной мантиссы, еще 5 —для представления десятичной экспоненты,лежащей от 0 до 28.
Остальные биты неиспользуются.Представляемое знаком s (+1 или -1), мантиссойm (0–(296-1)) и экспонентой e (0–28) значениеравно (-1)s·m·10-e.Таким образом, значения этого типа могут, вотличие от стандартных типов float и double,представлять десятичные дроби с 28-ю точнымизнаками и используются для финансовыхвычислений. Такая точность необходима,поскольку в этих вычислениях ошибкиокругления в сотые доли процента принакоплении за счет больших сумм и большогоколичества транзакций в течение несколькихлет могут привести к значительным суммамубытков для разных сторон.Для типа decimal определены все те жеоперации, что и для типов с плавающей точкой,однако при выходе их результатов за рамкизначений типа создается исключительнаяситуация. Этот тип не имеет специальныхзначений -0.0, NaN и бесконечностей.В Java классы, методы и инициализаторы могутбыть помечены модификатором strictfp.
Онозначает, что при вычислениях с плавающейточкой в рамках этих деклараций всепромежуточные результаты должны бытьпредставлены в рамках того типа, к которомуони относятся, согласно стандарту IEEE 754.Иначе, промежуточные результаты вычисленийсо значениями типа float могут бытьпредставлены в более точном виде, что можетпривести к отличающимся итоговымрезультатам вычислений.Инструкции и выраженияВыраженияВ обоих языках выражения строятся при помощи применения операторов к именам илитералам.
Условно можно считать, что имеется следующий общий набор операторов.• x.y — оператор уточнения имени, служит для получения ссылки на элемент пространстваимен или типа, либо для получения значения поля (или свойства в C#);151•f(x) — оператор вызова метода (а также делегата в C#) с заданным набором аргументов;•a[x] — оператор вычисления элемента массива (а также обращения к индексеру в C#);•new — оператор создания нового объекта (или значения в C#), используется вместе собращением к одному из конструкторов типа — new MyType("Yes", 2) (в Java с егопомощью нельзя создавать значения примитивных типов);••++, -- — префиксные и постфиксные унарные операторы увеличения/уменьшения на 1;•+, - — унарные операторы сохранения/изменения знака числа;•! — унарный оператор логического отрицания;•~ — унарный оператор побитового отрицания;•*, /, %, +, - — бинарные операторы умножения, деления, взятия остатка по модулю,(T)x — оператор явного приведения к типу T;сложения и вычитания;•<<, >> — бинарные операторы побитовых сдвигов влево/вправо;•<, >, <=, >= — бинарные операторы сравнения по порядку;•==, != — бинарные операторы сравнения на равенство/неравенство;•&, |, ^ — бинарные операторы логических или побитовых операций: конъюнкции,дизъюнкции, сложения по модулю 2;•&&, || — бинарные операторы условных конъюнкции и дизъюнкции, (x && y)эквивалентно (x?y:false), a (x || y) — (x?true:y);•?: — тернарный условный оператор, выражение a?x:y вычисляет значение a, если оноtrue, то вычисляется и возвращается значение x, иначе вычисляется и возвращаетсязначение y;•=, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^= — бинарные операторы присваивания, все они,кроме первого, сначала производят некоторую операцию над старым значением левогооперанда и значением правого, а затем присваивают полученный результат левомуоперанду.Операторыx.y, f(x), a[x], new, x++, x-+, -, !, ~, ++x, --x, (T)x*, /, %+, <<, >><, >, <=, >===, !=&^|&&||?:=, *=, /=, %=, +=, -=, <<=, >>=, &=, |=, ^=АссоциативностьлеваялеваялеваялеваялеваялеваялеваялеваялеваялеваяправаяправаяТаблица 10.
Приоритет и ассоциативность операторов.152В Таблице 10 операторы перечисляются сверху вниз в порядке уменьшения их приоритета, атакже приводится ассоциативность всех операторов. Оператор op называетсялевоассоциативным, если выражение (x op y op z) трактуется компилятором как ((x op y) opz), и правоассоциативным, если оно трактуется как (x op (y op z)).Помимо перечисленных выше операторов имеются также общие для обоих языков операции,которые выполняются при помощи различных конструкций — это получение объекта,представляющего тип, который задан по имени, и проверка принадлежности объекта или значениятипу.
В каждом из языков есть также несколько операторов, специфических для данного языка.Получение объекта, представляющего тип, связано с механизмом рефлексии (reflection),имеющимся в обоих языках. Этот механизм обеспечивает отображение сущностей языка (типов,операций над ними, полей их данных и пр.) в объекты самого языка. В обоих языках операцияполучения объекта, представляющего тип, входит в группу операций с высшим приоритетом.Любой тип Java однозначно соответствуетнекоторому объекту класса java.lang.Class,любой метод описывается с помощью одного изобъектов класса java.lang.reflect.Method,любое поле — с помощью одного из объектовкласса java.lang.reflect.Field.Получить объект типа Class, представляющийтип T (даже если T = void), можно с помощьюконструкции T.class.Для проверки того, что выражение x имеет типT, в Java используется конструкция(x instanceof T),возвращающая значение логического типа.В обоих языках операция проверки типа имееттакой же приоритет, как операторы <, >, <=, >=.В C# типы представляются объектами классаSystem.Type, методы — объектамиSystem.Reflection.MethodInfo, а поля —объектами System.Reflection.FieldInfo.Объект типа System.Type, представляющий типT, можно получить при помощи конструкцииtypeof(T).Для проверки того, что выражение x имеет типT, в C# используется конструкция(x is T),имеющая логический тип.Эта проверка использует естественныепреобразования типов (подтипа в более общийтип или наоборот, если точный тип объектаявляется подтипом T) иавтоупаковку/распаковку, не затрагиваяопределенных пользователем неявныхпреобразований.В C# имеется и другой оператор, связанный спреобразованием типа.Для преобразования объекта x к заданномуссылочному типу T можно использоватьконструкцию(x as T),тип результата которой — T.Если в результате естественных преобразованийтипов и автоупаковки/распаковки, значение x непреобразуется к типу T, то результат этоговыражения — null.Приоритет этого оператора такой же, как уоператора is, а ассоциативность — левая.В Java есть дополнительный оператор сдвигачислового значения вправо >>>, заполняющийосвобождающиеся слева биты нулями.Он имеет такой же приоритет, как и остальныеоператоры сдвига, и левую ассоциативность.153Соответствующий оператор присваивания >>>=имеет такой же приоритет, как и другиеоператоры присваивания, и правуюассоциативность.В C# можно строить выражения, в рамкахкоторых переполнения при арифметическихдействиях вызывают (или не вызывают)исключения при помощи оператораchecked(x) (unchecked(x)),где x — выражение, контекст вычислениякоторого мы хотим определить (см.
раздел оцелочисленных типах).Оба этих оператора входят в группу операторовс высшим приоритетом.Выражение default(T) используется в C# 2.0для получения значения типа T по умолчанию.Для ссылочных типов это null, для числовыхтипов — 0, для логического типа — false, a дляостальных типов значений определяется наоснове их структуры.Это выражение используется дляинициализации данных в шаблонных типах,зависящих от типового параметра, которыйможет быть как ссылочным типом, так и типомзначений.Этот оператор входит в группу с высшимприоритетом.Оператор ?? (null coalescing operator)используется в C# 2.0 в следующем смысле.Выражение (x??y) эквивалентно ((x ==null)?y:x), только значение x вычисляетсяоднократно, т.е., если значение x не равно null,то результатом этой операции является x, аиначе y.Этот оператор имеет приоритет меньший, чемприоритет условной дизъюнкции ||, нобольший, чем приоритет условного оператора?:.