Языки программирования. Лекция 6.
Язык ADA
Проблемы целочисленных тд:
1). Проблема представления
2). Проблема универсальности (насколько система целочисленного тд соответствует машинной архитектуре)
3). Надежность
фиксированное представление тд неуниверсальность.
Естественный тип данных- natural int ( в Cи#) (то, что в Си называется просто int)
(для грядущих 64-битных архитектур)
Язык ADA
Целочисленный тд
Для языка Ада ключевой пункт – надежность.
В Аде существуют понятия тип и подтип ( очень гибкая концепция типов).
Типы могли выводиться друг из друга ( type T1 is new T- Т1 производный от Т, не путать с наследованием! Т1 наследует все мн-во значений и операций типа Т).
Типы между собой не совместимы полностью!!!
Для Ада: Если
type T1=T, то Т1- новый тип данных.
( для Си++ typedef T T1; T1- просто синоним Т, но не новый тип!)
Но подтипы совместимы.
Пример:
1).
Задача: Несовместимость без знаковых типов с целочисленными:
type CARDINAL is new INTEGER range 0..MAXINT;
I:CARDINAL;
J:INTEGER;
I и J не совместимы!!!!!!!
Т. е. нельзя I+J, I:=J, J:=I и т.д. ( статический контроль).
2).
Задача: Ограничить мн-во значений
Подтипы :
subtype NATURAL is INTEGER range 0..MAXINT;
K:NATURAL;
J:INTEGER;
K:=J; J:=K; K+J(значение- тип integer); -совместимы - квазистатический контроль( во время исполнения, т.к. значение J известно только в момент исполнения) надежность
Например: проверка J на попадание в диапазон.
K:=-1; нельзя, ограничение диапазона – статический контроль.
Вещественные типы данных
1). Плавающие
S*Ma*Bp
S-знак + или –
M-мантисса( n бит) ½<= M <1
(т.к. машина двоичная, для десятичной-1/10<= M <1)
в терминах двоичной системы 0.b1b2…bn, где bi-биты мантиссы
т.к. ½<= M <1b1=1-нормализованное представление.
Естественно в качестве В( порядок) выбирать 2.
1985- стандарт IEEE 754 базовые правила работы с плавающей арифметикой:
-Мантисса хранится в нормализованном представлении b1 хранить не обязательно.
-устанавливает представление
32-битное
64-битное
-младшие значения порядка –зарезервированы
-не все значения мантиссы являются одинаково допустимыми
Зарезервированные значения NaN- Not a Number( выдается при ошибке вещественной арифметики) и +, - бесконечность. С ними можно сравнивать и производить ряд операций.
Все производители компьютеров приняли этот стандарт.
Это стандарт поддерживают С# и Java( float ( 32 bit) и double (64 bit))
Си# поддерживает decimal – 128 bit, для работы с SQL. Вообще, SQL оказал большое влияние на С# .
Ада
Для переносимости фиксируем точность:
Type T is digits D; D-значащих разрядов
Type T is digits 6;
[log2 D]+1- число бит в мантиссе
Модельные числа для языка Ада - М*2р с размерностью мантиссы [log2 D]+1
D<7 32- битная реализация
D>6 64- битная реализация
Т.о. стандарт Ады определял модельные числа, а задача компилятора- подобрать такую реализацию, что доступна на данном процессоре, чтобы она включала целиком все модельные числа.
Если D велико(например, 50), то компилятор должен сам генерировать все операции с такими числами (стандарт Ады-83). Практика показала, что соответствующие реализации очень накладны.
Современные компиляторы выбирают представления либо float, либо double. Если соответствующих вариантов нет, то компилятор выдает ошибку и дальше это проблема программиста, переделывать программу.
Пример:
Промежуток= 2-n
при р=0 и р=1 – 2n чисел, и т.д. промежуток растягивается, а количество чисел 2n
большая погрешность при больших числах!
2).Фиксированный тип (delta тип)
type T is delta H range L..R
l, R- константы.
Интервал от L до R с интервалом H (удобен для сеточных функций).
Причины появления такого типа:
1). Фиксированная точность
2). Более компактное хранение(конец 70-х главный ресурс-память)
кол-во чисел= (L-R)/H
Удобен для хранения результатов измерений при оцифровки звука (диапазон и кол-во значений).
Вывод: язык Ада наиболее адекватен для численных математических расчетов Он не стал языком №1, т.к.:
-
сложность яп;
-
соответствующая ниша занята уже фортраном;
Логический тип
Есть во всех яп, которые мы рассматриваем:
- Boolean
- Bool ( Cи#, Cи++)
- True, false
Во всех яп логический тд несовместим со всеми остальными. Т.е. все преобразования – явные.
Но в языке Си++, изначально логического типа не было. Возможное решение:
Typedef bool
#define TRUE 1
#define FALSE 0
Необходимость введения в С++ bool- bool, как описано выше, это не новый тд, а синоним unsigned int.
Т.е.:
Для полноценного тд, существует перекрытие функций:
int f(int)
int f(bool)
Для полноценного тд объявления обеих ф-ий корректно, для описания bool, как показано выше, не корректно.
f(x) – тип х определит функцию, которая будет вызвана.
необходимость введения полноценного типа bool.
Для совместимости С и С++:
1). Неявное преобразование bool int
2)true=1, false=0 все логические значения будут сведены к ним. Например, 31.
В С++:
bool b;
int I;
b&&I; можно, т.к. есть bool int, но компилятор выдаст предупреждение из-за неэффективности.
Проблема тд – Ленивые вычисления
Двуместные операции:
ор1 ор 2
У ряда операций достаточно вычислить только первый аргумент, например:
And, or:
0 and ор=0
1 or ор=1
Следовательно, можно вычислить только 1-ый операнд.
В старых ЯП в целях оптимизации компилятор мог переупорядочивать операнды( увеличение эффективности, например повторное вычисление операнда в выражении)!
ор1 ор 2 op1op2
f(a) f(b) f(a)f(b)
Если ф-ия обладает побочным эффектом, то может возникнуть проблема.
Если компилятор производит оптимизацию и переупорядочивание вычислений, то вычисления становятся непереносимыми.
Во всех современных языках порядок вычисления операндов выражения и аргументов функции не зафиксирован.
В первом варианте языка Ада:
1).ор1 and op2 op1 or op2 вычисляют оба операнда, порядок их вычисления зависит от компилятора.
2). Укороченные операции and_if и or_else вычисления слева на право (ленивые операции).
В окончательном варианте 2 не вошли, т.к. были избыточными.
В С все логические операции- ленивые, арифметические- компилятор имеет право устраивать некоторую оптимизацию. В современных языках принят такой же подход.
Пример: while (i<= N) and ( a[i]<> x) do …
And должна быть ленивой, иначе -выход за границу массива!
Порядковые типы
1).Перечисления.
Впервые появился в яп Паскаль- явное перечисление значений.
Базовый тип - целочисленный тип данных.
type DaysofWeek= ( Mon, Tue, …, n+1) Mon=0 Tue=1…
daysofWeek i;
i:=3;
i:=Wed; наглядность
i:=8; -нельзя, т.к. 8 выходит за диапазон [0,6] надежность.
В языке Ада компилятор может выбирать базовым типом не целочисленный, а подтип, т.е. столько бит, сколько необходимо для хранения.
В 1988 году появился язык Оберон, но уже без перечислимых типов данных. Вирт посчитал его избыточным для языка, т.к Оберон –ООЯП
-
перечислимые типы усложняют компиляцию программ (многомодульных программ, т.к. когда мы импортируем типы данных импортировать имена, т.е. для перечислимого типа- импортируем неявно соответствующие константы- очень накладно и могут возникнуть конфликты имен)
-
(основная!!!) перечислимые типы слабо удовлетворяют концепции наследования:
Т<= open (openmode, enum openmode)
поток ввода- вывода, openmode, enum openmode- .режимы открытия
T=> (наследование) T1 у него уже свой open на верхнем уровне надо зафиксировать всевозможные значения, с которым может открываться файл. Детализация идет с более низким уровнем иерархии.
С++:
Иерархия Iostream
Ios- класс, в нем есть соответствующие константы, и он неявно совместим с целочисленным мы можем любой целочисленной переменной присвоить значение перечислимого типа без всяких преобразований. Операции в данном классе аргументы – целого тд.
Ios::имя_константы
В Delphi есть, т.к. перечислимый тип был в Паскале.
1995- Java (перечислимого типа нет, т.к. Java -ООЯП)
static final int Mon=1
Значение final не меняется
Здесь мы уже теряем в надежности
(day_of_week=19;)
1999-C# (перечисления есть)
причина: Понятие перечислимого тд хорошо коррелирует с понятием интерактивной среды разработки (IDE).
инспектор объекта
name
|
Value
|
|
|
|
combobox
|
x
|
150
|
Value 1
|
|
|
…
|
|
|
Value n
|
|
|
|
В combobox явно перечислены всевозможные значения, которые могут быть.
Классы:
- классы-заготовки для наследования
В системе MFC:
CDialog CMyDialog
-терминальные классы, предназначенные для использования( в них перечисления очень полезны, т.к. класс расширяться не будет).Компонентное программирование
C# использует парадигмы:
-компонентное программирование
-чисто объектно-ориентированная парадигма
В Паскаль, Модула-2- перечислимые типы такие, как рассказывалось выше.
ADA
1).
type Color is (Red, Green, Blue);
type Т is (Red, ..);
i:= Red; для Ада это не ошибка (зависит от полного контекста, т.е. от типа данных i), для модула-2, Паскаль, С –это ошибка!
2).
procedure P(X: color)
procedure P(X:T)
P(i)- в зависимости от типа i
P(Red)- ошибка, т.к. он не знает что такое red.
Для этого есть конструкция “ указание типа”(указывает) (не “ преобразование типа”(преобразует) !)
общий вид указания типа: Т’е
Р(Color' Red);
В Паскале тип- Boolean, на основе перечислимого типа.
Character- предопределенный перечислимый тип в языке Ада.
type CHARACTER is (‘A’,’B’,’C’,…,‘a’,’b’,’c’,…,’0’,…);
Сравнение перечислений в C# и C++:
Основа перечислимых типов- диапазон 0…N-1
Можно ли преобразовывать перечислимый тип в числа и наоборот?
Кроме С++(по наследству от С) неявно нельзя.
type T=(C1,…,CN)
X:T;
X:=T(8);-явное преобразование числа в константу(квазистатический контроль).
X:=color(i);
В модуле-2:
Val(T,e) Т-имя типа, e- значение.
7>
Достарыңызбен бөлісу: |