Более подходящей темы не нашел. И разбудим тему:
Подходящий метод для масштабирования дроби?
У нас есть дробь: a/b
uint32_t a, uint32_t b
Есть условие, напр. b <= 0xFFFFF. нужно уменьшить знаменатель.
С калкуляторе: a/b = ((a * 1048575) / b) / 1048575
На компиляторе с uint64_t все как на листе с карандашом (Arduino IDE -> Arduino, AVR через Arduino IDE и др.). Но при компилятор без uint64_t (PIC CCS для выбранного микроконтроллера) нахожу трудности.
Вынужден либо считать с меньшими числами (/10 /100 /1000 ...) (шаг будет не самый маленький из возможных). Либо знаменатель и числитель напр /2, пока знаменатель не подходит. И следствие: потеря разрешения (напр. 1 Hz) или потеря точности.
Или иногда использую float. Опять же с некоторой точностью более-менее одинакова (6-7 знаков после запятой?). А не хочу- значительно увеличивает использование памяти и снижает скорость.
Код:if (b > 1048575) { // if b is too large -> data scaling uint64_t a64 = a; a64 = a64 * 1048575 / b; a = (uint32_t)a64; b = 1048575; }Любой другой простой, более точный способ? Цифры большие. Не могу их уменьшить. (Si5351, AD4351 ... )Код:while (b > 0xFFFFF) { // if b is too large а >>= 1; b >>= 1; }
--- --- ---
Пример:
a = 843 429;
b = 2 438 152;
---
max b = 1 048 575
--- --- ---
метод 1: a / b = 843 429 / 2 438 152 = (843 429 * 1 048 575) / (2 438 152 * 1 048 575) = 362 733 / 1 048 575 = 0,345929475 ...
метод 2: a / b = 843 429 / 2 438 152 = 421 714 / 1 219 049 = 210 857 / 609 538 = 0,345929211 ...
A так как у нас шаг 1 или 10 герц на VHF, то по второму способу вижу как шаг неровный и прыгает.
(Не то чтобы кварцевый резонатор и его температурный коэффициент не портят счет ...).
Вопрос принципиальный.