CodeLab
145 subscribers
538 photos
20 videos
159 links
Говорим просто о сложном

Обсуждение, новости, материал и сплетни — все здесь https://t.me/CodeLabMLChat
Download Telegram
🔗Итак, #Первая_цифра_после_точки. В задании указано, вывести первую цифру после десятичной точки, ну и хули там решаем
Самым обычным решением будет просто умножить наше число на 10, чтобы оно стало целым, а затем находим остаток от деления #Первая_цифра_после_точки

Код:

s = float(input())
print(int(s * 10) % 10)
Ебать я щас сидел разбирал другой пример решения, просто интересно ваше мнение: Как вы думаете, верно ли это решение или нет? Какой будет ответ, если ввести 19.9? #float

Код:

n = float(input())
print(int((n - int(n)) * 10))
Само решение степик пропускает, это если что решение к заданию выше, но есть нюанс
Anonymous Quiz
67%
Да, верно
33%
Нет, неверно
Так, еще раз, представим, что с клавиатуры подается число 19.9, теперь подставляем и думаем
Какой будет ответ?
Anonymous Quiz
67%
8
33%
9
CodeLab
Так, разберем сразу на примере, как раз увидим как работает функция len() и что такое метод split(). У нас подается строка, состоящая из 4 слов. Переменной words присваиваем нашу строку.split(). Как раз таки #split() это метод, который разделяет нашу строку…
⭕️ Еще одно решение, которое я спиздил в комментариях к заданию (чуть позже опубликую причины, почему решение выше не является верным).

‼️ Итак, гений решил через метод split(), который я уже пытался объяснить (Сообщение я прикрепил). Итак, что тут происходит

0️⃣ Input() запрашивает у нас ввод, вводим и он возвращает строку, тут все как обычно.

1️⃣ Дальше выводим s.split('.').

2️⃣ Мы разбиваем нашу строку s и в качестве разделителя используем точку, как раз, что нам и нужно.

3️⃣Допустим, было у нас число 111.234 - метод просто вернет список ['111', '234']. Дальше идет [-1]. Это значит что выбирается первый с конца элемент, как в нашем примере, это будет 234. Ну и собственно [0] выбирает первый символ '234', это будет просто 2, так как индекс [0] имеет первый символ. #split #Программирование
CodeLab
Какой будет ответ?
‼️ Теперь, почему все-таки 8? Берем код выше. input() возвращает нам строку и дальше выводим:

(int((n-int(n))*10)).

⭕️ Если бы подставили, скажем, 14.89, то все достаточно просто, вычитаем, получаем 0.89, умножаем на 10 и получаем 8.9, а перед скобками стоит int(), значит дробная часть отбрасывается, ответ 8.

Пока что все логично и понятно. Кароч, мне стало достаточно интересно узнать почему 0.1, 0.2, 0.3, 19.9, не могут быть точно представлены в виде конечной дроби в двоичной системе, поэтому я обратился к GPT.

Число 19.9 не может быть точно представлено в виде числа с плавающей точкой (тип float) из-за особенностей двоичного представления в компьютере.

🌶 Это связано с тем, что числа с плавающей точкой хранятся в двоичной системе счисления, а не в десятичной. Десятичные числа, такие как 19.9, записываются в виде суммы степеней числа 10 (пример 1 на фото) Однако, в двоичной системе, это число нужно представить в виде суммы степеней числа 2 (Пример 2 на фото).
🔗 Суть в том, что десятичные дроби, такие как 0.1, 0.2, 0.3 - 0.9 не могут быть точно представлены в виде конечной дроби в двоичной системе.

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

❗️Так как компьютер ограничен количеством битов для хранения числа, он не может хранить бесконечную дробь и должен её округлить 19.9. до ближайшего возможного представления 19.899999999999998(примерно) 🧑‍💻
Завтра попробую об этом поподробнее рассказать, всем сладких 😋
👨‍💻 Иииитак, вчера я ничего не делал, щас буду рассказывать про хранение памяти в компьютере, как раз это свяжем с проблемой чисел с плавающей точкой, поэтому постарайтесь все внимательно прочитать‼️

⭕️ Для хранения одной ячейки информации в памяти используется байт (8 битов), а не один бит. Как лично я понял, когда идет речь об обращении к 'ячейке памяти', то речь тут все-таки о байтах.

0️⃣ В одном байте, как мы знаем 8 бит, но процессор обращается к памяти на уровне байтов. Он может иметь значение 1 или 0. следовательно 1 будет означать передачу тока в транзистор, а 0 – нет. ⭕️ Каждая такая ячейка имеет уникальный адрес, который используется для доступа к данным, хранящимся в этой ячейке. А нужно это для быстрого поиска и использования информации, процессор будет напрямую обращаться к любой ячейке памяти.

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

1️⃣ Информация дальше подпизжена частично из GPT (просто на всякий вам): Значит, есть формат IEEE 754, который описывает числа с плавающей точкой (лично я это не знал, поэтому пишу вам).

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

2️⃣ Порядок
(экспонента) — отвечает за масштаб числа, сдвигая десятичную точку.

3️⃣ Мантисса
— содержит значимые цифры числа. Теперь об этом поподробнее. Я буду ссылаться на сайт https://struchkov.dev/blog/ru/floating-point-math/:

4️⃣ Итак, возьмем вещественное число 6.25 и переведем его в двоичный код. (Хочу показать как найти мантиссу)

⭕️ Целую часть (6) мы делим на 2, при этом записывая остаток от деления:
6 : 2 = 3[0], 3 : 2 = 1[1], 1 : 2 = 1[1]❗️ (В квадратных скобках остаток от деления). (И получили мы 110, т.к с конца записали)

Дробную часть (0.25) в свою очередь умножаем на 2, при этом, целую часть записываем, а дробную продолжаем умножать: 0.25 * 2 = 0.5 (0 записали, а 0.5 продолжаем умножать на 2, получаем 1 (0.5 x 2 = 1.0), единицу тоже записываем (Записываем не с конца, просто получаем на выходе 01).

5️⃣🔗Теперь, все как в школе🧑‍💻: остатки от деления целой частей записываем с конца - 110, и дробную, также с конца - получаем 01. Соединяем и получаем 110.01, это наше число 6.25 только в двоичном виде. Если вам не понятен перевод числа, я прикреплю фотки после сообщения, это будет [1] изображение. Так что это за ебанная мантисса вообще?

‼️ Ниже будет разбор по фотке, чтобы было понятнее ‼️
‼️ Мантисса (или дробная часть) — это часть числа, которая определяет его точность. Я уже упомянул стандарт IEEE-754, согласно этому стандарту, двоичное число представляется в виде формулы, где s — знак числа, M — мантисса, B — основание, E — экспонента (порядок, степень двойки).

⭕️ Поскольку мы работаем в двоичном коде, основание равно двум, и формула принимает следующий вид: [2]. Вещественное число мы сохраняем как три отдельных числа: знак, экспоненту и мантиссу, да и все бы заебись, но количество бит для хранения ограниченно форматом.

👨‍💻Формат если че это такая структура, которая описывает, как именно должны быть организованны данные. ❗️Именно формат определяет, сколько битов выделяется для различных частей данных: для мантиссы, знака и порядка(экспоненты).

0️⃣ Рассматриваем формат, в котором доступно 32 бита: 1 бит знака, 8 битов для экспоненты и 23 бита для мантиссы. Этот формат называется ‼️"одинарной точностью". Также есть формат 'Двойная точность (64 бита)': 1 бит для знака, 11 битов для экспоненты, 52 бита для мантиссы.

⁉️Дак вот, нам нужно сдвинуть запятую нашего числа с прошлого поста 110.01 влево настолько, пока в целой части не останется единица. При этом, каждый сдвиг увеличивает степень основания (сейчас поясню).

1️⃣ На первом этапе у нас число 110.01 * 10 ** 0, все написано по формуле! Десятка в основании, так как это 2 в двоичной степени, сам автор статьи это поясняет. Следующим этапом будет сдвиг запятой влево, т.е получится 11.001 * 10 ** 1.

2️⃣Ну и последним этапом, 1.1001 * 10 ** 2. В итоге мы получаем
1.1001 x 2 **
2. (По сути просто сдвигаем влево и увеличиваем степень нашей '2')

Здесь 1.1001 - это наша мантисса, а поскольку наше число положительное, бит знака будет равен 0.

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

‼️Чтобы дальше получить экспоненту, нам нужно прибавить число 127
. То есть было у нас число 1.1001 * 2 ** 2, к этой двойке прибавляем 127, с каких это х‼️ев?

🔗Под экспоненту в нашем представлении чисел с плавающей запятой выделено 8 бит, что позволяет сохранить 256 различных значений. Но есть проблемка, ведь в нашем представлении не предусмотрено отдельного бита для знака экспоненты.

‼️Решением проблемы будет состоять в хранении экспоненты относительно середины доступного диапазона значений, то есть диапазон чисел от 0 до 255, а для 8-битного диапазона этой "серединой" будет число 127 [3] изображение.

3️⃣ По итогу, к нашей изначальной степени 2 прибавляем 127 и получаем 129. При преобразовании 129 в двоичную получаем 10000001 - это и будет экспонента. Зачем вообще это все нужно ?

Ответ - да х🌶й знает вообще, мне лично стало интересно почитать и изучить, как это работает в действительности, а не просто 'а нуу, 0.1 + 0.1 не равно 0.2 да и ладно, написано, значит написано'. Спасибо большое автору статьи! Сейчас скину пару изображений и перейдем к финалу
⭕️ Согласно стандарту, формула для представления двоичного числа
⭕️ Поскольку преобразования происходят в двоичном коде, основание экспоненты равно 2
Формат "одинарной точности", в котором доступно 32 бита: 1 бит знака, 8 битов для экспоненты и 23 бита для мантиссы.
🔗Еще, было указано про прием, который применяли еще в первых машинах, который позволял не сохранять целую часть числа, так как она всегда равна единице. Это выглядит вот так, поэтому целую часть мы не записываем, она всегда равна единице.
Нормализованное число (нормисное) имеет следующий вид: (Просто добавляем единицу)
⭕️ 8 битный диапазон, для нахождения экспоненты. Все отрицательные степени будут располагаться левее числа 127, а все положительные - правее.