“Есть всего 10 типов людей. Те кто понимают двоичную систему и все остальные.” — Автор Неизвестен

Это отрывок из курса программирования на JavaScript CoderslangJS.

— Привет, Герой! Сегодняшнюю лекцию для тебя проведет C2H5. Он — робот и наш союзник в борьбе с машинами.

— Спасибо за представление, Профессор. Мышление машин принципиально мало отличается от человеческого, но у него есть свои особенности.

Двоичная система счисления

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

Для начала, представь 10 лампочек. Каждая из них может быть включена или выключена.

Внимание, вопрос! До скольки ты мог бы посчитать используя эти 10 лампочек?

Ээээммм, до 10?

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

— Нет, думаю, что это невозможно.

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

Попробуй представить, что каждая лампочка не просто включена или выключена, а отображает одну цифру от 0 до 9.

Тогда, мы бы могли получить все комбинации от 0 000 000 000 до 9 999 999 999. Или 10 миллиардов разных чисел, включая 0, конечно.

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

— Сейчас разберемся детально. Давай представим на нашем “ламповом калькуляторе” какое-нибудь не слишком длинное число, например 2375. Нули отбросим для простоты подсчета. Чтобы понять, что это число “две тысячи триста семьдесят пять”, ты делаешь несколько операций:

5 * 1 + 7 * 10 + 3 * 100 + 2 * 1000 = 5 + 70 +300 + 2000 = 2375

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

БАЗА в степени ПОЗИЦИЯ.

БАЗА — это основа системы счисления. В привычных людям числах — это 10. В более естественной для машин, двоичной системе - 2.

Отсчет позиций мы начинаем справа и начальная позиция всегда 0, поэтому вес первого разряда - 1, т.к. возведение любой БАЗЫ в нулевую степень равно 1.

Следующие разряды в десятичной системе, имеет вес 10, 100, 1 000, 10 000 и т.д.

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

Это достаточно очевидно, но ведь в первоначальной задаче не было цифр, а были только 2 состояния — вкл/выкл?

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

Представь такую последовательность лампочек - 0 0 1 0 1 0 1 1 0 1

Начнем с того, что присвоим каждой позиции свой вес.

Вес позиции 0 = 2 ^ 0 = 1

Вес позиции 1 = 2 ^ 1= 2

Вес позиции 2 = 2 ^ 2 = 4

Вес позиции 9 = 2 ^ 9 = 512

Теперь, чтобы посчитать итоговое число, нам осталось только умножить вес каждой позиции на ее значение (0 или 1).

Получится 1 * 1 + 0 * 2 + 1 * 4 + 1 * 8 + 0 * 16 + 1 * 32 + 0 * 64 + 1 * 128 + 0 * 256 + 0 * 512 = 1 + 4 + 8 + 32 + 128 = 173

Теперь понятно. Получается если мы включим все лампочки, то получится 1 + 2 + 4 + 8 + 16 + 32 + 64 + 128 + 256 + 512 = 1023?

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

Абстракция

— Если ты посмотришь внимательно, то, на самом деле, и десятичные числа и двоичные существуют только в нашем воображении.

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

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

Если стульев было бы 3, а не 12, то проще всего было бы показать их, как 3 пальца на одной руке или 3 включенных лампочки. Это самый простой и очевидный способ что-то посчитать. Но что делать если их 12, 40, 125? Пальцев уже не хватит, а где хранить лампочки тоже не очень понятно.

Поэтому, люди придумали системы счисления. И десятичная система далеко не всегда была так распространена. Римляне бы подписали те же стулья как XII и, скорее всего не поняли бы что означает надпись 12.

Все это — абстракция. Мы усложнили подсчет количества предметов, но оперировать большими числами стало намного проще.

— Мне кажется, что числа встречаются в нашей жизни настолько часто, что уже никто и не воспринимает это как усложнение.

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

Обрати внимание, что если бы, в какой-то момент вместо цифр 0 1 2 … 9, люди решили использовать буквы a b c … k, то твои 12 стульев превратились бы в bc стульев, но на сами стулья это бы никак не повлияло.

Алгоритмы и псевдокод

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

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

Хорошая новость — после того, как эта программа написана, ей могли пользоваться совершенно разные люди.

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

Целью лучших программистов тех времен — было создание полноценного искусственного интеллекта. Такого, который мог бы решить любую поставленную задачу, а не только отличать котов от собак.

Чем все закончилось — ты уже знаешь. В какой-то момент даже сами создатели уже не могли предсказать как поведут себя машины. Они оправдывали это всеобщим благом и рассказывали как была ужасна жизнь людей до изобретения ИИ.

Но в итоге — люди стали для машин тем, чем когда-то были муравьи для людей. Они повсюду, но нет никакого смысла их истреблять. Как и испытывать какие-либо эмоции по поводу того, что они растащат несколько крупинок сахара упавшие с кухонного стола.

— И ты думаешь, что мне действительно по силам разобраться в том с чем не справились лучшие умы 2021 ?

— Иначе мы бы не тратили время на твою подготовку, Герой. Твоё преимущество в том, что мы точно знаем как сделать из тебя программиста и внедрить в ** компанию которую нельзя называть **.

Но, что-то мы отвлеклись. Давай попробуем разобраться, как найти человека в телефонном справочнике. Пусть его зовут Васильев Петр.

Способ 1 - Линейный поиск

открываем справочник на первой странице
просматриваем все записи сверху вниз
если найдено совпадение (Васильев Петр)
    звоним по найденному номеру
иначе
    переходим к следующей записи
повторить пока не закончатся страницы

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

— Ты прав. При наличии оглавления туда точно стоит взглянуть. Этот метод называется индексация и он очень часто используется в базах данных.

Но, при всей неоптимальности линейного поиска, он точно поможет нам найти телефон Петра Васильева или убедиться в том, что в справочнике его нет.

Как бы ты оптимизировал алгоритм линейного поиска, если бы у тебя не было индексов (оглавления), но ты знал что все записи упорядочены от А до Я?

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

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

Но, так как этого не было в условии, и мы можем оказаться в мире где 90% людей с фамилией на букву А, то я бы предложил открыть справочник ровно посередине. Оценить точность попадания и пойти направо или налево, отбросив половину записей.

Так как я робот, попробую формализовать этот алгоритм для тебя “почти” человеческим языком.

Способ 2 - Двоичный поиск

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

Как и в случае с линейным поиском, мы или найдем необходимую запись, или убедимся в том, что ее нет. ВАЖНО! Двоичный поиск работает только в отсортированных структурах данных, например телефонных справочниках или словарях.

Он работает намного быстрее, чем линейный поиск. И чем больше элементов в структуре данных, тем сильнее становится преимущество!

Если представить, что одна итерация (повторение) алгоритма поиска занимает 1 секунду и в нашей телефонной книге 100 записей, то линейный поиск займет 100 секунд в худшем случае или 50 в среднем, а двоичный поиск — меньше 7!

— Очевидно, что сокращение количества данных для поиска в 2 раза после каждого повторения очень полезно.

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

Линейному поиску в таком случае потребуется примерно неделя, а двоичный поиск справится всего за 20 секунд!

— Ого.

— К сожалению, если мы работаем с неупорядоченными данными, то линейный поиск — наш единственный вариант.

— А если мы отсортируем данные перед поиском?

— Сортировка — дорогой и долгий процесс. Она будет иметь смысл только в том случае, если мы будем работать с этими данными долго и будем делать много поисков.

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

У псевдокода нет жестких правил, машины с ним не работают. Он просто должен описывать логику алгоритма и быть понятным людям.

— Выглядит полезно. Ведь я пока не очень умею программировать.

— Это мы исправим. Давай пройдем тест, чтобы оценить, как ты усвоил новую информацию.

Ты можешь стать Full Stack JS разработчиком на CoderslangJS.