Студопедия — Числа с плавающей запятой и их особенности
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Числа с плавающей запятой и их особенности






Xpoint.ru» База знаний» Статьи» Числа с плавающей запятой и их особенности

По мотивам обсуждений: Объект Number и его особые свойства (бесконечности и нули), Ошибка в вычислениях чисел с плавающей запятой

Многие программисты годами пишут свои программы, не понимая, что такое числа с плавающей запятой, и чем они отличаются от "обычных", целых чисел. Это не мешает им создавать хорошие программы. Но в конце концов каждый сталкивается с "необъяснимым" явлением:

$a = 1.1 - 1;$b = 0.1;if ($a == $b){ print "$a равно $b";}else{ print "$a не равно $b";}

Здесь и далее все примеры простоты ради приводятся на Perl. Они должны быть понятны и тем, кто не знаком с этим языком программирования, а обсуждаемые проблемы одинаковы для всех языков.

Эта программа печатает "0.1 не равно 0.1". В чём дело? Напрашивается вывод, что в языке программирования что-то не в порядке. В сети можно найти немало переписок с разработчиками языков о подобных "ошибках". На самом же деле, этот пример демонстрирует некоторые важные свойства чисел с плавающей запятой — их эта статья и попытается объяснить.

Оглавление

  • Как узнать, что используются числа с плавающей запятой?
  • Откуда берётся неточность?
  • Как бороться с погрешностями?
  • Бесконечность и прочие вкусности
  • Представление чисел с плавающей запятой в памяти
  • Реализация арифметических операций
  • Ссылки

Как узнать, что используются числа с плавающей запятой?

В языках программирования со строгой типизацией существуют, как правило, специальные типы данных для чисел с плавающей запятой (float/double/long double в Си, single/double/extended в Паскале). Если в вычислении участвует хотя бы одна переменная или константа с плавающей запятой, все другие числа тоже преобразовываются к этому типу.

В языках без строгой типизации, как Perl, PHP или JavaScript, заметить использование чисел с плавающей запятой сложнее. Для программиста все числа выглядят одинаково, переключение с целочисленных типов на типы с плавающей запятой происходит автоматически. Можно исходить из того, что используются операции для чисел с плавающей запятой, если какая-нибудь из участвующих переменных содержит дробную часть или её значение выходит за пределы диапазона целых чисел. Но бывают и случаи, когда числа с плавающей запятой используются для целочисленных значений:

$a = 0.5;$a *= 2;

Здесь переменная $a равна единице (это покажет и сравнение, в отличие от примера в начале статьи), но её значение всё равно хранится как число с плавающей запятой потому, что её значение раньше содержало дробную часть.

Некоторые языки, к примеру dBase, содержат дополнительный тип данных для чисел с фиксированной запятой. Они предназначены для более точных расчётов, к примеру в бухгалтерии. По сути, это "обычные" целые числа, у которых несколько последних знаков определены, как знаки после запятой. Соответственно, они и ведут себя так же, как целые числа. Всё, что написано в этой статье — не о них.

Откуда берётся неточность?

Основная причина неточности при использовании чисел с плавающей запятой в том, что компьютер не может работать с бесконечными дробями, которые мы знаем из математики — для них понадобилось бы бесконечное количество памяти. Это и понятно, мы тоже округляем числа до какого-то знака, когда имеем дело с десятичными дробями. Но это не объясняет приведённого в начале статьи примера — ведь там всего один знак после запятой?

Существует ещё один фактор — компьютер считает не в десятичной системе, а в двоичной. А если представить 0.1 как двоичную дробь, то она окажется периодической: 0.0(0011). Соответственно, в памяти компьютера число 0.1 представлено как 1.1001100110011001100110011001100110011001100110011010b * 2^(-4). Обратите внимание на округление в конце числа. Если перевести его обратно в десятичную систему, то получится 0.10000000000000000555111512.

Почему тогда показывается не это число, а 0.1? Дело в том, что числа с плавающей запятой на выводе всегда округляются. Perl, к примеру, по умолчанию выводит только пятнадцать значащих знаков. Но, если использовать функцию printf(), можно вывести до семнадцати значащих знаков, и тогда мы вдруг увидим 0.10000000000000001. В некоторых браузерах метод Number.toPrecision() JavaScript'а позволяет выводить числа даже с пятьюдесятью значащими знаками.

Так почему всё-таки 1.1 − 1 не равно 0.1? Если посмотреть значение числа 1.1 − 1, то мы увидим 0.10000000000000008881784197. Оно, очевидно, не равно компьютерному представлению числа 0.1, хотя при стандартном округлении и выглядит точно так же. Разница объясняется тем, что мы считали с округлённой версией числа 1.1.

Как бороться с погрешностями?

Если использовать числа с плавающей запятой, то погрешность результатов оценить сложно. До сих пор не существует удовлетворительной математической теории, которая позволяла бы это делать. С другой стороны, погрешность при операциях с целыми числами оценивается легко. Поэтому одна возможность избавиться от неточностей — это использование чисел с фиксированной запятой, упомянутых выше. Эта возможность нашла наиболее широкое применении в финансовых программах, где заранее известно нужное количество знаков после запятой. Для других же приложений ограничения чисел с фиксированной запятой часто оказываются проблематичными — с их помощью нельзя представить ни очень большие числа, ни очень маленькие.

Вместо этого можно дальше использовать числа с плавающей запятой, но при этом всегда учитывать, что возможны неточности. Так, при выводе результаты надо непременно округлять, причём часто автоматического округления недостаточно, и округление приходится задавать явно. Также надо быть осторожным с операцией сравнения. Можно округлять числа перед сравнением, либо, что более эффективно, смотреть на разницу чисел:

if (abs($a - $b) < 0.000001 * min($a, $b)){ print "$a равно $b";}else{ print "$a не равно $b";}

Проблема здесь, опять же, состоит в том, что сложно оценить размер возможных погрешностей — неизвестно, с какой максимальной точностью можно считать, чтобы погрешности не попали в результат. Выражать это число через размер переменных, с которыми мы работаем, как это сделано в примере — первый шаг, но он не решает всех проблем.







Дата добавления: 2015-10-12; просмотров: 370. Нарушение авторских прав; Мы поможем в написании вашей работы!



Картограммы и картодиаграммы Картограммы и картодиаграммы применяются для изображения географической характеристики изучаемых явлений...

Практические расчеты на срез и смятие При изучении темы обратите внимание на основные расчетные предпосылки и условности расчета...

Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...

Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...

Понятие массовых мероприятий, их виды Под массовыми мероприятиями следует понимать совокупность действий или явлений социальной жизни с участием большого количества граждан...

Тактика действий нарядов полиции по предупреждению и пресечению правонарушений при проведении массовых мероприятий К особенностям проведения массовых мероприятий и факторам, влияющим на охрану общественного порядка и обеспечение общественной безопасности, можно отнести значительное количество субъектов, принимающих участие в их подготовке и проведении...

Тактические действия нарядов полиции по предупреждению и пресечению групповых нарушений общественного порядка и массовых беспорядков В целях предупреждения разрастания групповых нарушений общественного порядка (далееГНОП) в массовые беспорядки подразделения (наряды) полиции осуществляют следующие мероприятия...

Дренирование желчных протоков Показаниями к дренированию желчных протоков являются декомпрессия на фоне внутрипротоковой гипертензии, интраоперационная холангиография, контроль за динамикой восстановления пассажа желчи в 12-перстную кишку...

Деятельность сестер милосердия общин Красного Креста ярко проявилась в период Тритоны – интервалы, в которых содержится три тона. К тритонам относятся увеличенная кварта (ув.4) и уменьшенная квинта (ум.5). Их можно построить на ступенях натурального и гармонического мажора и минора.  ...

Понятие о синдроме нарушения бронхиальной проходимости и его клинические проявления Синдром нарушения бронхиальной проходимости (бронхообструктивный синдром) – это патологическое состояние...

Studopedia.info - Студопедия - 2014-2024 год . (0.009 сек.) русская версия | украинская версия