И.Г. Головин - Конспект лекций по курсу Языки программирования (1161120), страница 10
Текст из файла (страница 10)
Что будет при выходе задиапазон? C,C++ никак не решают эту проблему. В С# есть возможность контроля.Пример: архитектура IA 32(придумана в 1987 и за 20 лет расширилась, но система командосталась та же самой). ARM – меньше энергоемкость, проще. СISC – высокая энергоемкость,поедают много энергии (а точнее выделяют) и большая теплоотдача, значит ARM до сих порподдерживаются и выпускаются.
Современные архитектуры ничего не проверяют за выходза границы.Создатели АДЫ поддерживали 3 требования:Надежность (все равно некий компромисс из-за того, что нужна скорость)Эффективность (системы в целом)Читабельность (не связано с надежностью и эффективностью)Как же решили все эти проблемы?Если хотим эффективность и надежность, нельзя использовать беззнаковость. Программистдолжен выбрать компромисс между типом или подтипом.
Типы различны тогда и только51тогда когда различны их имена (именная эквивалентность типам). Различные типы данныхнесовместимы.Пример (Ада)В АДА есть объявление нового типа данных.TType T1 is new T – имена различны, значит и типы данныхразличныX, y :T1A, b :TX + yA + bX + a – так писать нельзяY + b – так писать нельзяРазные типы данных несовместимы.Объявление может сопровождаться уточнением (ограничениедиапазона).TType T1 is new T Range (0.. MAXINT)Type Natural is new INTEGER range 1..MAXINTType Positive is new INTEGER range 0..MAXINTЛюбая попытка присвоить типу INTEGER – ошибкаX:INTEGERY:NATURALX:=y – нельзя, но допустимо X:= INTEGER (y)Y:= NATURAL (X);Квазистатические преобразования: если компилятор знает текущее значение X, то оносуществит статическую проверку, а если нет, то сразу выдаёт сообщение об ошибке.
Ада,Модула 2, стандартный Pascal содержат значительную часть квазистатических проверок.Перечислимые типы52Языку Assembler противопоказан квазистатический контроль.MOV AL, AXКомпилятор генерирует некоторый код – что противоречит сути Ассемблера.a[-1] ~ *(a-1)В С++ появился динамический контроль типа, кроме того, нет квазистатического контроля.Все современные языки с квазистатическим контролем таковы, что где можно вставитьпроверку, компилятор вставит. А где же тогда гибкость? Концепция типа слишкомограничительна. С одной стороны, хочется поддерживать контроль, а с другой стороныхотелось бы натуральные неотрицательные числа считать разновидностью целых. Еслипрограммисту нужна гибкость, то он может использовать концепцию подтипа – некотороеограничение на множество значений базового типа.
Совместимость сохраняется, подтипыодного типа относятся к одному типу и совместимы по операциям. Если они ограниченные,то обязательно происходит квазистатический контроль, конструкции вставляютсякомпилятором.Type Natural is INTEGER range 1..MAXINTType Positive is INTEGER range 0..MAXINTY:=XX:=YЗдесь компилятор вставит проверкуZ: POSITIVEZ:=xY:=zДолжен быть контроль!В диалектах паскаля (например,Turbo) существуют специальные опции ипсевдокомментарии, позволяющие квазистатические проверки. Дональд Кнутиронизировал: продуктивную версию (для эффективного отключения квазистатическойпроверки) сравнивал с моряком, который носит спасательный пояс на суше, а в моревыкидывает.С одной стороны, эта концепция с точки зрения надежности дает возможностьконтролируемого поведения программы, исключения надо ловить и обрабатывать(максимальное количество проверок компилятор делает статически), имеется гибкаявозможность управлять уровнем надежности и эффективности.Надежность – запретить преобразования, разрешить преобразования.
Но преобразованияконтролируемы статически или во время выполнения. Проблема беззнаковости решена –если боитесь, не используйте.Программист имеет право указывать почти произвольный диапазон, а дело компиляторавыбрать нужный диапазон представления. Сама по себе концепция оказалось оченьмощной, обеспечивая нужную надежность или гибкость.Другой подход – программист выбирает из готовых диапазонов. Проблема различныхархитектур не стоит (Java только на 32 битной, либо 64).53На этом закончим рассмотрение целых типов данных.Вещественные типы данныхСуществуют следующие вещественные ТД:ПлавающиеФиксированныеПлавающие есть во всех ЯП, а фиксированные не во всех.
Если взять вообще всеархитектуры, то представление вещественных типов данных отличается, что влияет напереносимость программ. Язык Ада, как и в случае с целыми типами данных, задает такназываемый «внутрикомпиляторный» подход. Программист работает в терминахабстрактной структуры типов данных, а компилятор уже решает, как это преобразовать вмашинное представление. Там и появилось разделение вещественного типа данных наплавающий и фиксированный. Вещественные от целых типов данных с точки зрениямашины отличаются тем, что операции на вещественными типами данных не точны, так какв ограниченном количестве битов нельзя представить все возможные вещественные числа.Отсюда самая главная задача при работе с вещественными числами – управлениеточностью. В Аде плавающий тип данных – это тип данных, в котором зафиксированаточность, например,type myreal is digits 10;такое объявление говорит, что myreal – это вещественный тип данных, для которогокомпилятор должен подобрать такое представление, чтобы в мантиссе были точнопредставлены 10 знаков.
Т.е. для плавающих типов данных выбрана, так называемая,модельная реализация, вернее модельные числа, которые представлены в виде М*2^p, где0.1<=M<1. Это нормализованное представление. Здесь мантисса выбирается таким образом,чтобы точно представлять 10 десятичных разрядов. Таким образом получается множествомодельных чисел, а компилятор должен выбрать такую реализацию на целевойархитектуре, чтобы нужный тип входил как подмножество в множество чисел реализации.Программист следил за точностью, а компилятор за нужным представлением. Как показалапрактика, такое представление оказалось несколько тяжеловато, поэтому в языке Ада былопросто зафиксировано несколько базовых типов, которые предлагали использоватьпрограммистам.В форме мантисса и порядок записываются следующим образом: S*M*B^p, гдеЗнак – SМантисса – MПорядок – pБаза – BХранятся они отдельно. Представление с плавающей точкой неоднозначно.
Нормализацияформа мантиссы 1/В <= M< 1 (B не обязательно 2, может быть, например, 16).Какие основные проблемы возникают с вещественными числами?Надежность (попадание или непопадание в диапазон операций – ситуация еще хуже чем сцелыми – нет диапазона, здесь проблемы переполнения и потери точности). M разрядов подмантиссу и N под порядок. Можно хранить 2^(M+N).54Представление вещественных чисел относительно приближенно.Пусть M = 24, -126 <= p <= 126, B=2, тогда какое минимальное целое число, которое можетхраниться? Минимальная мантисса ½, значит минимальное число 2^(-127) – меньше никакне получим.Overflow/underflow зависят от нескольких параметров: и от B и от точности мантиссы.Существенна погрешность или не существенна, зависит от задачи (и алгоритма решениязадачи – должны использоваться алгоритмы, нечувствительные к машиннымпогрешностям).Проблема надежности и представления еще более актуальны. Один и тот же алгоритм наразных представлениях вещественных чисел по-разному считает.На универсальность влияют такие понятия, как модельные и физические числа.
Модельные– не зависят от представления, результаты были в пределах относительной обозначеннойточности. Модельные числа приняты в языке Ада.Пример (Ада)Type T is digital NN вычисляется статически, N десятичных цифр – точностьпредставления.Type FLOAT is digital 6;Модельное число в Ада – B – количество бит для хранения мантиссыB = [log2N]+1-4B<=p<=4BS*M*2pВ модельных числах в качестве порядка используется 2.½ представляется c нулевым значением порядка.1 представляется точно – мантисса ½, а порядок 1.p = 0: Δ (расстояние между «засечками», то есть между двумя соседними числами) равно 2-B,2B значений мантиссы. От 1 до 2 порядок 1, Δ = 2-B+1.Для 24 битной мантиссы погрешность 2102 между соседними числами (засечками)P = -126: Δ = - 24-126= -150 (очень велико).Засечки для модельных чисел должны соответствовать засечкам для физических. Вреальности, практика программирования на Ада привела к тому, что концепция удобна, нонереальна.
Для каждой реализации определяется несколько типов. Программист должен55сам выбрать тип чисел. Реальные алгоритмы не могут использовать эмуляциювещественных вычислений.С течением времени проблема представления утратила актуальностьIEEE 754 – стандарт на применения плавающих чисел (IEEE – некоммерческая организация,стандарты IEEE охотно принимаются индустрией).
802 стандарт – беспроводные сетиIEEE определяет 2 представления чисел: 32 бита и 64.В Java float (соответствует 32битному представлению), double (64-битному). Float – дляоптимизации хранения. Double – сначала все в double а потом уже в float (в C, C++).По стандарту есть мантисса и порядок и 1 бит под знак:M*2pПервый бит всегда 1 (из условия нормализации), поэтому под мантиссу 23 бита (хотяточность 24). Под порядок отводится 8 бит. В 64-битном под порядок 11 битов, а подмантиссу 52(причем точность 2-53).P+127Старшее и младшее начального порядка зарезервированы.Nan = NaN – not a number.
0 = 0 (точно). Существуют специальные представления для +infи -inf.Все современные процессоры удовлетворяют этому стандарту.Итак, получаем следующие стандарты для чисел с плавающей точкой. float, double. longdouble – зависит от реализации.Заметим, что представление с плавающей точкой не является универсальным. В технике(инженерии) встречаются разновидности вещественных чисел, которые неудобнопредставлять в виде с плавающей точкой. Например, рассмотрим АЦП – аналого-цифровойпреобразователь. Сигнал преобразуется при определенной частоте дискретизации в регистрразрядностью n бит.2n - количество различных значений, которое может измерять, АЦП не выдают значений сплавающей точкой.точность фиксирована = (R – L) / (2N – 1)Необходимо представление с фиксированной точкой!Частая операция преобразования Фурье (выводит спектр)Type FL is digital Range L..
RType F is delta H Range L.. RКакие еще проблемные области требуют вычисления с фиксированной точностью?«Давайте я выдам приблизительно 28 копеек?» Торговля, банковские операции. Известноемошенничество: в одной из банковских систем программист сделал «закладочку», которая56всегда «обрубала» долю. (25.554 -> 25.55; .004 переходит на какой-то счет). Нашлимошенника только с помощью налоговых органов. Тенденция современных языков –упрощение базиса.В Паскале Writeln, Readln – не суть процедуры, это замаскированные операторы вводавывода. Язык C порвал с этой традицией, все функции ввода/вывода – части стандартнойбиблиотеки.То, что было в языке уходило в стандартную библиотеку (ввод/вывод, например).
Сейчаспроисходит обратный процесс. Представьте себе, стандартный ввод в языке Java. Это простосмешно. Библиотеки String, Object – как бы входят в стандартную библиотеку. Они являютсячастью языка. Есть специальный пакет «java.lang», являющийся частью компилятора.В языке C вы можете все стандартные функции написать сами. Компилятор не обязанничего знать о стандартной библиотеке. А в C++ сейчас (начиная с 90-х годов) компиляторуже знает, правда немного: std::exception. Например, bad_cast. Происходит интеграциякомпилятора с библиотекой.