[ЗВУК] [ЗВУК]
Сегодня мы поговорим о вещественных числах.
Вещественные числа — это, для простоты, все те числа, которые не являются целыми.
Давайте посмотрим, как они записываются — они могут быть очень большими или очень
маленькими — ну и заодно разберемся в процессе,
как они хранятся в памяти компьютера.
Итак, представим себе, что у нас есть какое-то достаточно большое число,
содержащее в себе хотя бы 10 знаков десятичных, а, может быть, и больше.
Тогда это число, если особенно нужно их перемножать между собой или сравнивать,
или просто как-то оценивать величины, у нас, если мы его запишем традиционно,
с десятью знаками и еще сколько-то знаков после точки, это будет очень сложно для
понимания, потому что придется считать количество цифр.
Поэтому пользуются так называемой научной, или инженерной,
записью чисел, которая выглядит примерно так.
У нас записывается число от 1 до 10.
По сути, это целое число,
но только мы обязательно ставим точку после первой цифры.
Затем пишется буква e и число — положительное или отрицательное.
Какой смысл имеет такая запись?
Это мантисса так называемая,
то есть некоторое количество первых десятичных цифр.
После буквы e идет экспонента — степень десятки,
на которую нужно умножить это число.
То есть мы 1,234 умножаем на 10 в 10-й степени.
То есть вот это называется мантисса, вот это — экспонента.
Экспонента может быть отрицательной.
Это значит, что нужно умножить на 10 в минус 10-й степени, то есть, по сути,
разделить на 10 в 10-й.
В компьютере, конечно же, хранится все в виде двоичных чисел.
То есть если мы наше более-менее любое вещественное число
в десятичной системе исчисления можем представить вот в таком виде...
Конечно, с какой-то точностью, потому что мы не можем хранить все знаки,
у нас просто кончится память.
Например, в числе π количество знаков очень велико.
В компьютере используется двоичная система, то есть,
например, мы можем хранить дроби точно в виде 1/8.
Это 1 делить на 2 в 3-й степени.
А вот 1/10 хранить точно мы не можем.
Хотя, казалось бы, это очень простая привычная нам десятичная дробь.
Почему?
Потому что 10 не является точной степенью двойки,
и у нас хранится какое-то приближение этой дроби.
То есть у нас любое абсолютно вещественное число представимо в виде дроби, где
числитель — это какое-то целое число, а знаменатель — это какая-то степень двойки.
Возможно, отрицательная, тогда мы на нее умножаем.
То есть на самом деле мы храним только некоторое
количество первых двоичных знаков.
Теперь посмотрим, как число хранится в памяти.
В отличие от целых чисел, которые могут содержать в себе, по сути, бесконечное
количество десятичных знаков (то есть пока память не кончится), вещественные числа
имеют очень ограниченный размер, а именно 8 байт, или 64 бита.
Сейчас я расскажу, как они устроены примерно.
Это не совсем точно, но для понимания достаточно.
Ну и достаточно честно.
Итак, вот наши 64 бита.
1 бит отводится на знак + или −.
В принципе, бывает −0 такое вещественное число.
Ну, ничего страшного.
Затем 11 бит отводится на экспоненту,
то есть на ту степень двойки, на которую нужно умножить или разделить.
Она тоже может быть знаковая.
И оставшиеся биты (52) отводятся на хранение мантиссы,
то есть, по сути, целого числа,
которое затем умножается или делится на какую-то степень двойки.
Таким образом, вещественное число — это не любое число.
То есть это, во-первых, оно обязательно рациональное.
Значит, это дробь какая-то.
Во-вторых, даже не каждая дробь,
не каждое рациональное число может быть представлено.
Они очень ограничены.
Ну что главное нужно знать?
Что хранить можно примерно 14–15 первых десятичных знаков или 52 двоичных знака.
Дальше уже будут неточности.
То есть это максимум, на что мы можем расчитывать.
Ну и ограничения на экспоненту также у нас накладывают ограничения на
размер тех чисел, которые мы можем хранить.
То есть, по сути, максимальная размерность, которая может быть, — это
где-то 10 в 1000-й степени примерно или, соответственно, 10 в минус 1000-й степени.
Вот такие ограничения у нас есть на вещественные числа.
Кроме этого, существуют и другие проблемы с вычислением каких-то погрешностей,
состоящие не только в том, что числа у нас хранятся неточно.
У нас числа и вводятся тоже неточно.
Давайте посмотрим такой пример.
У нас есть числовая прямая,
и на ней есть некоторое интересующее нас число x.
Конечно же, оно у нас представлено не точно,
а это какая-то из близлежащих точек,
которые представимы в виде двоичной дроби,
то есть дроби, где у нас в знаменателе есть какая-то степень двойки.
Но на самом деле проблема может быть гораздо больше.
Например, если число задано...
сказано, что задано 7 знаков после точки, или, например, 6 знаков после точки,
то это значит, что у нас, в принципе, ошибка может быть достаточно большая.
Если 6 знаков после точки, то это будет примерно 5 × 10 в минус 7-й степени.
То есть у нас следующий знак, который нами уже не введен, может быть, в принципе,
любой цифрой: как нулем (тогда у нас нет ошибки, ну и как все последующие знаки),
так и, например, пятеркой.
То есть вот это отличие будет очень большое.
То есть даже несмотря на то, что у нас не совсем точно представлено число,
реальная погрешность гораздо больше.
И наше число x — это не точечка на нашей прямой, а какой-то отрезок,
который можно условно назвать: x минус некоторое число ε и
x плюс некоторое число ε.
Из-за этого мы не можем просто взять и сравнить два
вещественных числа на равенство.
То есть если мы проводили какие-то вычисления и хотим понять,
совпадают ли два числа или не совпадают, то мы должны делать не просто сравнение
на «равно–равно», а гораздо более «хитрое» сравнение.
А именно: если мы хотим сравнить два числа x и y,
мы должны посчитать модуль их разности и проверить, что он достаточно мал.
То есть вот так записывается сравнение двух чисел на равенство.
Если же вы хотите проверить, что x меньше, чем y и точно не равен,
то вам нужно проверять опять
же другое выражение.
Значит, x + ε (худший случай,
когда x — самое большое) все равно меньше, чем число y.
Ну вот тогда мы можем расчитывать, что x действительно меньше, чем y,
с учетом всех наших ошибок.
Таким образом, как нам правильно считать погрешность, как нам понимать,
что мы можем гарантировать в качестве точности в ответе на задачу?
Давайте смотреть.
Как мы уже говорили, у нас есть число, допустим, два числа — x и y,
каждое из них не превосходит по
модулю 10 в 9-й степени (это миллиард).
Достаточно часто возникающая задача.
И они заданы с точностью 6 знаков после точки.
Значит, что там находится в седьмом и последующих знаках, мы не знаем.
Поэтому ε мы можем взять
равной 5
× 10 в минус 7-й степени.
Почему так?
Потому что у нас 6 знаков, это 10 в минус 6-й степени.
Соответственно, в следующем знаке, в тех знаках,
которые нами не приведены, максимум может быть вот такое отличие.
Отлично!
Теперь у нас есть задача посчитать произведение чисел
x и y и определить, с какой погрешностью мы его посчитаем.
Значит, вот настоящий результат наш должен быть x × y.
На самом деле, в худшем случае x представимо в виде,
например, (x + ε) и y также
представимо в таком же виде.
Это худший случай, когда у нас оба числа
отличаются на ε от своего настоящего значения.
Раскроем скобки И посмотрим.
Вот наш настоящий результат, правильный: X * Y.
Затем у нас будет
ε * (X + Y).
Когда мы попарно перемножим, получится такое выражение.
И наконец, будет ε².
ε у нас число очень маленькое,
поэтому мы можем не учитывать это слагаемое,
нам оно в оценке не пригодится.
X + Y — правильный ответ, соответственно,
погрешность понятно, какая — это ε * (X + Y).
Подставив конкретные значения для худшего случая,
мы получим собственно нашу погрешность.
Это будет 5 * 10⁻⁷,
и умножить на сумму (X + Y).
В худшем случае это 2 * 10⁹.
Итак, 10⁹
* 10⁻⁷ = 10², и 5 * 2 даст нам еще 10.
То есть результат этого будет 10³.
Таким образом, перемножая просто два числа до миллиарда, заданные с точностью шесть
знаков после точки, на вид это довольно много, мы получим погрешность в 1000.
Довольно неожиданно, тем не менее вот такой простой способ
оценки погрешности в принципе работает и подходит для многих задач.
Если вы, например, занимались экспериментальной физикой,
писали какие-то лабораторные работы, то вы хорошо знакомы с подсчетом
погрешности и сможете посчитать ее более точно.
Как вы видите, мы здесь даже не учитывали,
что у нас число представлено как-то не совсем точно.
На самом деле проблемы гораздо больше, чем от неточного представления наших чисел.
Главное, что нужно знать и всегда во всех задачах
пользоваться этим, — это сравнение вещественных чисел.
То есть если вы напишете «==»,
то у вас далеко не факт, что числа сравнятся
правильно и вы получите действительно ответ истинный для равных чисел.
Хотя, в принципе, вы можете ошибиться и в другую сторону,
получить результат сравнения истинный для разных чисел,
но это менее вероятно.
Как я уже говорил, 0,1 не представима точно в виде дроби,
где знаменатель является степенью двойки.
Ну и как несложно понять, 0,2 тоже не будут представлены точно.
Таким образом, у нас есть 0,1 и,
например, мы хотим сложить с 0,2.
Результат, очевидно, будет равен 0,3.
Если мы пользуемся десятичной системой счисления, то всё так и будет.
Но поскольку представление неправильно в первом слагаемом, неправильно
во втором слагаемом, ну и, в общем-то, оно будет неправильно в третьем слагаемом.
Мы можем надеяться на то, что несмотря на то, что оно в трех местах неправильно,
всё равно сравнение, например,
таких результатов вычисления и константы 0,3 окажется верным.
Ну а проверить это мы сможем уже на практике.
Главное, что нужно помнить про представление вещественных чисел,
— что у вас оно необязательно округляется вверх.
То есть у вас любое абсолютно число может быть представлено как меньшим числом,
записанным точно, так и большим.
И гарантировать ничего вы не можете.
То есть, в принципе, в результате вычислений каких-то у вас может оказаться,
что должно было получиться целое число, а получилось нецелое.
Например, три целых и одна какая-то стомиллиардная, или наоборот,
две целых, куча девяток, ну и может быть, какие-то еще цифры.
Об этом нельзя забывать, и подробнее мы поговорим об округлении (иногда возникает
такая потребность — округлить вещественные числа и перейти обратно к целым)
и посмотрим, какие есть способы округлять вещественные числа, и нужно
применять правильный во всех задачах, где может возникнуть такая ситуация.
Разное поведение в случае, если у нас представлено меньшим или большим числом.
Общий подход к вещественным числам такой.
Если вы можете их не использовать в задаче, например, вам уже вводятся
целые числа или вещественные числа с заданным количеством знаков,
так что вы можете выбросить эту точку и просто получить из этого числа целое,
то нужно стараться оставаться в целых числах.
В них нет проблем с точностью, и, вообще говоря, они работают быстрее.
Поэтому в некоторых задачах сегодняшнего занятия, несмотря на то,
что оно про вещественные числа, как раз будут ситуации,
когда с вещественными числами вы будете с большим трудом писать
решения и без труда напишете решения с целыми числами.
Но, как я уже говорил, чаще всего признаком того, что вещественные числа
не нужны, являются входные данные, представимые в виде целых чисел.
А сейчас мы посмотрим, как работать с вещественными числами на практике, как их
выводить, проводить, и, собственно, какие арифметические операции над ними возможны.
[МУЗЫКА]
[МУЗЫКА]