From fabbc8129c8b5fdfed4b60b90b74e1077eeb6ca1 Mon Sep 17 00:00:00 2001 From: Alexander Petrov Date: Tue, 30 Jun 2026 23:00:14 +0300 Subject: [PATCH] =?UTF-8?q?mdview2:=20percent=20=D0=BD=D0=B0=2016-=D0=B1?= =?UTF-8?q?=D0=B8=D1=82=D0=BD=D0=BE=D0=B9=20=D0=B0=D1=80=D0=B8=D1=84=D0=BC?= =?UTF-8?q?=D0=B5=D1=82=D0=B8=D0=BA=D0=B5=20(=D1=83=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=5F=5Fdivulong)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit calc_md_pct/calc_raw_pct тянули 32-битное деление __divulong (+__muluint2ulong) ради показа процента в статусе. Оба дают операнды ≤16 бит (≤18432 / ≤1024), переполняет только *100. Новый pct16() масштабирует оба вниз и считает долю циклом-вычитанием — 66 Б, НОЛЬ подтянутых арифм-хелперов. Точность ±1% (на границах точно), для индикатора прокрутки незаметно. Co-Authored-By: Claude Opus 4.8 --- examples/mdview2/mdview2.c | 17 +++++++++++++++++ examples/mdview2/mdview2.h | 1 + examples/mdview2/mdview2_md.c | 2 +- examples/mdview2/mdview2_raw.c | 9 ++++----- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/examples/mdview2/mdview2.c b/examples/mdview2/mdview2.c index 49c1621..c4ab922 100644 --- a/examples/mdview2/mdview2.c +++ b/examples/mdview2/mdview2.c @@ -284,6 +284,23 @@ void fill_row(uint8_t y, uint8_t attr) bios_clearwin(y, 0, 1, SCREEN_W, attr); } +/* Процент 0..100 = num*100/den на чистой 16-битной арифметике — чтобы НЕ + * тянуть 32-битное деление __divulong (~760 Б) ради показа процента в статусе. + * Оба вызова (MD/RAW) дают операнды, влезающие в 16 бит (≤18432 и ≤1024), + * переполняет только *100 — поэтому масштабируем оба вниз, пока num*100 не + * влезёт в uint16, затем считаем долю циклом-вычитанием (без div-хелпера). + * Инвариант вызовов: num ≤ den; результат всё равно ограничен 100. */ +uint8_t pct16(uint16_t num, uint16_t den) +{ + if (den == 0) return 0; + while (num > 655) { num >>= 1; den >>= 1; } /* num*100 ≤ 65500 < 65536 */ + if (den == 0) return 100; /* страховка от num>den */ + uint16_t n = (uint16_t)(num * 100u); + uint8_t p = 0; + while (n >= den && p < 100) { n = (uint16_t)(n - den); p++; } + return p; +} + /* Отображает указанную EMM-страницу файла в окно W3. * Если эта страница уже активна, переключение не выполняется. */ diff --git a/examples/mdview2/mdview2.h b/examples/mdview2/mdview2.h index de3d1ad..b40cec7 100644 --- a/examples/mdview2/mdview2.h +++ b/examples/mdview2/mdview2.h @@ -137,6 +137,7 @@ extern uint8_t g_scratch_phys; /* scratch EMM-страница для wi char fb(uint32_t p); /* байт активного буфера (W3-маппинг) */ void win_rest(uint8_t row, uint8_t col, uint8_t h, uint8_t w, uint8_t page, uint16_t off); void fill_row(uint8_t y, uint8_t attr); +uint8_t pct16(uint16_t num, uint16_t den); /* num*100/den (0..100), 16-бит, без __divulong */ uint32_t seg_off(uint16_t idx); /* offset исходника для логической строки idx */ /* ================================================================== * diff --git a/examples/mdview2/mdview2_md.c b/examples/mdview2/mdview2_md.c index a14c952..712d949 100644 --- a/examples/mdview2/mdview2_md.c +++ b/examples/mdview2/mdview2_md.c @@ -172,7 +172,7 @@ static uint8_t calc_md_pct(void) { uint16_t total = drawable_lines(); if (total <= VIEW_H) return 100; - return (uint8_t)((uint32_t)top_line * 100UL / (uint32_t)(total - VIEW_H)); + return pct16(top_line, (uint16_t)(total - VIEW_H)); } /* ---- навигация MD после загрузки (peer к raw_key) ---------------- */ diff --git a/examples/mdview2/mdview2_raw.c b/examples/mdview2/mdview2_raw.c index d94865b..ba1c6c0 100644 --- a/examples/mdview2/mdview2_raw.c +++ b/examples/mdview2/mdview2_raw.c @@ -161,15 +161,14 @@ static uint32_t raw_prev(uint32_t off) /* ---- статус-бар: % по байтам (отрисовка — render_raw_status_numbers * в mdview2_status.c, читает позицию через этот raw_pct) ---- */ -/* Процент по байтам без 32-битного деления: масштабируем offset'ы (>>8), - * дальше 32-битная арифметика. raw_top приватен модулю, поэтому % считаем - * здесь и отдаём готовым числом в статус-модуль. */ +/* Процент по байтам без 32-битного деления: масштабируем offset'ы (>>8 → + * ≤1024), дальше 16-битный pct16 (без __divulong). raw_top приватен модулю, + * поэтому % считаем здесь и отдаём готовым числом в статус-модуль. */ uint8_t calc_raw_pct(void) { uint16_t a = (uint16_t)(raw_top >> 8); uint16_t b = (uint16_t)(file_size >> 8); - if (b == 0) return 0; /* файл < 1 КБ */ - return (uint8_t)(a * 100UL / b); + return pct16(a, b); /* den==0 (файл < 1 КБ) → pct16 вернёт 0 */ } /* ---- посев позиции / пересев при смене активного буфера ----------- */