Правда, всё несколько сложнее, потому что Unicode позволяет модифицировать символы и получать новые комбинации. То есть можно добавлять комбинируемые диакритические знаки и акценты (типичный пример - знак ударения). Хотя для многих комбинаций есть уже готовые коды, можно собирать новые символы самостоятельно. Грубо говоря, если взять букву "е" и прилепить к ней две точки, получится "ё". Ну, а букву
По факту, никакого строгого предела на количество символов в Unicode нет, хотя некоторая часть влезает в размерность 2 байта (то есть 65 536 штук). Вообще, валидных кодовых точек Unicode сейчас около 1 112 064, поэтому история о том, что Unicode оперирует только двумя байтами - миф.
Другой интересный вопрос - как эти кодовые точки должны быть представлены в памяти или в сообщениях (в тех же электронных письмах). Для этого используются кодировки. Первая идея была весьма простой - давайте хранить эти шестнадцатиричные числа в двухбайтовом виде! Тогда строка "Hello" будет представлена как
С другой стороны можно ведь написать
Выходит, форм хранения уже по крайней мере две. Как их тогда различать? Было предложено в начало каждой строки добавлять такую штуку как Unicode Byte Order Mark (то есть метку, сообщающую о порядке следования байтов). Она выглядела как "FE FF" или "FF FE" (во втором случае это значит, что нужно байты переставить местами).
Потом задались и другим вопросом - а чего нам хранить все эти нули? Это особенно актуально для англоговорящих разработчиков, которые в основном использовали коды до U+00FF. С их точки зрения выходило, что для хранения строк приходится тратить в два раза больше места непонятно зачем. Это не говоря о том, что с дедушкиных времён осталась гора документов в ANSI и ещё бог знает чём, и никому не хотелось это всё конвертировать. Короче, до какого-то момента Unicode не получал распространения, но часики-то оглушительно тикали, и ситуация становилась хуже.
Тогда в 2003 придумали концепцию UTF-8 (https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt), которую предлагалось использовать для хранения строк Unicode (то есть Unicode != UTF8). Как подсказывает цифра 8, создатели предложили хранить данных в октетах (байтах), но их число варьируется в зависимости от кодовой точки. Иными словами, от U+0000 до U+007F (от 0 до 127) используеся лишь один байт, от U+0080 до U+07FF - два байта, и так далее. Максимум - 4 байта информации, что позволяет закодировать весь миллион с хвостиком кодовых точек, имеющихся на данный момент.
Это весьма удобно для документов US-ASCII (US - United States), которые как раз используют символы до U+007F, то есть каждый символ как раз кодируется одним байтом. Из этого следует, что такие документы выглядят одинаково что в ASCII, что в Unicode, то есть 65 - это "А" в обоих случаях. Поэтому на самом деле
é можно представить как U+0065 (обычная латинская "e") и U+0301 (акцент, применяемый к предыдущей букве). В принципе, это значит, что из любой "нормальной" буквы можно получить странного франкенштейна.По факту, никакого строгого предела на количество символов в Unicode нет, хотя некоторая часть влезает в размерность 2 байта (то есть 65 536 штук). Вообще, валидных кодовых точек Unicode сейчас около 1 112 064, поэтому история о том, что Unicode оперирует только двумя байтами - миф.
Другой интересный вопрос - как эти кодовые точки должны быть представлены в памяти или в сообщениях (в тех же электронных письмах). Для этого используются кодировки. Первая идея была весьма простой - давайте хранить эти шестнадцатиричные числа в двухбайтовом виде! Тогда строка "Hello" будет представлена как
U+0048 U+0065 U+006C U+006C U+006F, а в памяти - просто как 00 48 00 65 00 6C 00 6C 00 6F. Называется такой подход UCS-2 (потому что байта два, сообщает cpt. Obvious) или UTF-16 (потому что 16 бит). Собственно, отсюда и пошёл миф, что в Unicode может быть только два байта, не более.С другой стороны можно ведь написать
48 00 65 00 6C 00 6C 00 6F 00 (то есть использовать low-endian или high-endian, про эти термины как-нибудь в другой раз поговорим) - тут уж в зависимости от того, с чем будет сподручнее работать процессору.Выходит, форм хранения уже по крайней мере две. Как их тогда различать? Было предложено в начало каждой строки добавлять такую штуку как Unicode Byte Order Mark (то есть метку, сообщающую о порядке следования байтов). Она выглядела как "FE FF" или "FF FE" (во втором случае это значит, что нужно байты переставить местами).
Потом задались и другим вопросом - а чего нам хранить все эти нули? Это особенно актуально для англоговорящих разработчиков, которые в основном использовали коды до U+00FF. С их точки зрения выходило, что для хранения строк приходится тратить в два раза больше места непонятно зачем. Это не говоря о том, что с дедушкиных времён осталась гора документов в ANSI и ещё бог знает чём, и никому не хотелось это всё конвертировать. Короче, до какого-то момента Unicode не получал распространения, но часики-то оглушительно тикали, и ситуация становилась хуже.
Тогда в 2003 придумали концепцию UTF-8 (https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt), которую предлагалось использовать для хранения строк Unicode (то есть Unicode != UTF8). Как подсказывает цифра 8, создатели предложили хранить данных в октетах (байтах), но их число варьируется в зависимости от кодовой точки. Иными словами, от U+0000 до U+007F (от 0 до 127) используеся лишь один байт, от U+0080 до U+07FF - два байта, и так далее. Максимум - 4 байта информации, что позволяет закодировать весь миллион с хвостиком кодовых точек, имеющихся на данный момент.
Это весьма удобно для документов US-ASCII (US - United States), которые как раз используют символы до U+007F, то есть каждый символ как раз кодируется одним байтом. Из этого следует, что такие документы выглядят одинаково что в ASCII, что в Unicode, то есть 65 - это "А" в обоих случаях. Поэтому на самом деле
"A".ord вернёт код буквы для UTF8 ("A".encoding почти наверняка сообщит как раз UTF8, во всяком случае, на любой нормальной системе). Да, небольшая проблема заключается в том, что всему остальному миру всё равно пришлось подстраиваться под новый стандарт, но что поделать, ka ir tas ir. Справедливости ради, английский - язык международного общения, плюс программы тоже пишутся латинскими буквами.👍5🔥4
Таким образом, появилось уже две кодировки: UTF8 и UTF16. Только в одной каждый символ занимал по 2 байта и надо ещё было разбираться, в какой последовательности эти байты записаны, а в другой многие "привычные" буквы занимали всего байт. Несложно догадаться, какая кодировка получила большую популярность.
Кстати, это не единственные варианты. Был такой зверь как UTF7, похожий на UTF8, но гарантировавший, что старший бит всегда будет содержать ноль. Это было сделано, чтобы текстовые сообщения, отправляемые через некие странные почтовые системы, доходили по-нормальному (иначе там могло быть такое, что часть информации обрезалась). Был и UCS4 (по факту, UTF32), который хранил данные по 4 байта, но это казалось слишком большим расточительством.
Собственно, теперь мы понимаем, что всяких кодировок действительно придумали изрядное количество. Отсюда растут ноги у таинственных вопросительных знаков, которые можно периодически встретить в некоторых случаях - это символы, которые в данной кодировке не получается отобразить. Грубо говоря, можно взять любую кодовую точку из Unicode и попытаться отобразить в ASCII, но далеко не для всех чисел получится найти соответствие, что и приведёт к появлению весёлых вопросительных знаков.
Из всего этого получается интересный вывод: строка фактически не будет иметь никакого смысла, если мы не знаем, какую кодировку она использует. Хотя мы всё равно используем термин "plain text", он оказывается довольно размытым, потому что неясно в какой-такой кодировке он "plain". Если в нём используются любые символы после 127, то ASCII тут тоже не поможет. Именно поэтому при создании веб-страниц в тэге
Кстати, с веб-страницами вообще очень интересная штука. Изначально планировалось, что кодировку будет сообщать веб-сервер при отправке HTML. Но ведь на одном сервере может лежать огромное количество страниц и сайтов, использующих самые разные языки. Значит, лучше, чтобы сама веб-страница говорила, что у неё за кодировка. Но позвольте, как тогда нам эту страницу начать читать, если мы не имеем представления о её кодировке? Выходит замкнутный круг - чтобы прочитать страницу, нужно знать кодировку, а чтобы знать кодировку, нужно начать читать страницу. К счастью, в начале файла HTML мы обычно используем "стандартные" символы до 127, а
Кстати, это не единственные варианты. Был такой зверь как UTF7, похожий на UTF8, но гарантировавший, что старший бит всегда будет содержать ноль. Это было сделано, чтобы текстовые сообщения, отправляемые через некие странные почтовые системы, доходили по-нормальному (иначе там могло быть такое, что часть информации обрезалась). Был и UCS4 (по факту, UTF32), который хранил данные по 4 байта, но это казалось слишком большим расточительством.
Собственно, теперь мы понимаем, что всяких кодировок действительно придумали изрядное количество. Отсюда растут ноги у таинственных вопросительных знаков, которые можно периодически встретить в некоторых случаях - это символы, которые в данной кодировке не получается отобразить. Грубо говоря, можно взять любую кодовую точку из Unicode и попытаться отобразить в ASCII, но далеко не для всех чисел получится найти соответствие, что и приведёт к появлению весёлых вопросительных знаков.
Из всего этого получается интересный вывод: строка фактически не будет иметь никакого смысла, если мы не знаем, какую кодировку она использует. Хотя мы всё равно используем термин "plain text", он оказывается довольно размытым, потому что неясно в какой-такой кодировке он "plain". Если в нём используются любые символы после 127, то ASCII тут тоже не поможет. Именно поэтому при создании веб-страниц в тэге
meta мы пишем кодировку (а если не пишем, то *стоило бы это делать*) - аналогичная история с письмами.Кстати, с веб-страницами вообще очень интересная штука. Изначально планировалось, что кодировку будет сообщать веб-сервер при отправке HTML. Но ведь на одном сервере может лежать огромное количество страниц и сайтов, использующих самые разные языки. Значит, лучше, чтобы сама веб-страница говорила, что у неё за кодировка. Но позвольте, как тогда нам эту страницу начать читать, если мы не имеем представления о её кодировке? Выходит замкнутный круг - чтобы прочитать страницу, нужно знать кодировку, а чтобы знать кодировку, нужно начать читать страницу. К счастью, в начале файла HTML мы обычно используем "стандартные" символы до 127, а
meta располагается в самом начале документа, так что её можно обработать без проблем, а потом уже использовать указанную кодировку. Если же meta нет, то некоторые браузеры могут пытаться "угадать" кодировку с помошью анализа встречающихся "нестандартных" символов, но иногда это может привести к тому, что вместо кириллических символов вылезут какие-нибудь китайские иероглифы. Поэтому, дамы и господа, мы с вами должны чтить кодировку.👍16🔥10🆒2
В этом уроке мы поговорим о разнообразных кодировках, которые используются в программном обеспечении (ASCII, UTF8, UTF16, UCS4), а также о стандарте Unicode. Поговорим о том, зачем нам нужно столько разных кодировок, откуда они взялись, чем отличаются, и какие являются наиболее актуальными. https://www.youtube.com/watch?v=E5uQeik0tdc
YouTube
Unicode, UTF8, ASCII, ANSI, UCS2 | Что это такое, как работает и зачем нужно?
В этом уроке мы поговорим о разнообразных кодировках, которые используются в программном обеспечении (ASCII, UTF8, UTF16, UCS4), а также о стандарте Unicode. Поговорим о том, зачем нам нужно столько разных кодировок, откуда они взялись, чем отличаются, и…
👍17
Что ж, друзья, очередной год завершается. Его итоги мы подвели на недавнем стриме, было круто, благодарю всех за участие 😄 Надеюсь, сегодня вы проведёте этот вечер (ночь) со своими близкими и/или друзьями в приятной обстановке, и что будущий год будет куда лучше уходящего.
Я не очень верю в историю про "как встретишь - так проведёшь", но пока у меня проходит вечер за книгой по C 😂 Впрочем, потом сделаю что-нибудь вкусное, может, сумеем сегодня дозаписать одну композицию.
Отличных всем праздников, очень скоро увидимся!
P.S. Желающие сделать небольшой подарок каналу могут забустить его вот тут: https://t.iss.one/dev_in_ruby_colors?boost
P.P.S. Ну, и одна из наших старых композиций, в относительно "новогоднем" стиле 🤪 https://youtu.be/EwKNZ0dXC9E
Я не очень верю в историю про "как встретишь - так проведёшь", но пока у меня проходит вечер за книгой по C 😂 Впрочем, потом сделаю что-нибудь вкусное, может, сумеем сегодня дозаписать одну композицию.
Отличных всем праздников, очень скоро увидимся!
P.S. Желающие сделать небольшой подарок каналу могут забустить его вот тут: https://t.iss.one/dev_in_ruby_colors?boost
P.P.S. Ну, и одна из наших старых композиций, в относительно "новогоднем" стиле 🤪 https://youtu.be/EwKNZ0dXC9E
YouTube
Dog & Butterfly - Heart cover
"Dog & Butterfly" was originally recorded by the "Heart" rock band. We created this track as a tribute to this great band.
🎄18❤4🎉2🍾2👍1
Подвели итоги, а теперь я понимаю, что Габриэль Гарсия Маркес был прав...
"Все ещё продолжается понедельник, который был вчера. Погляди на небо, погляди на стены, погляди на бегонии. Сегодня опять понедельник". Привыкший к его чудачествам, Аурелиано не обратил на эти слова внимания. На следующий день, в среду, Хосе Аркадио Буэндиа снова появился в мастерской. "Просто несчастье какое-то, — сказал он. — Погляди на воздух, послушай, как звенит солнце, все в точности как вчера и позавчера. Сегодня опять понедельник".
Да, похоже, что из понедельника мы так и не выбрались, и не выберемся ещё очень долго. Есть желание покричать вместе с прекрасной дамой из Исландии.
https://www.youtube.com/watch?v=ImyPz4tqPFU
"Все ещё продолжается понедельник, который был вчера. Погляди на небо, погляди на стены, погляди на бегонии. Сегодня опять понедельник". Привыкший к его чудачествам, Аурелиано не обратил на эти слова внимания. На следующий день, в среду, Хосе Аркадио Буэндиа снова появился в мастерской. "Просто несчастье какое-то, — сказал он. — Погляди на воздух, послушай, как звенит солнце, все в точности как вчера и позавчера. Сегодня опять понедельник".
Да, похоже, что из понедельника мы так и не выбрались, и не выберемся ещё очень долго. Есть желание покричать вместе с прекрасной дамой из Исландии.
https://www.youtube.com/watch?v=ImyPz4tqPFU
YouTube
Kælan Mikla - Kalt
Webpage: https://kaelanmikla.com
Facebook: https://www.facebook.com/Kaelanmikla
Bandcamp: https://kaelanmikla.bandcamp.com/album/k-lan-mikla
Spotify: https://open.spotify.com/artist/28meEMqGpDrolyQ9OVoDAH
Apple Music: https://music.apple.com/us/album/k%C3%A6lan…
Facebook: https://www.facebook.com/Kaelanmikla
Bandcamp: https://kaelanmikla.bandcamp.com/album/k-lan-mikla
Spotify: https://open.spotify.com/artist/28meEMqGpDrolyQ9OVoDAH
Apple Music: https://music.apple.com/us/album/k%C3%A6lan…
❤6😁1🤯1
Закон Амдала
Есть такой интересный закон, придуманный Джином Амдалом несколько десятилетий назад, его время от времени упоминают в контексте информационных систем, так что знать его суть не помешает.
Вообще, смысл данного закона очень простой: если мы "улучшаем" (ускоряем) *часть* некой системы, то общий эффект на быстродействие *всей* системы будет зависеть от того, насколько этот компонент был важен (то есть какой процент времени работа с ним занимает) и насколько мы его улучшили. Звучит как пассаж от капитана очевидность, но для оценки есть конкретная формула.
S - это то, насколько система в общем будет работать (в полтора, два раза и тд)
a - процент времени, который занимает работа конкретного компонента (выражается от 0.0 до 1.0)
k - фактор "улучшения"
Ну, к примеру, если мы знаем, что в нашей системе определённый компонент затрачивает 60% всего времени, необходимого для выполнения задачи, и мы улучшаем (ускоряем) этот компонент аж в 3 раза, то по факту S будет равно 1.67, то есть вся система ускорится чуть более, чем в полтора раза. То есть, казалось бы, мы очень серьёзно улучшили немалую часть системы, но окончательная выгода оказалась не такой уж большой.
Вообще говоря, этот закон может применяться далеко не только в информационных системах. К примеру, водитель грузовика знает, что ему нужно проехать 2500 километров, а скорость будет составлять условные 100 км/ч. Значит, вся поездка займёт 25 часов без учёта остановок.
Тогда вопрос - если мы предположим, что на участке пути в 1500 км можно ехать со скоростью в 150 км/ч, то насколько быстрее мы реально доедем? Ответить на этот вопрос несложно.
Участок в 1500 километров из всей дороги в 2500 км - это 60%, то есть
Если мы едем на этом участке 150 км/ч, то
Следовательно, финальное S равно 1.25, иными словами, приедем мы на 5 часов раньше.
Любопытно, что будет, если одну из частей системы мы сделаем настолько быстрой, что она практически не затрачивает никакого времени (это время настолько мало, что им можно пренебречь).
То есть что будет, если k равно бесконечности? В этом случае кусок
Есть такой интересный закон, придуманный Джином Амдалом несколько десятилетий назад, его время от времени упоминают в контексте информационных систем, так что знать его суть не помешает.
Вообще, смысл данного закона очень простой: если мы "улучшаем" (ускоряем) *часть* некой системы, то общий эффект на быстродействие *всей* системы будет зависеть от того, насколько этот компонент был важен (то есть какой процент времени работа с ним занимает) и насколько мы его улучшили. Звучит как пассаж от капитана очевидность, но для оценки есть конкретная формула.
S = 1 / ( (1 - a) + (a / k) )
S - это то, насколько система в общем будет работать (в полтора, два раза и тд)
a - процент времени, который занимает работа конкретного компонента (выражается от 0.0 до 1.0)
k - фактор "улучшения"
Ну, к примеру, если мы знаем, что в нашей системе определённый компонент затрачивает 60% всего времени, необходимого для выполнения задачи, и мы улучшаем (ускоряем) этот компонент аж в 3 раза, то по факту S будет равно 1.67, то есть вся система ускорится чуть более, чем в полтора раза. То есть, казалось бы, мы очень серьёзно улучшили немалую часть системы, но окончательная выгода оказалась не такой уж большой.
Вообще говоря, этот закон может применяться далеко не только в информационных системах. К примеру, водитель грузовика знает, что ему нужно проехать 2500 километров, а скорость будет составлять условные 100 км/ч. Значит, вся поездка займёт 25 часов без учёта остановок.
Тогда вопрос - если мы предположим, что на участке пути в 1500 км можно ехать со скоростью в 150 км/ч, то насколько быстрее мы реально доедем? Ответить на этот вопрос несложно.
Участок в 1500 километров из всей дороги в 2500 км - это 60%, то есть
a = 0.6.Если мы едем на этом участке 150 км/ч, то
k = 1.5, то есть в полтора раза быстрее.Следовательно, финальное S равно 1.25, иными словами, приедем мы на 5 часов раньше.
Любопытно, что будет, если одну из частей системы мы сделаем настолько быстрой, что она практически не затрачивает никакого времени (это время настолько мало, что им можно пренебречь).
То есть что будет, если k равно бесконечности? В этом случае кусок
a / k в формуле уходит, потому что значение будет стремиться к нулю. Тогда вся формула превращается в S = 1 / ( 1 - a ). Следовательно, даже если мы возьмём 60% всей системы и ускорим её так, что она будет выполнять необходимые операции мгновенно, всё равно общий рост производительности будет только 2.5 (т.к 1 / 0.4). Вот такая, понимаешь, загогулина.❤11🔥7👍2
Коллеги из sitepoint прислали новый глобальный опрос для разработчиков (проводится каждый год). Думаю, снова поучаствовать, и вообще everyone is welcome - там вроде какие-то подарки обещают. Не реклама, просто хороший повод составить какую-никакую картину о мире it https://www.developereconomics.net/?member_id=sitepoint
Developer Economics
Developer Nation Survey | Developer tools, apps, design, games
The Developer Nation survey is run by independent analyst firm SlashData, reaching over 30,000+ developers in 165 countries annually
✍2👌1
Big-endian и little-endian: порядок следования байтов и причём тут Гулливер
Частенько в руководствах и документации можно встретить термины big-endian и little-endian - да хотя бы в предыдущей записи про кодировки. Но что они вообще значат? На самом деле, всё довольно просто - это буквально война тупоконечников и остроконечников (я серьёзно).
Когда-то давно Джонатан Свифт написал роман "Путешествия Гулливера" - помните такой? Там была история, что, дескать, изначально варёные яйца лилипуты разбивали с тупого конца, но потом один из императоров умудрился себе порезать руку за завтраком, очищая яичко, после чего был издан указ: разбивать яйца только с острого конца, иначе будут применяться санкции.
Это привело к кровавым бунтам, тысячи человек пошли на казнь, так как, следуя заветам предков, всё равно разбивали яйца с тупого конца. По этой теме писались книги (хотя тупоконечную литературу запрещали), устраивались диспуты, и так далее, хотя в главном трактате некоего пророка было написано просто "разбивайте так, как вам больше нравится". Скажем прямо, в реальной жизни подобный идиотизм тоже встречается частенько. Это, конечно, едкая сатира, но она напрямую связана с нашим вопросом.
В оригинале "тупоконечники" - это big endians, а другая сторона - little endians. Отсюда и пошли эти термины - впервые в далёком 80-м году их употребил Дэнни Коэн, один из участников проекта ARPANet. Это была во многом шутка, но в итоге словечки прижились.
Предположим, у нас есть шестнадцатеричное число
Следовательно, на всё это число потребуется 4 байта или 32 бита (это называется "слово", "word"). Если принять, что каждый адрес в памяти указывает на 8 бит информации, то наше число займёт адреса с
Можно сделать так:
но можно сделать и так:
То есть сначала может идти "самая значимая" пара (это
Поэтому подход, когда наиболее значимый байт идёт на первой позиции, называется "big endian" или BE (большинству из нас это куда привычнее), а "little endian" или LE - это когда сначала идёт наименее значимый байт. В разных машинах может задействоваться один из двух подходов, к примеру, многие устройства (но не все) от Oracle используют режим big endian. Впрочем, есть чипы вида bi-endian, которые умеют работать в обоих режимах.
Кроме того, многое зависит от самой операционной системы. Так, Android и iOS используют именно little-endian, с Windows в целом аналогичная история. В сетевых же протоколах, напротив, используется вариант big endian (принятую по сети информацию может потребоваться переставить обратно в вариант little endian, в зависимости от машины).
Дело же в том, что с технической точки зрения нет особенной разницы, какой вариант представления использовать, равно как и нет разницы, с какой стороны разбивать яйцо. Для обычных программистов знать, какой режим использует ОС, особенно не нужно, потому что это должны учитывать компиляторы.
Однако этот термин может встречаться в других местах - например, в документации Solidity и Ethereum, где рассказывается о хранении данных в слотах (к примеру, uint хранится в виде big endian, равно как и селектор функции в calldata).
Интересно, что сказал бы по этому поводу Свифт...
Частенько в руководствах и документации можно встретить термины big-endian и little-endian - да хотя бы в предыдущей записи про кодировки. Но что они вообще значат? На самом деле, всё довольно просто - это буквально война тупоконечников и остроконечников (я серьёзно).
Когда-то давно Джонатан Свифт написал роман "Путешествия Гулливера" - помните такой? Там была история, что, дескать, изначально варёные яйца лилипуты разбивали с тупого конца, но потом один из императоров умудрился себе порезать руку за завтраком, очищая яичко, после чего был издан указ: разбивать яйца только с острого конца, иначе будут применяться санкции.
Это привело к кровавым бунтам, тысячи человек пошли на казнь, так как, следуя заветам предков, всё равно разбивали яйца с тупого конца. По этой теме писались книги (хотя тупоконечную литературу запрещали), устраивались диспуты, и так далее, хотя в главном трактате некоего пророка было написано просто "разбивайте так, как вам больше нравится". Скажем прямо, в реальной жизни подобный идиотизм тоже встречается частенько. Это, конечно, едкая сатира, но она напрямую связана с нашим вопросом.
В оригинале "тупоконечники" - это big endians, а другая сторона - little endians. Отсюда и пошли эти термины - впервые в далёком 80-м году их употребил Дэнни Коэн, один из участников проекта ARPANet. Это была во многом шутка, но в итоге словечки прижились.
Предположим, у нас есть шестнадцатеричное число
0x12345678, и оно размещается в памяти, начиная с адреса 0x100 (про организацию память можно глянуть стрим https://youtube.com/live/1B6lBJUQ5q8?feature=share). Каждая двойка шестнадцатеричных чисел (12, 34 и тд) занимает по 8 бит (потому что каждое число hex требует 4 бит, 0x0 = 0b0000, 0xf = 0b1111).Следовательно, на всё это число потребуется 4 байта или 32 бита (это называется "слово", "word"). Если принять, что каждый адрес в памяти указывает на 8 бит информации, то наше число займёт адреса с
0x100 по 0x103. Но вопрос в том, как их там разместить: справа налево или слева направо?Можно сделать так:
100 101 102 103
12 34 56 78
но можно сделать и так:
100 101 102 103
78 56 34 12
То есть сначала может идти "самая значимая" пара (это
0x12), а может, наоборот, наименее значимая (0x78). Казалось бы, выбор очевиден, но можно вспомнить хотя бы о том, что некоторые народы читают справа налево, а кто-то вообще пишет столбиком. Так что, на самом деле, всё не так однозначно™.Поэтому подход, когда наиболее значимый байт идёт на первой позиции, называется "big endian" или BE (большинству из нас это куда привычнее), а "little endian" или LE - это когда сначала идёт наименее значимый байт. В разных машинах может задействоваться один из двух подходов, к примеру, многие устройства (но не все) от Oracle используют режим big endian. Впрочем, есть чипы вида bi-endian, которые умеют работать в обоих режимах.
Кроме того, многое зависит от самой операционной системы. Так, Android и iOS используют именно little-endian, с Windows в целом аналогичная история. В сетевых же протоколах, напротив, используется вариант big endian (принятую по сети информацию может потребоваться переставить обратно в вариант little endian, в зависимости от машины).
Дело же в том, что с технической точки зрения нет особенной разницы, какой вариант представления использовать, равно как и нет разницы, с какой стороны разбивать яйцо. Для обычных программистов знать, какой режим использует ОС, особенно не нужно, потому что это должны учитывать компиляторы.
Однако этот термин может встречаться в других местах - например, в документации Solidity и Ethereum, где рассказывается о хранении данных в слотах (к примеру, uint хранится в виде big endian, равно как и селектор функции в calldata).
Интересно, что сказал бы по этому поводу Свифт...
🔥8👍5❤1
В этом уроке по Rust мы поговорим о том, как обрабатывать возникающие ошибки. Мы рассмотрим макрос panic!, методы unwrap, unwrap_or_else, expect, подход с match, а также оператор ? и обсудим, что такое Result и зачем он нужен. https://www.youtube.com/watch?v=ylLx0Mfm0u0
YouTube
Язык Rust, урок #8 | Обработка ошибок, оператор ?, error propagation, Result, match
В этом уроке по Rust мы поговорим о том, как обрабатывать возникающие ошибки. Мы рассмотрим макрос panic!, методы unwrap, unwrap_or_else, expect, подход с match, а также оператор ? и обсудим, что такое Result и зачем он нужен.
Таймкоды:
00:00 Введение
00:55…
Таймкоды:
00:00 Введение
00:55…
🔥13❤🔥2
Тёмная сторона Европы
Впервые я посетил Рим, Вечный город, аккурат 9 июля 2006 года. Откуда такая точная дата? Дело в том, что именно в этот день состоялся финал чемпионата мира по футболу, где Италия как раз обыграла Францию (думаю, вы помните тот удар Зидана, только не по воротам, а по лицу Марко Матерацци). Я уже как-то упоминал эту историю, это тогда отчим активно обсуждал происходящее на поле с местными мужиками, хотя по-итальянски не знал ни слова. 😂
В следующий раз я попал сюда спустя десять-одиннадцать лет, когда мы предприняли путешествие "дикарями" от столицы и до Франции на поезде с рядом остановок. Знаете, именно тогда я заметил неприятную вещь - в Италии, да и не только здесь, полиция совершенно ничего не может сделать с мелкими мошенниками и преступниками. В 2006 этого было как-то меньше, а теперь тут просто целая орда весьма странных людей, которые настойчиво впаривают *нечто*. Не хочется быть настолько конкретным, но зачастую это мигранты из Африки, и это, в общем-то, ни для кого не секрет.
Обычно это сводится к такой панибратской попытке заговорить зубы, что-нибудь всучить якобы в подарок, после чего следует просьба "помочь" - отказывать уже как-то невежливо. Впрочем, видел я и другую схему, сидя на лестнице какого-то очередного древнего собора. Идёт влюблённая пара, к ним подходит ловкий парень и вручает девушке розу - ну, вроде как за красивые глаза. Пара благодарит и идёт дальше, но парень не отстаёт и что-то активно говорит. Что именно - я не слышал, но и так можно догадаться, что-нибудь о прекрасной даме и тяжёлой жизни в Риме. В итоге, кавалер вынужден потянуться за кошельком и выдать "дарителю" евро-другой за подарок, ибо как-то не комильфо при своей возлюбленной выглядеть скрягой.
Да, такое сплошь и рядом. В Риме, во Флоренции, в Милане, в Турине... В Париже прямо около Эйфелевой башни мы наткнулись знаете на кого? На напёрсточников. 😂 Да, вот прямо сидят и облапошивают народ. Я поинтересовался у местных - как же так, почему их терпят? Ну, причина простая - с ними ничего получается сделать. Приходит полиция, а они убегают, да и всё. Ну, может штраф выпишут.
Такое происходит, конечно, далеко не везде, но всё же. Выйдя на одной станции метро, мы оказались буквально в самом центре сборища каких-то чернокожих ребят, которые слушали некоего оратора с мегафоном, агрессивно что-то орущего. В этом же районе мы видели молодых парней, которые с намёком стояли у стен домов (что они продавали, думаю, объяснять не нужно). Видел я и ребят, которые курили "травку" прямо у собора Сакре-Кёр, это на Монмартре.
И дело тут не в том, что есть какие-то "правильные" и "неправильные" приезжие. Просто есть ощущение, что многим из этих людей банально нечем заняться и нечем кормить семью, а определённая вседозволенность вообще расхолаживает. Сколько-то лет назад в ЕС считалось правильным привечать всех подряд, а потом уже разбираться, но теперь уже далеко не так - маятник качнулся в обратную сторону. Но, как мне кажется, всё это сейчас является бомбой замедленного действия, и нужно было в первую очередь думать, как и чем эти люди будут жить дальше. Впрочем, увидим.
Впервые я посетил Рим, Вечный город, аккурат 9 июля 2006 года. Откуда такая точная дата? Дело в том, что именно в этот день состоялся финал чемпионата мира по футболу, где Италия как раз обыграла Францию (думаю, вы помните тот удар Зидана, только не по воротам, а по лицу Марко Матерацци). Я уже как-то упоминал эту историю, это тогда отчим активно обсуждал происходящее на поле с местными мужиками, хотя по-итальянски не знал ни слова. 😂
В следующий раз я попал сюда спустя десять-одиннадцать лет, когда мы предприняли путешествие "дикарями" от столицы и до Франции на поезде с рядом остановок. Знаете, именно тогда я заметил неприятную вещь - в Италии, да и не только здесь, полиция совершенно ничего не может сделать с мелкими мошенниками и преступниками. В 2006 этого было как-то меньше, а теперь тут просто целая орда весьма странных людей, которые настойчиво впаривают *нечто*. Не хочется быть настолько конкретным, но зачастую это мигранты из Африки, и это, в общем-то, ни для кого не секрет.
Обычно это сводится к такой панибратской попытке заговорить зубы, что-нибудь всучить якобы в подарок, после чего следует просьба "помочь" - отказывать уже как-то невежливо. Впрочем, видел я и другую схему, сидя на лестнице какого-то очередного древнего собора. Идёт влюблённая пара, к ним подходит ловкий парень и вручает девушке розу - ну, вроде как за красивые глаза. Пара благодарит и идёт дальше, но парень не отстаёт и что-то активно говорит. Что именно - я не слышал, но и так можно догадаться, что-нибудь о прекрасной даме и тяжёлой жизни в Риме. В итоге, кавалер вынужден потянуться за кошельком и выдать "дарителю" евро-другой за подарок, ибо как-то не комильфо при своей возлюбленной выглядеть скрягой.
Да, такое сплошь и рядом. В Риме, во Флоренции, в Милане, в Турине... В Париже прямо около Эйфелевой башни мы наткнулись знаете на кого? На напёрсточников. 😂 Да, вот прямо сидят и облапошивают народ. Я поинтересовался у местных - как же так, почему их терпят? Ну, причина простая - с ними ничего получается сделать. Приходит полиция, а они убегают, да и всё. Ну, может штраф выпишут.
Такое происходит, конечно, далеко не везде, но всё же. Выйдя на одной станции метро, мы оказались буквально в самом центре сборища каких-то чернокожих ребят, которые слушали некоего оратора с мегафоном, агрессивно что-то орущего. В этом же районе мы видели молодых парней, которые с намёком стояли у стен домов (что они продавали, думаю, объяснять не нужно). Видел я и ребят, которые курили "травку" прямо у собора Сакре-Кёр, это на Монмартре.
И дело тут не в том, что есть какие-то "правильные" и "неправильные" приезжие. Просто есть ощущение, что многим из этих людей банально нечем заняться и нечем кормить семью, а определённая вседозволенность вообще расхолаживает. Сколько-то лет назад в ЕС считалось правильным привечать всех подряд, а потом уже разбираться, но теперь уже далеко не так - маятник качнулся в обратную сторону. Но, как мне кажется, всё это сейчас является бомбой замедленного действия, и нужно было в первую очередь думать, как и чем эти люди будут жить дальше. Впрочем, увидим.
👍22👎1😱1😢1
Как числа представлены в компьютере?
Это немаловажный вопрос, ответ на который состоит из нескольких частей. Дело в том, что у нас есть обычные неотрицательные целые числа (то есть от 0 и далее, без дробной части), просто целые числа (которые могут быть отрицательными или положительными), а также дробные, которые тоже могут быть отрицательными или положительными.
Проще всего, конечно, с целыми неотрицательными числами. Так как мы, опять же, работаем только с нулями и единицами, то привычные нам десятичные числа в компьютере могут быть закодированы в виде вектора, состоящего из набора 0-1, в общем случае:
Чтобы было проще, возьмём w = 4 и двоичное число
Это можно легко проверить, например, в Rust:
Таким образом, числу 10 соответствует вектор
При w = 4 минимальное число, которое мы можем закодировать
В общем, здесь всё просто и довольно очевидно. Интереснее становится, когда мы переходим к **целым числам, имеющим знак** (то есть они могут быть отрицательными). Где и как нам этот знак хранить? Раньше мы несколько обходили этот момент, говоря, что отдельный бит резервируется под хранение знака. Это некое упрощение.
На самом деле, вариантов представления чисел со знаком есть некоторое количество (в том числе, и случай, когда наиболее значимый бит просто говорит "есть минус или нет минуса"). Но, пожалуй, самый распространённый принцип - это так называемый "two's complement". Суть довольно проста.
У нас опять есть вектор из нулей и единиц указанной длины, предположим,
Все биты, за исключением наиболее значимого, интерпретируются как и раньше, то есть "привносят" в значение
Наиболее значимый бит (запишем его как
В нашем случае выходит:
Полученное значение затем просто суммируется с тем, что мы получили после обработки всех битов, кроме наиболее значимого:
Следовательно,
Если
Можно сказать, что при такой кодировке X "тянет" наше число в сторону отрицательных значений, а другие биты "тянут" его обратно на положительную сторону. Следовательно, наименьшее значение получится, когда X тянет нас в отрицательную сторону, но все остальные биты отсутствуют:
То есть при w = 4 наименьшее значение будет -8.
Максимальное значение получается, когда "знаковый" бит равен нулю, зато есть все остальные, которые тянут нас в положительную сторону:
Аналогично, при w = 8 диапазон будет от -128 до 127. К примеру,
вернёт
А теперь важный момент: мы понимаем, что **наш вектор из битов можно рассматривать по-разному**. Если мы считаем, что наиболее значимый бит используется для хранения информации о знаке, то, к примеру, число
Это немаловажный вопрос, ответ на который состоит из нескольких частей. Дело в том, что у нас есть обычные неотрицательные целые числа (то есть от 0 и далее, без дробной части), просто целые числа (которые могут быть отрицательными или положительными), а также дробные, которые тоже могут быть отрицательными или положительными.
Проще всего, конечно, с целыми неотрицательными числами. Так как мы, опять же, работаем только с нулями и единицами, то привычные нам десятичные числа в компьютере могут быть закодированы в виде вектора, состоящего из набора 0-1, в общем случае:
[ x(w - 1), x(w - 2), ... x(0) ]
w - длина вектора. Естественно, чем больше длина этого вектора, тем больше чисел мы можем с его помощью закодировать. В этом векторе наиболее значимый бит x(w-1) находится слева, а наименее значимый x(0) - справа. Если бит имеет значение 1, то он "привносит" в закодированное значение 2 ** i, где i - его порядковый номер. Собственно говоря, именно на этом факте строится процесс перевода из двоичного вида в десятичный.Чтобы было проще, возьмём w = 4 и двоичное число
1010. Наиболее значимый бит имеет порядковый номер 3 (считаем с нуля), также у нас установлен в значение 1 бит под номером 1. Следовательно:2 ** 3 + 2 ** 1 = 10
Это можно легко проверить, например, в Rust:
let number: u8 = 10;
println!("{number:b}");
Таким образом, числу 10 соответствует вектор
1010, но верно и обратное. Больше того, это соответствие "один ко одному", то есть в данном случае 1010 никакое другое число не представляет. Такая штука называется биекция.При w = 4 минимальное число, которое мы можем закодировать
0 0 0 0, то есть просто 0, а максимальное - 1 1 1 1, то есть 15 (аналогично, для w = 8 максимальное число - это 255).В общем, здесь всё просто и довольно очевидно. Интереснее становится, когда мы переходим к **целым числам, имеющим знак** (то есть они могут быть отрицательными). Где и как нам этот знак хранить? Раньше мы несколько обходили этот момент, говоря, что отдельный бит резервируется под хранение знака. Это некое упрощение.
На самом деле, вариантов представления чисел со знаком есть некоторое количество (в том числе, и случай, когда наиболее значимый бит просто говорит "есть минус или нет минуса"). Но, пожалуй, самый распространённый принцип - это так называемый "two's complement". Суть довольно проста.
У нас опять есть вектор из нулей и единиц указанной длины, предположим,
1 0 1 1.Все биты, за исключением наиболее значимого, интерпретируются как и раньше, то есть "привносят" в значение
2 ** i:2 ** 1 + 2 ** 0 = 2 + 1 = 3
Наиболее значимый бит (запишем его как
X) имеет специальное назначение, и он фигурирует в выражении:-X * (2 ** (w - 1))
В нашем случае выходит:
-1 * (2 ** 3) = -8
Полученное значение затем просто суммируется с тем, что мы получили после обработки всех битов, кроме наиболее значимого:
-8 + 3 = - 5
Следовательно,
1011 = -5.Если
X = 0, то формула выше обращается в ноль, и наше число будет неотрицательным. К примеру, 0 1 0 1 = 2 ** 2 + 2 ** 0 = 5.Можно сказать, что при такой кодировке X "тянет" наше число в сторону отрицательных значений, а другие биты "тянут" его обратно на положительную сторону. Следовательно, наименьшее значение получится, когда X тянет нас в отрицательную сторону, но все остальные биты отсутствуют:
1 0 0 0 = -(2 ** 3) = -8
То есть при w = 4 наименьшее значение будет -8.
Максимальное значение получается, когда "знаковый" бит равен нулю, зато есть все остальные, которые тянут нас в положительную сторону:
0 1 1 1 = 2 ** 2 + 2 ** 1 + 2 ** 0 = 4 + 2 + 1 = 7
Аналогично, при w = 8 диапазон будет от -128 до 127. К примеру,
let number: i8 = -128;
println!("{number:b}");
вернёт
10000000.А теперь важный момент: мы понимаем, что **наш вектор из битов можно рассматривать по-разному**. Если мы считаем, что наиболее значимый бит используется для хранения информации о знаке, то, к примеру, число
10110100 равно -76. Но если мы считаем, что речь идёт о неотрицательных числах, то это 180!🔥7❤5✍2👍2🥰1
Иными словами, нам нужно объяснить компьютеру, с чем мы имеем дело и как хотим интерпретировать этот вектор. Собственно говоря, именно поэтому нам нужно быть очень аккуратными, если мы конвертируем числа со знаком в числа без знака:
Результат выполнения:
То есть последовательность битов та же, но интерпретация другая! Это происходит не только в Rust, но и в других языках, к примеру, в C.
С u8 ситуация может быть не сильно лучше:
На экран будет выведено
Из всего этого следует важный вывод: конвертировать числа таким образом стоит с большой осторожностью, потому что это может привести к неожиданным проблемам и серьёзным багам. Инструмент Clippy даже выдаст предупреждение на моменте
let number: i8 = -6;
println!("{number:b}");
let number2: u8 = number as u8;
println!("{number2}");
println!("{number2:b}");
Результат выполнения:
11111010
250
11111010
То есть последовательность битов та же, но интерпретация другая! Это происходит не только в Rust, но и в других языках, к примеру, в C.
С u8 ситуация может быть не сильно лучше:
let number: u8 = 255;
let number2: i8 = number as i8;
println!("{number2}");
На экран будет выведено
-1.Из всего этого следует важный вывод: конвертировать числа таким образом стоит с большой осторожностью, потому что это может привести к неожиданным проблемам и серьёзным багам. Инструмент Clippy даже выдаст предупреждение на моменте
number as i8. Если вам нужно просто "отбросить" знак, то следует использовать функцию "модуль" .abs().👍12❤1
We automate the lies
with images we fake
Machines to grant our every wish
when all we do is take https://www.youtube.com/watch?v=fMcN5Lh8jxY
with images we fake
Machines to grant our every wish
when all we do is take https://www.youtube.com/watch?v=fMcN5Lh8jxY
YouTube
Wait
Provided to YouTube by Kontor New Media GmbH
Wait · VNV Nation
Electric Sun
℗ Anachron Sounds
Released on: 2023-04-28
Artist: VNV Nation
Composer, Lyricist, Mixer: Ronan Harris
Mixer, Mastering Engineer: Benjamin Lawrenz
Music Publisher: Schubert Music…
Wait · VNV Nation
Electric Sun
℗ Anachron Sounds
Released on: 2023-04-28
Artist: VNV Nation
Composer, Lyricist, Mixer: Ronan Harris
Mixer, Mastering Engineer: Benjamin Lawrenz
Music Publisher: Schubert Music…
👍1
Кстати. Пожалуйста, добавьтесь в чат для отправки комментов https://t.iss.one/+MxYT6-01eeA1NTYy К сожалению, без добавления нельзя, этим пользуются спамеры.
Telegram
DEV: Рубиновые тона: ЧАТ
Обсуждение канала "DEV: Рубиновые тона"
👍3❤1👌1🥴1
Теперь поговорим о дробных числах и их представлении в компьютере, в частности, о том, как их описывает стандарт IEEE 754, принятый в 1985 году.
Чтобы было проще, начнём с обычного десятичного числа
То есть тут повторяется ситуация с порядковыми номерами, которую мы видели ранее при обсуждении целых чисел. Каждая цифра здесь привносит определённое значение в зависимости от своего порядкового номера.
При этом цифрам, стоящим после точки, мы просто присваиваем отрицательные индексы. В принципе, это же число можно представить как
Ясное дело, этот принцип можно применить и двоичным числам. К примеру, если взять двоичное
Или, проще говоря,
То есть мы видим, что после точки у нас появляются дроби со степенями двойки:
Поэтому стандарт IEEE 754 представляет дробные числа в виде формулы:
Здесь три параметра, и в компьютере каждый хранится в своём поле.
Ну, а
Итак, эти числа состоят аж из трёх полей сразу, и обычно имеют либо одинарную (single, 32 бита), либо двойную (double, 64 бита) точность. К примеру, для одинарной точности
Здесь, правда, возможно три разных случая.
Первый случай самый типичный, он описывает нормированные значения. Это случай, когда экспонента не состоит целиком из нулей или целиком из единиц. Говорят, что экспонента хранится в смещённой (biased) форме, а само её значение считается как:
e - число без знака с последовательностью
Следовательно, финальное значение
Поле
Следующий случай - денормированные значения, это когда в поле
Такие денормированные значения, в частности, используются, чтобы представить значение 0. А чего бы нам для нуля не использовать первый случай? Ну потому, что там
Кстати, тут получается интересный момент: у нас может быть как +0, так и -0. Почему? Потому что хотя биты в
На самом деле, этот случай используется ещё и тогда, когда нужно представить числа, очень близкие к нулю, как мы увидим в примере ниже.
Последний третий случай - это специальные значения, когда в поле
Если в
Чтобы было проще, начнём с обычного десятичного числа
35.42, у которого, как можно видеть, имеется дробная часть. Как ещё можно записать это число? Ну, к примеру, вот так:3 * (10 ** 1) + 5 * (10 ** 0) + 4 * (10 ** -1) + 2 * (10 ** -2)
То есть тут повторяется ситуация с порядковыми номерами, которую мы видели ранее при обсуждении целых чисел. Каждая цифра здесь привносит определённое значение в зависимости от своего порядкового номера.
При этом цифрам, стоящим после точки, мы просто присваиваем отрицательные индексы. В принципе, это же число можно представить как
35 + (42 / 100), суть та же.Ясное дело, этот принцип можно применить и двоичным числам. К примеру, если взять двоичное
101.11, то у нас выйдет:1 * (2 ** 2) + 0 * (2 ** 1) + 1 * (2 ** 0) + 1 * (2 ** -1) + 1 * (2 ** -2)
Или, проще говоря,
4 + 0 + 1 + (1/2) + (1/4)
То есть мы видим, что после точки у нас появляются дроби со степенями двойки:
1/2, 1/4, 1/8, и так далее. Так мы можем легко представить дробь 3/16 (или 0.1875), это будет 0.0011. Хотя такой подход в теории можно использовать, он не слишком удобен, особенно для очень больших чисел.Поэтому стандарт IEEE 754 представляет дробные числа в виде формулы:
((-1) ** s) * M * (2 ** E)
Здесь три параметра, и в компьютере каждый хранится в своём поле.
s равно либо 0, либо 1. Это информация о знаке, соответствующее поле занимает всегда 1 бит.M - это мантисса, дробное число, обычно меньше 1. Его представляет поле frac, занимает оно n бит и содержит последовательность`f(n-1), ..., f(1), f(0)`.Ну, а
E - это экспонента, которая может быть как положительной, так и отрицательной. Её представляет поле exp длиной k бит с последовательностью e(k-1), ..., e(1), e(0).Итак, эти числа состоят аж из трёх полей сразу, и обычно имеют либо одинарную (single, 32 бита), либо двойную (double, 64 бита) точность. К примеру, для одинарной точности
s занимает один бит номер 31, exp - с 23 по 30 биты, остальное (с 0 по 22) отводится под мантиссу.Здесь, правда, возможно три разных случая.
Первый случай самый типичный, он описывает нормированные значения. Это случай, когда экспонента не состоит целиком из нулей или целиком из единиц. Говорят, что экспонента хранится в смещённой (biased) форме, а само её значение считается как:
E = e - B
e - число без знака с последовательностью
e(k-1), ..., e(1), e(0). B - это значение bias, которое равно 2 ** (k - 1) - 1, то есть для одинарной точности оно равно 127, потому что в этом случае длина поля exp составляет 8 бит.Следовательно, финальное значение
E будет лежать в пределах от -126 (тк e - число без знака, и оно точно больше нуля в данном случае) до 127 для одинарной точности.Поле
frac в этом случае описывает дробную часть, то есть его значение f в десятичном виде лежит от 0 (включительно) до 1 (не включительно), это довольно важно, процесс формирования f увидим в примере ниже. Финальное значение мантиссы M = 1 + f. Следующий случай - денормированные значения, это когда в поле
exp содержатся все нули. В этом случае E = 1 - B, M = f.Такие денормированные значения, в частности, используются, чтобы представить значение 0. А чего бы нам для нуля не использовать первый случай? Ну потому, что там
M = 1 + f, то есть в любом случае M >= 1.Кстати, тут получается интересный момент: у нас может быть как +0, так и -0. Почему? Потому что хотя биты в
exp и frac занулены, s всё равно может иметь значение как 0, так и 1.На самом деле, этот случай используется ещё и тогда, когда нужно представить числа, очень близкие к нулю, как мы увидим в примере ниже.
Последний третий случай - это специальные значения, когда в поле
exp записаны все единицы. Правда, этот случай содержит два других возможных сценария.Если в
frac записаны одни нули, то таким образом мы представляем бесконечность (плюс или минус бесконечность, зависит от знака s) - примеру, если мы поделили на ноль.👍4
Если в
В качестве примера можно взять 8-битный формат, где на
Как мы представим ноль? Ну, очевидно вот так (биты разграничены по соответствующим полям):
Классно. Теперь число
Теперь
Подставляем:
Попробуем ещё взять вот такое число, это в нашем случае самое большое из денормированных:
Выходит, что
А если самое маленькое из нормированных?
Тут
Аналогично, самое маленькое позитивное число, которое мы можем представить (грубо говоря, самое близкое к нулю):
Тут
Вот это как раз случай с денормированными числами, когда мы представляем очень близкое к нулю значение.
Кстати, тут один интересный момент. Смотрите, что у нас вышло:
Я расположил эти числа по возрастанию от самого маленького десятичного к самому большому. Но при этом можно видеть, что их двоичные аналоги тоже стоят по возрастанию! Это вовсе не случайно: стандарт создавался с учётом того, что программистам наверняка потребуется сортировать такие числа по тем же принципам, что и для целых чисел (хотя тут есть небольшая проблема, если в первом бите появляется
Собственно говоря, из примера выше мы видим, что представить "любое" число мы с помощью такого стандарта не можем. К примеру, у нас идёт "перескок" от
frac указано что-то иное (не все нули), то это значение называется "not a number" (NaN). Оно может вылезти, если результат невозможно представить реальными числами (настоящие джедаи помнят про мнимые числа, это не тот случай), либо если происходит что-то странное в духе "бесконечность минус бесконечность".В качестве примера можно взять 8-битный формат, где на
exp отводится k=4 бит, а на frac даётся n=3 бит (понятно, что на знак в любом случае 1 бит). В этом случае значение bias B = 2 ** (4-1) - 1 = 7.Как мы представим ноль? Ну, очевидно вот так (биты разграничены по соответствующим полям):
0 0000 000
e=0, E = 1 - 7 = -6.f можно записать как 0 / 8 (тк в поле frac у нас все нули), M = f = 0 / 8. Выходит формула:((-1) ** 0) * (0/8) * (2 ** -6) = 0
Классно. Теперь число
7/8, то есть 0.875. Его представление:0 0110 110
e = 0110 = 6, тогда E = 6 - 7 = -1.Теперь
f. У нас три бита, 2 ** 3 = 8, а само значение frac = 110, то есть 6. Выходит, что f = 6/8, M = 14 / 8.Подставляем:
((-1) ** 0) * (14 / 8) * (2 ** -1) = 0.875
Попробуем ещё взять вот такое число, это в нашем случае самое большое из денормированных:
0 0000 111
Выходит, что
e = 0, E = -6. При этом f = M = 7/8. Подставим:((-1) ** 0) * (7/8) * (2 ** -6) ~ 0.013671875
А если самое маленькое из нормированных?
0 0001 000
Тут
e = 1, E = -6, f = 0 / 8, M = 8 / 8. Подставляем:((-1) ** 0) * (8/8) * (2 ** -6) ~ 0.015625
Аналогично, самое маленькое позитивное число, которое мы можем представить (грубо говоря, самое близкое к нулю):
0 0000 001
Тут
e = 0, E = -6, f = M = 1/8. В формуле:((-1) ** 0) * (1/8) * (2 ** -6) = 0.001953125
Вот это как раз случай с денормированными числами, когда мы представляем очень близкое к нулю значение.
Кстати, тут один интересный момент. Смотрите, что у нас вышло:
0 0000 000 = 0
0 0000 001 = 0.001953125
0 0000 111 = 0.013671875
0 0001 000 = 0.015625
0 0110 110 = 0.875
Я расположил эти числа по возрастанию от самого маленького десятичного к самому большому. Но при этом можно видеть, что их двоичные аналоги тоже стоят по возрастанию! Это вовсе не случайно: стандарт создавался с учётом того, что программистам наверняка потребуется сортировать такие числа по тем же принципам, что и для целых чисел (хотя тут есть небольшая проблема, если в первом бите появляется
1, то есть число отрицательное).Собственно говоря, из примера выше мы видим, что представить "любое" число мы с помощью такого стандарта не можем. К примеру, у нас идёт "перескок" от
0.013671875 сразу к 0.015625, и сделать с этим особенно ничего не получится. Да, можно использовать не 8 бит, а 32 или даже 64 (двойная точность), но, как вы понимаете, всё равно покрыть все возможные случаи никак не выйдет. Поэтому в том же Rust есть понятие "эпсилон" (мы его с вами видели на стриме), то есть определённая погрешность, которую стоит учитывать.👍4
В этом уроке мы попробуем ответить на важный вопрос: как именно хранятся числа в компьютере, если современные процессоры оперируют только нулями и единицами? Мы узнаем о принципах хранения целых чисел без знака, со знаком, а также о стандарте IEEE 754, описывающем хранение дробных чисел. https://www.youtube.com/watch?v=Pe3GCa3WKBU
YouTube
Как представлены числа в компьютере? | Uint, int, float, IEEE 754, single, double, two's complement
В этом уроке мы попробуем ответить на важный вопрос: как именно хранятся числа в компьютере, если современные процессоры оперируют только нулями и единицами? Мы узнаем о принципах хранения целых чисел без знака, со знаком, а также о стандарте IEEE 754, описывающем…
❤🔥8❤2
В этом уроке по Rust мы поговорим о HashMap, а также продолжим работать над задачами Rustlings. В этот раз будет много практики! https://www.youtube.com/watch?v=CRIWL6rllGI
YouTube
Язык Rust, урок #9 | HashMaps, большая практика Rustlings
В этом уроке по Rust мы поговорим о HashMap, а также продолжим работать над задачами Rustlings. В этот раз будет много практики!
Таймкоды:
00:00 Введение
00:30 Что такое hash maps?
01:20 Как создавать и записывать в hash map?
02:20 Получение значений
04:50…
Таймкоды:
00:00 Введение
00:30 Что такое hash maps?
01:20 Как создавать и записывать в hash map?
02:20 Получение значений
04:50…
👍10❤🔥2🔥2