# format() без format() Модели пишут на Python функцию `fmt(value, spec)`, которая для целых и дробных чисел символ в символ повторяет встроенную `format()`, но без неё самой, без f-строк, `%` и `repr`. Задание короткое, а ловушек много: округление по точному двоичному значению, заполнение нулями вместе с разделителями разрядов, флаг `z`, NaN, бесконечности и разбор строки формата. Ответ сравнивается с настоящим CPython на 502 случаях и двумя замерами скорости. 29 октября 2026. Интерактивная версия: [report.html](report.html), все бенчмарки: [../index.html](../index.html) ## Полоса тестов ![Полоса тестов](charts/strip.svg) Каждая строка показывает один прогон модели, а каждое деление в ней означает один тест. Тёмное деление значит, что тест пройден, красное значит провал, серое значит, что код не запустился. Столбцы общие для всех прогонов и отсортированы от лёгких тестов к трудным. ## Что выяснили **Без единой ошибки справился только Opus агентом.** Оба агентских прогона, с уровнем рассуждения по умолчанию и с `effort: max`, прошли 502 случая из 502 и оба замера. Ближе всех из моделей через API DeepSeek Flash с 478, у GPT-6.1 Sol 422, у Qwen3.8-Max 402. **Через шлюз Opus думает в разы меньше и нарушил запрет.** Opus через API с `effort: max` рассуждал 9,5 тысячи токенов против 55 и 240 тысяч у агентов на той же модели и отформатировал порядок числа f-строкой, которую задание запрещает. В зачёт идёт ноль, с правкой было бы 447. **Главные ловушки: нули с разделителями, ноль при явном выравнивании и проценты.** `fmt(1234, '08,')` в Python даёт `0,001,234`, шире заданной ширины, и это не угадала ни одна модель через API. `<05` у всех, кроме агентов, дал пробелы вместо нулей. DeepSeek и GPT умножают на 100 точно, а CPython умножает во float, поэтому `1e308` с `%` даёт `inf%`. **Короткое задание различает модели лучше длинного.** Спецификация занимает одну страницу, но результаты разошлись от 402 до 502. В прошлых тестах сильные модели почти все проходили 100%, и места решала скорость кода. **Пустая строка входит в любую строку.** Qwen проверял тип как `typ in "eEfFgG%"`, а для пустого типа это истинно, и целое без типа уходило в ветку для float. Ровно на это же мы наткнулись в своей реализации для стенда. ## Все прогоны | Место | Модель | Тесты | Ловушки | Случайные | Ошибки | Скорость | Время | Рассуждение | Всего токенов | Токенов/с | Строк кода | С правкой | |---|---|---|---|---|---|---|---|---|---|---|---|---| | 🥇 1 | Claude Opus 5.5 (агент, effort max) | 502 (100.0%) | 85/85 | 400/400 | 17/17 | 2/2 | 35 мин 24 с | 241.3K* | 244.9K | 115* | 456 | — | | 🥈 2 | Claude Opus 5.5 (агент) | 502 (100.0%) | 85/85 | 400/400 | 17/17 | 2/2 | 8 мин 51 с | 54.8K* | 58.8K | 111* | 489 | — | | 🥉 3 | DeepSeek Flash (V4.1) | 478 (95.2%) | 83/85 | 379/400 | 16/17 | 0/2 | 7 мин 23 с | 70K | 74.3K | 168 | 673 | — | | 4 | GPT-6.1 Sol | 422 (84.1%) | 75/85 | 332/400 | 15/17 | 0/2 | 11 мин 40 с | скрыто | 19.5K | 28 | 512 | — | | 5 | Qwen3.8-Max | 402 (80.1%) | 65/85 | 322/400 | 15/17 | 1/2 | 40 мин 43 с | 92.8K | 96.6K | 40 | 524 | 416, скорость 1/2 | | 6 | Claude Opus 5.5 (effort max) | 0 (0.0%) | 0/85 | 0/400 | 0/17 | 0/2 | 2 мин 36 с | 9.5K | 14.9K | 96 | 468 | 447, скорость 0/2 | В колонке «С правкой» указан результат того же кода после исправления одной-двух строк. В рейтинг он не входит. «Токенов/с» показывает, как быстро модель пишет: все токены ответа, включая рассуждение, делённые на полное время ответа. ## Время ответа ![Время ответа](charts/time.svg) ## Сколько модель написала ![Токены](charts/tokens.svg) Синим показано рассуждение, бирюзовым код и ответ. Серый цвет значит, что провайдер не показывает, сколько ушло на рассуждение. ## Разбор по участникам ### Claude Opus 5.5 (агент, effort max) Тоже 502 из 502 и оба замера, 0,05 и 0,01 секунды. С `effort: max` агент думал вчетверо дольше, 35 минут и около 240 тысяч токенов, и написал код короче, 456 строк, но результат тот же: задача уже решалась полностью и на обычном уровне. Протокол соблюдён. ### Claude Opus 5.5 (агент) 502 из 502 и оба замера скорости, 0,06 и 0,01 секунды. Единственный, кто прошёл все ловушки с первого раза: точное округление, нули с разделителями, `z`, NaN, `%` во float и разбор строки формата. Работал вслепую 9 минут, около 55 тысяч токенов рассуждения, код 489 строк. Протокол соблюдён: одно чтение задания и одна запись решения. ### DeepSeek Flash (V4.1) 478 из 502, лучший результат среди моделей через API, но оба замера скорости провалены: замер засчитывается, только если все ответы в нём верны. `%` умножает число на 100 точно, а не во float, поэтому `1e308` даёт 300 цифр вместо `inf%`, и крупные числа в процентах расходятся в последних знаках. Не учтён `0` при явном выравнивании (`<05` даёт `5 ` вместо `50000`), а при выравнивании `=` нули не ставятся. Ответ за 7,4 минуты, 70 тысяч токенов рассуждения. ### GPT-6.1 Sol 422 из 502, оба замера провалены из-за неверных ответов. Как и DeepSeek, считает `%` точно, а не во float. Печатает `-nan` с минусом, теряет `%` у `nan`, ставит на один ноль больше при заполнении нулями с разделителями, не группирует `_` у шестнадцатеричных и на `.0g` даёт `2e+02` вместо `1e+02`. Первая попытка оборвалась на шлюзе через 298 секунд без ответа, вторая заняла 11,7 минуты, код начался только на 624-й секунде. ### Qwen3.8-Max 402 из 502 и один замер из двух. Думал дольше всех, 40 минут и 93 тысячи токенов рассуждения, и попался на ловушку, на которой споткнулись и мы при написании стенда: проверка `typ in "eEfFgG%"` для пустого типа истинна, поэтому целое без типа уходит в ветку для float и падает. С правкой этой строки было бы 416. Остальные ошибки настоящие: флаг `z` не работает, у `-inf` с `z` получается `-0.0`, нули с разделителями и заполнение нулями у `inf` неверны. ### Claude Opus 5.5 (effort max) 0 из 502: решение нарушает запрет задания. Порядок числа форматируется f-строкой `f"{abs(exp):02d}"`, то есть встроенным форматированием, ещё две f-строки стоят в текстах ошибок. Если заменить их, было бы 447 из 502: ломаются наименьшее денормализованное число (деление на ноль), флаг `z`, `+nan`, нули с разделителями и `0` при явном выравнивании. Через шлюз Opus с `effort: max` рассуждал всего 9,5 тысячи токенов и ответил за 2,6 минуты, а агентом на той же модели думал 55 и 240 тысяч. ## Задача Нужно повторить мини-язык формата Python для `int` и `float`: заполнение и выравнивание, знак, флаги `z`, `#` и `0`, ширину, разделители `,` и `_`, точность и типы `d`, `b`, `o`, `x`, `X`, `e`, `E`, `f`, `F`, `g`, `G`, `%`. Где `format` бросает `ValueError`, функция тоже должна его бросить. Встроенное форматирование запрещено, разрешены `math`, `fractions`, `float.as_integer_ratio()` и `str()` от целого. Полный текст: [task/task.md](task/task.md) ## Как проверяли - 85 ручных ловушек. Среди них округление половины к чётному по точному значению (`2.675` с `.2f` даёт `2.67`), перенос порядка при округлении, денормализованные числа с точностью до 1100 знаков, граница записи у `g`, заполнение нулями с разделителями шире заданной ширины (`fmt(1234, '08,')` даёт `0,001,234`), `#` как символ заполнения, флаг `z` у нуля, но не у `-inf`, NaN без знака, `%`, который умножает во float и поэтому превращает `1e308` в `inf%`, и целые, которые для дробных типов сначала переводятся во float. - 400 случайных форматов из генератора с фиксированным seed: случайные заполнение, выравнивание, знак, флаги, ширина, разделитель, точность и тип на целых до 10^40 и на дробных, включая числа рядом с половинами при округлении и точные двоичные дроби. - 17 строк формата, которые обязаны закончиться `ValueError`: точность у целого, запятая с `x` и `b`, оба разделителя, `z` у целого типа, флаги не по порядку, неизвестный тип, точка без точности, разделитель после точности и лишние символы. - 2 замера скорости, на каждый 1 секунда: 20 000 вызовов со случайными форматами и 600 чисел с точностью около 1000 знаков. Своя реализация стенда без `format()` укладывается в 0,06 и 0,01 секунды. - Ограничения проверяются по коду решения (f-строки, вызовы `format` и `repr`, `%` для строк, запрещённые модули), а `builtins.format` на время прогона подменяется заглушкой. Нарушение даёт ноль. - Сам стенд проверен дважды: обёрткой над настоящей `format()` и своей реализацией без неё, обе дают 502 из 502 и проходят замеры. ## Условия - Участвуют те же модели, что в прошлых тестах. Каждая получила задание слово в слово, одним сообщением, без системного промпта и без инструментов, и не могла запустить свой код. - Параметры рассуждения такие же, как раньше: у Qwen включён `enable_thinking`, у GPT `reasoning_effort: high`, Opus через API получал `thinking: adaptive` и `effort: max` через нативный `/messages` партнёрского шлюза, Kimi и DeepSeek работали в режиме по умолчанию. - Opus 5.5 дополнительно решал задачу агентом Claude Code с чистым контекстом, дважды: с уровнем рассуждения по умолчанию и с `effort: max`. Протокол один: одно чтение задания и одна запись решения, без запуска кода. - Задание заканчивается фразой «Сначала продумай решение, затем ответь модулем», которая не отключает размышление у адаптивных моделей. - В зачёт идёт код как есть. Вариант с правкой считается отдельно, только для понимания. ## Нюансы - Стенд проверен двумя способами: обёрткой над настоящей `format()` и своей реализацией без неё. Обе дают 502 из 502, своя укладывается в замеры за 0,06 и 0,01 секунды. При её написании мы сами попались на две ловушки, `"" in "boxX"` и `z` у `-inf`, обе вошли в ручные тесты. - Замер скорости засчитывается, только если все ответы в нём верны. Медленных решений не было: все правильные укладываются в сотые доли секунды, а замеры проваливаются из-за неверных ответов. - Запрет на встроенное форматирование проверяется по коду и подменой `builtins.format`, а `str()` от float проверен отдельно подменой `str` на 3000 случаях: так не делает ни одно решение. - Первая попытка GPT-6.1 Sol оборвалась на шлюзе через 298 секунд без ответа, засчитана вторая. - Время и токены Opus-агентов оценочные: время по журналу агента, выходные токены по счётчикам API, рассуждение как выходные токены за вычетом кода. - Kimi K3.1 Pro исключён: Moonshot был перегружен с 10:05 до последней проверки в 12:21. ## Исключены из рейтинга - **Kimi K3.1 Pro** (0 из 502): Провайдер перегружен: с 10:05 до 12:21 Moonshot отвечал ошибкой 429 `engine_overloaded` на все 10 попыток отправить задание и на все пробные запросы из одного слова. Это сбой доступа, а не модели. Попытки сохранены в `answers/kimi-busy*.json`. ## Участники | Модель | Разработчик | ID | Доступ | Лимит ответа | |---|---|---|---|---| | Claude Opus 5.5 (агент) | Anthropic | `claude-opus-5-5` | субагент Claude Code, чистый контекст, без запуска кода | — | | Claude Opus 5.5 (агент, effort max) | Anthropic | `claude-opus-5-5` | субагент Claude Code, `effort: max`, чистый контекст, без запуска кода | — | | Kimi K3.1 Pro | Moonshot AI | `kimi-k3.1-pro` | API api.moonshot.ai (через VPN роутера) | 128K | | Qwen3.8-Max | Alibaba | `qwen3.8-max` | API token-plan.maas.qwencloudapi.com | 131.1K | | GPT-6.1 Sol | OpenAI | `gpt-6.1-sol` | партнёрский шлюз, `reasoning_effort: high` | 128K | | DeepSeek Flash (V4.1) | DeepSeek | `deepseek-flash` | API api.deepseek.com | 384K | | Claude Opus 5.5 (effort max) | Anthropic | `claude-opus-5-5` | партнёрский шлюз, нативный `/v1/messages`, `thinking: adaptive`, `effort: max` | 128K | ## Файлы | Путь | Что это | |---|---| | `README.md` | отчёт в формате Markdown | | `report.html` | страница отчёта с графиками | | `bench.json` | метаданные: участники, условия, нюансы и выводы, из них собирается отчёт | | `task/task.md` | задание, которое получили модели | | `harness/test_fmt.py` | скрытые тесты: ручные ловушки, генератор, проверка ограничений, замеры | | `harness/own/solution.py` | своя реализация без format(), проверка, что задача решается | | `harness/oracle/solution.py` | обёртка над настоящей format() для проверки стенда | | `answers/.json` | метаданные ответа: время и токены | | `solutions//solution.py` | код, который написала модель | | `grades/.txt` | результаты тестов и список падений |