![]() |
Модераторы: Daevaorn |
![]() ![]() ![]() |
|
oper54 |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 217 Регистрация: 13.5.2005 Репутация: 1 Всего: 1 |
Доборое время суток...
Вот интересно стало как вы глядят числа на низком уровне... 1. Как выглядит отрицательное число(по битам) 2. Как выглядит число с плавающей запятой(по битам) ![]() |
|||
|
||||
jonie |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 15 Всего: 118 |
почитай стандарт представления чисел с плавающей точкой....скажем в MSDN все написано даже... да и поиск тоже даст результаты.
на вскидку могу вспомнить: (проверить стоит) signed integer - старший бит - знаковый(1=="-",0=="+") все остальное - число. в беззнаковом этот бит отдается под число. float - 8 бит экспонента, 23 - мантисса, старший бит опять же знак double - 11 бит экспонента, 52 - мантисса, старший бит знаковый. ........IEEE читай ....... ну или там хотяб (особо обращаем внимание на хранение экпоненты)...: http://www.intuit.ru/department/se/pbmsu/2/2.html -------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
takedo |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 501 Регистрация: 1.6.2005 Репутация: 1 Всего: 3 |
В конце концов посмотри по битам сам через маску:
Приведу пример для самого простого типа, а дальше по аналогии: char data; bool bits[8]; bits[0] = data&0x80; bits[1] = data&0x40; ... Ну и так далее. Единственное, что может быть наоборот старший и младший биты, но для твоей задачи это неважно. ![]() -------------------- я не гольфист - я хоккеист |
|||
|
||||
W4FhLF |
|
||||||||||||||||||
![]() found myself ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2831 Регистрация: 2.12.2006 Репутация: 20 Всего: 121 |
Что-то в последнее время стала популярна эта тема, отпарвлять читать маны интела смысла нет, поэтому я сейчас постараюсь довольно доступно разъяснить эту тему.
Отрицательное целое или с плавающей точкой? Целые числа делятся на отрицательные и положительные условно, в памяти никакого деления на положительные и отрицательные нет, допустим int(в 32х разрядной системе) допускает значения от -2147483648(0x80000000) до 2147483647(0x7FFFFFFF) или от -2^31 до 2^31 - 1. Отсюда следует, что например -1 запишется в памяти как 0xFFFFFFFF, -2 как 0xFFFFFFFE. Давай убедимся в этом на практике и продизассемблируем такую программу:
Прежде всего нас интересуют первые три операции присвоения, компилятор их скомпилирует в машинный код, а переведя этот машинный код на язык ассемблера(продизассемблировав его) мы увидим такие эквивалентые, с точки зрения процессора, команды:
Операция MOV DWORD PTR DS:[402008],FFFFFFFE на языке ассемблера дословно значит: присвоить ячейке памяти по смещению 0x402008 значение размером 4 байта(DWORD) равное 0xFFFFFFFE. Каждую строку я закоментировал. В первой операции присвоения используется OR только потому, что она занимает меньше места, чем MOV, но она эквивалентна ей в данном случае. Отсюда можно вывести простую закономерность, фактическое представление любого отрицательного целого числа в памяти можно получить по формуле: RealValue = 0xFFFFFFFF - b + 1 Где b - это абсолютное значение отрицательного числа. Для удобства в процессоры была включена специальная команда для этого - NEG. Выдержка из книги Юрова:
Команда эта так же используется компилятором при иневертировании положительного знака целых чисел:
Такой вот код компилятор преобразует в следующее машинное выражение:
Как видишь, сначала происходит присвоение положительного числа, а после изменение знака специальной командой процессора.
Тут всё сложнее. Дело в том, что работой с flat point числами занимается арифметический сопроцессор - FPU. Он имеет свои команды, свои регистры(при этом основными являются регистры R0-R7, состовляющие основу модели сопроцессора - стек сопроцессора. Размерность каждого из этих регистров 80 бит, обрати внимание на это). Набор функций и форматы данных с которыми работает сопроцессор описывает стандарт IEEE 754 (http://babbage.cs.qc.edu/IEEE-754/References.xhtml). При этом формат данных с плавающей запятой делится на 3 группы: Короткий Длинный Расширенный Отличаются они между собой прежде всего разрядностью, первый занимает в памяти 4 байта, второй 8 байт, а третий 10. В общем случае вещественное число или число с плавающей точкой имеет следующую структуру в памяти: [знак][экспонента][мантисса] От размера экспоненты и мантиссы как раз зависит формат данных. В С/С++ мы привыкли использовать два формата: float и double. Первый является коротким форматом представления вещественного числа(под экспоненту отводится 8 бит, под мантиссу 24), второй длинным(под экспоненты отводится 11 байт, под мантиссу 53). Под знак во всех форматах отводится 1 бит. Теперь переходим к практике, я буду разбирать всё на примере float, с остальными форматами всё естественно аналогично только с учётом размера составных частей. Скомпилируем такой пример и посмотрим как с ним работает процессор:
Смотрим во что превращается команда присвоения:
Ага, ну вот, то о чём я и говорил. Сопроцессор использует свой набор команд, поэтому непосвящённым они кажутся совсем непривычными. При этом в них нет ничего необычного. Первая команда загружет нв верхушку стека сопроцессора значение из памяти, а вторая кладёт значение с вершины по адресу 0x402000(очевидно, что это смещение в памяти нашей переменной a). При этом если мы посмотрим по адресу 0x403094 мы не увидим ничего даже отдалённо напоминающего -7.770000, вместо этого мы видим следующее значение по этому адресу: 0xC0F8A3D7. Вот это и есть представление числа -7.770000 в памяти, таким его видит процессор. Основываясь на вышесказанном, конвертируем это число в последовательность битов и получаем: 11000000111110001010001111010111 Раскладывая его на составляющие получаем: 1 - знак. (0 - число положительное; 1 - отрицательное) 10000001 - Экспонента. Показывает сколько порядков надо взять у мантиссы, чтобы получить целую часть числа. 11110001010001111010111 - Мантисса. Начнём постепенно строить модель нашего числа. Нам известно, что число отрицательное, теперь нужно перевести экспоненту в нормальный вид. Берём её значение, оно равно 129 и чтобы получить кол-во битов целой части отнимаем от этого числа 127, получаем 2(на самом деле устройство экспоненты это довольно обширная тема, я в подробности вдаваться не стал). Берём у мантиссы 2 бита в счёт целой части: 11.110001010001111010111 Но 11b это не 7, скажите вы, и будете правы. На самом деле перед этим я должен был сказать, что при преобразовании в число с плавающей точкой в мантиссу уходит всё до последнего бита, равного 1. Этот бит всегда есть и поэтому его нет смысла хранить в памяти, он добавляется в "уме". Вы должны были обратить на это внимание, когда я описывал формат и сказал, что размер мантиссы у float - 24 бита, а когда мы разделили на составляющие наше число получили 23 бита, перед этими 23 битами стоит ещё один. Учитывая это получаем: 111.110001010001111010111 Итак, целая часть 111b, а это как раз 7 в десятичной системе. Осталось привести к нормальному виду дробную часть: 110001010001111010111, но и тут наши приключения не заканчиваются ![]() DrobValue = Drob(1) * 2^(-1) + Drob(2) * 2^(-2) + Drob(3) * 2^(-3) + Drob(4) * 2^(-4) ... Drob(n) * 2^(-n) Где n кол-во бит в оставшейся мантиссе. Или, если применить к нашему случаю, получаем: DrobValue = (1 * 2^(-1)) + (1 * 2^(-2)) + (0 * 2^(-3)) + (0 * 2^(-4)) ... 1 * 2^(-21) Если проссумировать всё, как написано выше, получим: 0,769999980926514 И вот тут открывается ещё одна тайна ![]() Связывая в одно всё вышесказанное, значение 0xC0F8A3D7 превращается в отрицательное число с плавающей точкой, где целая часть равна 7, а дробная 769999980926514: -7.769999980926514 Ну вот, надо же... Целая "статья" получилась. На полноту описание конечно же не претендует, я и половины особенностей форматов FPU не рассмотрел, однако постарался изложить всё просто и доступно, подврепив примерами. Учите господа ассемблер и тогда для Вас всё будет прозрачным и понятным ![]() Это сообщение отредактировал(а) W4FhLF - 25.12.2006, 14:36 -------------------- "Бог умер" © Ницше "Ницше умер" © Бог |
||||||||||||||||||
|
|||||||||||||||||||
oper54 |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 217 Регистрация: 13.5.2005 Репутация: 1 Всего: 1 |
спасибо, исчерпывающий ответ...
предлагаю, запостить эту статью в FAQ Это сообщение отредактировал(а) oper54 - 16.1.2007, 21:21 |
|||
|
||||
GIK |
|
|||
![]() Добрый человек ![]() ![]() Профиль Группа: Участник Сообщений: 985 Регистрация: 3.6.2005 Где: я только не небыв ал Репутация: 1 Всего: 14 |
Помница на уроках информатики это рассуждали так: Все нули становятся единицами, все единицы становятся нулями и прибавляется 1 (как число) Например число 1 выглядит так (в одном байте) 00000001 Число -1 будет таким 11111111 т.е. изменение 1 на 0 и наоборот + один Так вроде легче понять начинающему ![]() Поправте если не прав, а то я в это дело давно не влазил, хотя нужно знать хорошо ![]() -------------------- Математика=>пиво=> програмирование, три вещи последовательны и совместимы !!! Программирование - это не деятельнось! Программирование - это состояние души! Бог - самый крутой программист. |
|||
|
||||
SerpentVV |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 52 Регистрация: 27.11.2006 Где: Астрахань Репутация: 1 Всего: 1 |
Да, это называется "дополнительный код". От количества разрядов не зависит. Например, для 8 разрядов (битов) на примере +1 +1 = 00000001 инвертируем 11111110 прибавляем 1 в младший разряд 11111111 = -1 Проверяем +1 -1 = 0 1|1111111 единички переноса |00000001 |11111111 ---------------- 00000000 = 0 два числа не переводятся: 0 и самое маленькое отрицательное число... для 8 битов это 10000000 = -128 Числа +128 нет, есть +127 = 01111111 = +127 |
||||
|
|||||
![]() ![]() ![]() |
Правила форума "С++:Общие вопросы" | |
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |