. Java и числа. От простого к сложному
Java и числа. От простого к сложному

Java и числа. От простого к сложному

Наш постоянный читатель Кирилл Сергеев делится с нами особенностями хранения чисел в памяти компьютера, используя примеры из Java. В первой части статьи он ярко и сочно рассказывает, как числа влияли на человечество на заре веков, а во второй объясняет, в каких форматах память компьютера хранит разные виды чисел, о числах с плавающей точкой в java и о многом другом интересном. Желаем приятного чтения!

Числа сквозь века: мифы, легенды, развитие

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

Сначала числа использовались исключительно для определения количества тех или иных однотипных предметов. Это были натуральные числа – как и предметы, счет которым с их помощью вели. Три шкуры, пять наконечников для стрел, два топора. Один, два, три, …, 15 членов общины, а дальше – «нас тьмы, и тьмы, и тьмы. Попробуйте, сразитесь с нами!».

Для нужд первобытного человека таких чисел хватало вполне. Но прогресс не удержать. Люди научились обменивать «что-нибудь ненужное» на предметы, необходимые в быту. А когда зародилась примитивная торговля, тут же появились профессиональные менялы и ростовщики. Чтобы начать охотиться, человек сначала должен где-то получить топор, копье или гарпун. Старшие товарищи уже обладают этими предметами. Так почему не одолжить у них орудие труда в счет будущей добычи или улова? Люди научились давать и брать в долг. Но если вы должны кому-то три беличьи шкурки, а у вас нет ни одной – получается, у вас минус три беличьи шкурки. Сначала не было топора, не было и шкурок. То есть – «все по нулям». Теперь – один топор и минус три охотничьих трофея. Люди научились считать количество целых неделимых предметов: как положительное, так и отрицательное. Так появились целые числа.

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

Хитрая лиса поселилась у медведя и тайком по вечерам «хавала его ништяки» – опорожняла кадку с медом. Медведю она говорила, что уходит то на родины, то на крестины. А сама забиралась на чердак и лакомилась медком. В первый вечер она съела четверть кадушки и вернулась в дом. Медведь поинтересовался, как ребенка назвали. Лиса и говорит: «Верхушечкой». Во второй вечер лиса слямзила еще четверть кадки, осталась половина. Лиса вернулась в дом и на вопрос медведя ответила, что ребенка назвали Середочкой. В третий вечер лиса разъелась до того, что навернула всю оставшуюся половину меда. Медведю с гордостью сообщила, что ребенка окрестили Поскребушком. И то правда, мало ли чудных имен на свете?

Сказка – ложь, да в ней намек… Лиса не просто объедала медведя. Делала она это «дискретно», в три подхода, каждый раз съедая часть целого. Сначала она осилила четверть кадки, после этого осталось три четверти. Во второй раз лиса вновь съела четверть. Кадушка стала наполовину пустой. А может быть, наполовину полной. Как бы то ни было, осталась половина. В третий раз лиса до того распробовала медок, что съела всю оставшуюся половину разом. В результате лисьей «рационализации» целая кадка натурального меда превратилась в ноль. Люди тем временем освоили рациональные дроби.

Человек рос. Росли города. Развивались цивилизации: шумерская, египетская, древнегреческая. И такие там жили люди, что хлебом их не корми, а дай построить зиккурат, пирамиду или храм Артемиды. Касательно храма Артемиды – если не построить, то уж хотя бы сжечь.

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

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

Сегодня человек при операциях с числами использует не единичную систему счисления, пальцы на руках и ногах, набор косточек или камушков, не устный счет, не абак, не хитроумные механические счетные машины. Компьютер теперь – не роскошь, а средство вычисления. Предлагаю рассмотреть, как хранятся числа в памяти компьютера. Особый упор сделаем на рассмотрение формата хранения вещественных чисел. Посмотрим, как это делается, и разберем примеры на современном, ультрановомодном и востребованном языке программирования высокого уровня – Java.

Как хранятся числа в памяти компьютера

Формат представления целых чисел в Java С целыми положительными числами все предельно просто. Выделяется n-бит на число. Число в java переводится в двоичную систему счисления. Затем записывается последовательно с нулевого бита по n-1 бит. Старшие не значащие разряды обнуляются.

Рассмотрим пример. Пусть есть целое число 389. Как определить, в каком формате хранится это число?

Переведем число 38910 в двоичную систему счисления.

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

Для проверки результата выполним небольшой код с выводом чисел на Java:

Результат вычислений совпал с результатом работы программы.

Формат хранения целых отрицательных чисел в java уже интересней. Отрицательное целое число представлено в дополнительном коде. Для перевода числа в дополнительный код нужно перевести его в двоичную систему счисления. Результат перевода представить в обратном коде. Для этого нужно поразрядно заменить все «0» на «1», а «1» на «0». К полученному результату нужно прибавить «1».

Рассмотрим пример. Дано целое число -386. Как определить, в каком формате хранится это число?

Переведем число 38610 в двоичную систему счисления.

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

Обр. код: 11111111111111111111111001111101

Представим результат в дополнительном коде.

Доп. код: 11111111111111111111111001111101 + 1 =

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

Для проверки результата выполним небольшой код на Java:

Результат вычислений совпал с результатом работы программы.

Формат представления вещественных чисел

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

0.7538 * 100 = 0.7538 * 10 2 , здесь мантисса – 0.7538, база (основание системы счисления) – 10, степень старшего разряда (разряд десятков) – 2,

0.007538 * 10000 = 0.007538 * 10 4 ,

7538.0 / 100 = 7538 * 10 -2 .

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

S – знак числа (мантиссы);

M – мантисса числа;

B – основание системы счисления, у нас 10;

Q – порядок числа.

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

Такое положение дел никак не может устроить программистов и инженеров, разрабатывающих электронно-вычислительную аппаратуру и программы для нее. Представление чисел с плавающей точкой в java должно быть унифицировано и стандартизировано. Таким стандартом является IEEE 754. Этот стандарт предусматривает, что число всегда хранится в нормализованной форме. Для чисел, представленных в двоичном коде, это означает, что точка будет сдвигаться влево или вправо до тех пор, пока в старшем бите мантиссы не окажется «1». При этом «1» в мантиссу не записывается. Она становится «неявной». Делается это для экономии одного разряда. Аппаратные средства устроены так, что они сами «помнят» о ее существовании и действуют с мантиссой так, как будто она там есть. То есть, мантисса будет иметь вид 1.M.

Показатель степени хранится в виде целого числа в коде со сдвигом 1023 или 127, зависит от точности. Это означает, что сдвиг точки для числа с двойной точностью хранится не в виде +2, -1, +6, а в виде 2+1023, -1+1023, 6+1023. Поэтому он всегда положительный. А оборудование само вычисляет, на сколько порядков переместить точку в мантиссе, и определяет направление сдвига. Разберем вышесказанное на примере.

Представим число 75.3810 в формате представления числа с плавающей точкой двойной точности. В Java это тип double. Построим это представление, исходя из определений и стандарта IEEE 754. В общем виде формат представления будет таким:

Под все число отводится 64 бита. Под знак – 1 бит. Под порядок – 11 бит. Под мантиссу – 52 бита.

Сначала переведем число 75.3810 в двоичную систему счисления. Перевод целой и дробной части осуществляется по-разному. Целая часть получается путем деления ее на 2 и записи остатков от деления в порядке, обратном их возникновению. Дробная часть получается путем ее умножения на 2 и записи целых частей в порядке их возникновения.

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

точка сдвинулась на шесть разрядов влево.

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

📎📎📎📎📎📎📎📎📎📎