В.В. Кулямин - Технологии программирования. Компонентный подход (1134162), страница 46
Текст из файла (страница 46)
Такая точность необходима,поскольку в этих вычислениях ошибкиокругления в сотые доли процента принакоплении за счет больших сумм и большогоколичества транзакций в течение несколькихлет могут привести к значительным суммамубытков для разных сторон.Для типа 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.Этот оператор имеет приоритет меньший, чемприоритет условной дизъюнкции ||, нобольший, чем приоритет условного оператора?:.
Он правоассоциативен.В C# 2.0 введен дополнительный оператор ::для разрешения контекста имен в рамкахглобального пространства имен илиопределенных синонимов.Дело в том, что в C# при разрешении имен,построенных с помощью точек, разделяющихидентификаторы, возможны многочисленныепроблемы, связанные с непредвиденнымимодификациями библиотек.Например, если мы написали директиву usingSystem.IO;, чтобы использовать классFileStream с коротким именем, иодновременно определяем в этом контексте154класс EmptyStream, то, если в будущем вSystem.IO появится класс EmptyStream,полученный код перестанет компилироваться.Эту ситуацию можно разрешить при помощисинонимов, определив, например, дляSystem.IO синоним SIO, а для нашейсобственной библиотеки, куда входитEmptyStream, синоним MIO, и используя именаклассов только вместе с синонимами —SIO.FileStream, MIO.EmptyStream.
Однакоесли в одной из используемых библиотек будетвведено пространство имен MIO, проблемавозникнет вновь.Чтобы однозначно отделить типы из внешнихбиблиотек от внутрипрограммных, можноиспользовать оператор ::. При этом левыйаргумент такого оператора может иметь двавида. Либо он имеет значение global — тогдаимя, заданное правым аргументом, ищется вглобальном пространстве имен и конфликтует свнутренними именами. Либо он являетсяименем синонима — тогда имя, заданноеправым аргументом, ищется только впространстве имен, определяемом этимсинонимом.Этот оператор входит в группу с высшимприоритетом.Тип или часть его операций, или дажеотдельный блок в C# могут быть помеченымодификатором unsafe. При этом содержимоепомеченного типа, операции или блокапопадает в небезопасный контекст (unsafecontext).