Pull to refresh

Comments 37

Целые числа тоже хранятся в дополненным коде, а не с битовым знаком, как упомянуто в статье. IEEE-754 определяет разные виды NaN, об этом тоже стоит упомянуть.

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

чего сложного в NaN я не понял, а дополненный код вы и так описали т.к. порядок хранится в нем.

Остались нераскрытыми вопросы: почему и куда точка плавает? что за видеокарты в 60-70, из-за особенностей вычислений которых игры не работали?

Поддержу! Суть плавающей точки не раскрыта. Вроде как, «информатика для самых маленьких», но основной момент протерян в дебрях статьи за выдержками из всего подряд. Про видеокарты 60-х - огонь! Вся статья - кривой перевод, либо нейросетевой шедевр, имхо.

Спасибо за комментарий. Это происходит из-за того, что при переводе чисел из десятичной в двоичную систему счисления и обратно, теряется точность о которой говорилось выше. Добавил более точное уточнение!

Нет, плавающая запятая не потому, что при переводе "теряется точность", а потому, что количества знаков после запятой зависит от экспоненты, в отличие от fixed point, где количество знаков определено заранее. Запятая "плавает".

Все верно. "Теряется точность" это про то, почему у нас появляются проблемы при работе с определенными дробями из десятичной системы

Отличное объяснение. Легко воспринимается. Помогло, наконец, полностью понять идею. Критики предлагают добавлять в статью несущественные детали и исторические данные, которые будут только мешать дочитать статью до конца.

Спасибо за комментарий! Рад что статья была полезна!

Спасибо, доходчиво. Еще стоит привести пример с большими числами, что бы показать что скажем +1.0 может оставить число без изменений, как можно реализовать операции над числами с плавающей запятой. Также можно объяснить как "накапливание" данных может влиять на точность.

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

куда это лучше добавить

В следующую статью, ибо вопрос про накапливание данных вполне самостоятельный.

Всё хорошо в объяснении, только вот экспонента (порядок) это степень двойки, а не десятки. Неплохо бы было объяснить и это момент.

А как двойка в двоичной системе записывается?

Моё замечание относится к тому, что хотя в общем идея чисел с плавающей точкой объяснена, только вот в IEEE-754 экспонента (e) - это показатель степени по основанию 2, а не по основанию 10, как в статье. Т.е. не 10^e, а 2^e.

А моё замечание относится к тому, что в двоичной системе нет цифры 2, поэтому 10^e и означает "по основанию 2"

Тогда это очень странная запись 10^2, где 10 это двоичное число, а 2 десятичное. Следовало писать 10^10 и внизу добавить маленькую 2 для указания системы счисления, ровно как было указано у первого множителя. Либо уж писать 2^2 и не путать людей

А где в статье такое? Я вижу 10^2 в значении "десять в квадрате".

Очень сложно читать. Основания чисел пишутся в нижнем регистре, а не в верхнем, в котором пишутся степени. В тексте не поймёшь, где степени и где основания.

из-за ограничений математики

Это в корне не верно. Математика здесь ничем не ограничивает. Ограничение возникает из модели представления вещественного числа с двоичным основанием. Ну или можно было сказать из-за ограничений двоичной арифметики.

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

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

И это не говоря уже о иррациональных числах.

Сейчас, принципиально не существует никакой возможности, реализовать на современных вычислительных мощностях корректную "арифметику". И судя по тому, что мы знаем о физике - никогда не будет.

Я вот не понял про перевод в десятичную систему. Каким образом 1*2-1 превратилось в 0.5?

физически невозможно записать число в периоде, который потенциально бесконечный

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

Сама по себе статья, конечно, полезна. Но:

  • очень много ошибок в плане русского языка;

  • не совсем корректная отсылка к целым числам в плане знака числа: целые-то хранятся в дополнительном коде, а вещественные -- в прямом, о чём стоило б сказать явным образом; кроме того, у вещественных есть знак мантиссы (собственно знак числа), а есть знак порядка (замаскированный из-за использования смещённого порядка);

  • некоторый бардак с хронологией, из-за чего возникает впечатление, что некоторые игры не работали на некоторых видюхах в 1960-70-е, хотя сие имело место, на самом-то деле, в 2000-х, и не из-за формата представления вещественных чисел как такового (IEEE 754 уж давно стандартом стал), а из-за разного набора обеспечиваемых аппаратных возможностей. DirectX, конечно, в каждой своей версии требует наличия некоего минимума, но производители вольны добавлять необязательные возможности по своему усмотрению;

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

  • можно было б для полноты картины упомянуть, что вещественные числа не всегда представляются как в степени 2 -- например, в Системе 360 используется степень 16, из-за чего при равном числе битов диапазон много шире, а вот точность хуже;

  • говоря о IEEE 754, неплохо б сказать, что лишь часть стандарта обязательна к реализации. Так, в зависимости от платформы выбор способа округления может предоставляться, а может и не предоставляться, ненормализованные числа могут поддерживаться, а могут превращаться в нуль, и т.д. Понятно, что статья вводная, но упомянуть о потенциальных проблемах стоило б, чтоб, кому оно интересно или надо, стал бы копать вглубь (и знал бы, в какую именно сторону).

Спасибо за статью. Вспомнил давно забытый материал уроков информатики, а так как в IT только пробую переквалифицироваться, думаю, это не лишнее :)

Я позволю себе обратить внимание, на ряд существенных неточностей материала, которые переворачивают многое с ног на голову.

Кроме этого, я хотел бы сразу обратить внимание, что читая этот материал, может сложиться ложное ощущение, будто бы описанная проблема связана именно со стандартом или прости господи с представлением чисел в бинарномн виде.

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

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

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

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

Сам по себе стандарт не держался в тайне - иначе каким простите образом, кто-то мог бы обсуждать и выбирать какой стандарт лучше?

Данный стандарт в последствии получил название IEEE-754. Это был стандарт описывающий способ хранения и работу чисел с плавающей точкой, который, казалось бы, раз и навсегда решил все проблемы связанные с числами с плавающей точкой. 

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

Разработчики стандарта IEEE-754 начали думать, как же решить эту проблему, и в итоге столкнулись с не идеальностью нашей системы исчислении и математики в целом, которую не удалось решить вплоть до сегодняшнего дня.

Еще раз. Никто не сталкивался с этой проблемой. Эта проблема известна со времен Пифагора. Разработчики решали совсем другие проблемы.

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

До этого момента, не было никаких гарантий того, что используя тот или иной вариант реализации подобной математики, результат бы отвечал ожидаемому. Разработчики стандарта IEEE754, строгостью стандарта, дали математику гарантии того, что расчет на бумаге согласно стандарту будет строго соответствовать результату в ЭВМ.

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

некоторые дроби представленные в десятичной системе счисления невозможно из-за ограничений математики представить в двоичном виде

Ровно как та-же самая проблема есть и в десятичной системе. От того, что вы измените основание для своего исчисления НИЧЕГО НЕ ИЗМЕНИТСЯ, кроме того множества чисел, которые в случае одного основания будут точнее в сравнении с другим основанием и наоборот.

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

Интересно было-бы услышать мнение автора о том, как именно его руководство отличается от типичного обьяснения стандарта IEEE754. Потому как далее по тексту, идет совершенно типичное ничем не отличающееся от типичного математического пояснения с математическими формулами и т.д. и т.п.

Как, на мой взгляд, следовало бы, рассказывать о заявленной проблеме

Давайте разделим число 13 на 7: 13 / 7 = 1,857142857142857
А теперь давайте представим, что мы можем делить только на цело: 13 / 7 = 1
Каким образом, в этих условиях, можно получить результат, который бы показал нам дробную часть?

И немного поразмышляв, мы получим простое решение - если я хочу учесть только один знак после запятой, то я бы умножил сначала 13 на 10, а потом выполнил бы тоже самое деление на цело: 13 * 10 / 7 = 130 / 7 = 18

Обратим внимание, что теперь, нам чтобы отделить дробную часть от целой, нужно просто поставить точку, между 1 и 8

А если нужно учесть два знака после запятой?

13 * 100 / 7 = 1300 / 7 = 185

А если три знака?

13 * 1000 / 7 = 13000 / 7 = 1857

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

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

Например:
32 бита позволяют нам оперировать числами в диапазоне от 0 до 4млрд ( 4294967295 )
то есть чтобы иметь какую то математику в пределах этого диапазона, да еще и с точностью хотябы до трех знаков после запятой, согласно нашему алгоритму, нам потребуется это число увеличить в 1000 раз 4294967295 * 1000 что потребует уже 42 бита на обеспечение результата. А если до 6 знака то уже потребуется 52 бита. И это только для чисел в диапазоне от 0 до 4 млрд.

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

А теперь представьте себе 1970 год, где даже 16 бит на число - это супер роскошь (16 бит это максимум 65536). Но при этом, мы хотим получить устройство, которое может считать намного больше чем 65тысяч.

С этого момента начинается рассказ о разработке разных стандартов представления чисел с плавающей точкой, при этом сам термин плавающая точка, уже понятеy человеку ( точка плавает от точности).

И наиболее простым, без лишней математики, наглядным пояснением именно стандарта IEEE754, я считаю пояснение от Fabien Sanglard в его книжке Game Engine Black Book: Wolfenstein 3D. На хабре был кажется перевод главы из этой книжки именно про это.


Спасибо за комментарий! Да, вы правы!

Цель этой статьи - дать фундаментальные знания новичкам в программировании о том, как с этими числами взаимодействует процессор.

Без точных и сложных уточнений, а объяснить «на пальцах». В интернете и так много материалов на эту тему. Те подробности о которых говорите вы, на него на другую аудиторию нацелены

Почему при сложении 0.1 + 0.3 получается ответ ~0.40000000000000003?

При сложении 0.1 и 0.3 получается 0.4. Это при сложении 0.1 и 0.2 получается 0.30000000000000004.

"для гуманитариев" мощно звучит, спасибо за понимание, респект.

Sign up to leave a comment.

Articles