惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
V
V2EX
T
The Blog of Author Tim Ferriss
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Hugging Face - Blog
Hugging Face - Blog
Stack Overflow Blog
Stack Overflow Blog
I
InfoQ
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Last Week in AI
Last Week in AI
Recent Announcements
Recent Announcements
Vercel News
Vercel News
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
美团技术团队
Martin Fowler
Martin Fowler
宝玉的分享
宝玉的分享
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
J
Java Code Geeks

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Только 17% всех 64-битных целых чисел можно разложить на ...
PatientZero · 2026-05-26 · via Все публикации подряд на Хабре

Уровень сложностиПростой

Время на прочтение3 мин

Охват и читатели4.1K

Перевод

В разработке ПО произведение двух целых чисел часто вычисляется до фиксированного количества битов с переполнением. Возьмём для примера 8-битные целые. Если умножить 127 на 127, то мы получим число 1 в виде 8-битного беззнакового целого с переполнением. Реальное полное произведение равно 16129. Для представления 16129 обычно используются 16 бит точности.

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

Хотите знать, почему меня это интересует?

Мы часто проектируем хэш-функции: это особые функции, получающие входные данные и генерирующие случайно выглядящие выходные. Много лет назад я проектировал очень быструю хэш-функцию clhash. Эта сверхбыстрая функция предназначена для хэширования строк из сотен и более байт. Если вы не знаете про clhash, то можете почитать про неё, она интересна сама по себе.

В clhash используется тип умножения, характерный для криптографии. Я пытался показать, что такой подход выгоднее по сравнению с методиками, основанными на стандартном умножении. Попробую это проиллюстрировать: простая хэш-функция для 32-битных целых чисел может брать младшие биты и перемножать их со старшими.

// simpleHighLowHash - это простой (и слабый) 32-битный хэш,
// умножающий старшие 16 бит на младшие 16 бит.
func simpleHighLowHash(x uint32) uint32 {
    high := uint16(x >> 16)
    low := uint16(x & 0xFFFF)
    return uint32(high) * uint32(low)
}

Вероятно, вам нужно, чтобы хэш-функция была равномерной: вероятность всех возможных 32-битных значений хэша должна быть одинаковой. В данном случае это возможно, только если хэш-функция может возвращать все 32-битные значения хэша, но это не так.

Великий математик Пал Эрдёш доказал, что доля всех 2n-битных значений, которую можно сгенерировать перемножением двух n-битных значений, при увеличении n стремится к нулю. Это значит, что если, например, вы умножаете 10000000-битные целые на 10000000-битные целые, то получится относительно мало 100000000000000-битных целых. Но как насчёт практических случаев, например, 32-битных или 64-битных целых?

Задачу легко можно решить перебором, перемножая 16-битные числа для получения 32-битных произведений. Там мы выясним, что произведением двух 16-битных целых оказываются чуть больше одного из пяти 32-битных чисел. Примерно 80% из всех 32-битных чисел эта хэш-функция никогда не вернёт. Однако время выполнения растёт экспоненциально, поэтому перебор для 32 бит масштабировать не получится.

Так что же нам делать в случае 32-битных множителей? То есть что делать, когда мы перемножаем два 32-битных целых, чтобы получить 64-битное произведение? Какую долю от всех 64-битных значений вернёт показанная ниже функция?

func simpleHighLowHash(x uint64) uint64 {
    high := uint32(x >> 16)
    low := uint32(x & 0xFFFFFFFF)
    return uint64(high) * uint64(low)
}

Можно ли получить точный результат?

Да!

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

Существует 3 215 709 724 700 470 902 64-битных (беззнаковых) целых чисел, которые можно записать как произведение двух 32-битных целых. Это примерно 17% от всех возможных значений.

А как насчёт реального вычисления пар целых чисел из их произведения? Одно из решений заключается в вычислении его полного разложения на простые числа с последующим получением всех возможных делителей меньше 2^32, начиная с множества кандидатов, содержащих только 1, и итеративно умножая имеющихся кандидатов на каждый простой делитель (оставляя при этом только произведения меньше 2^32). Мы можем избежать добавления во множество дубликатов, обрабатывая уникальные простые делители с кратными им числами. Затем мы выбираем такого максимального кандидата m в качестве наибольшего делителя меньше 2^32, вычисляем соответствующий сомножитель n / m и сообщаем, существует ли допустимое разбиение на два 32-битных множителя. В общем случае, ответ (если он существует) не уникален: он возвращает пару, в котором одно значение максимизировано. На Python код может выглядеть так:

for p in factor_multiplicities:
    new_candidates = []
    for c in candidates:
        for i in range(factor_multiplicities[p] + 1):
            if c * (p ** i) < 2**32:
                new_candidates.append(c * (p ** i))
    for new_c in new_candidates:
        candidates.append(new_c)
m = max(candidates)
print(f"Maximum candidate: {m}")
leftover = n // m
print(f"Leftover: {leftover}")
if leftover >= 2**32:
    print("Leftover is too large, cannot find a suitable candidate.")

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