Перейти к содержанию
    

Операции над большими числами

Правильно так: (5050/10^8)*2^28 =0x13BA0000000/0x5F5E100=0x34F4=13556

А я вот тут подумал, а если подойти к задаче с дугой стороны.

Я посмотрел, что прибавление или вычитание из кода идет с шагом или 2 или 3.

Закономерность вроде как тоже есть.. Изменение на 2 происходит после двух подряд изменений на три и так пять раз, после чего три раза подряд изменение на три и цикл снова..

2333 233 233 233 233 233 23332......

Может быть по такому пути проще идти и не городить огород со сложной математикой..

Только как бы это привязать к какому либо значению?? Или придется тупо на каких то хитрых циклах делать??

Изменено пользователем NickSmith

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Только как бы это привязать к какому либо значению?? Или придется тупо на каких то хитрых циклах делать??

Фигней не надо заниматься, а ? Всего-то нужно тривиальное деление 40 / 20 битов. Простейший цикл сдвиг-сравнение-вычитание.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Фигней не надо заниматься, а ? Всего-то нужно тривиальное деление 40 / 20 битов. Простейший цикл сдвиг-сравнение-вычитание.

А по подробней можно??

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А по подробней можно??

Ну как делается деление "столбиком" ? Так и здесь - сдвигаем делимое в накопитель остатка, сравниваем остаток с делимым, если больше либо равен - вычитаем делимое из остатка и записываем "1" в результат. Иначе не вычитаем и записываем "0". Для удобства регистр делителя и результата совмещается, по окончанию операции частное будет в том же накопителе. Реализации под конкретную платформу - практически всегда есть в аппликухах...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну как делается деление "столбиком" ? Так и здесь - сдвигаем делимое в накопитель остатка, сравниваем остаток с делимым, если больше либо равен - вычитаем делимое из остатка и записываем "1" в результат. Иначе не вычитаем и записываем "0". Для удобства регистр делителя и результата совмещается, по окончанию операции частное будет в том же накопителе. Реализации под конкретную платформу - практически всегда есть в аппликухах...

Т.е делать все по формуле..

Хорошо, а как быт с округлением результатов? у меня же ведь на выходе получается число с запятой.. А в демо программе, как я понял результат расчетов округляется или в большую или в меньшую сторону?

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

Я делаю это на tiny2313 там есть пример математики с большими числами.. Но он очень громоздок.. Что то строк под 150 по моему.. По этому я и подумал пойти простым путем и поиграть с увеличением или уменьшением готовой константы.. Кода по моему всяко меньше получится??

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

Приближение действительного числа рациональными дробями с заданным ограничением для знаменателя

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

tiny2313

Взяли бы мегу восьмую и писали на WinAVR - достаточно эффективные встроенные функции деления 64/64 есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Т.е делать все по формуле..

Хорошо, а как быт с округлением результатов? у меня же ведь на выходе получается число с запятой.. А в демо программе, как я понял результат расчетов округляется или в большую или в меньшую сторону?

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

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

Я делаю это на tiny2313 там есть пример математики с большими числами.. Но он очень громоздок.. Что то строк под 150 по моему..

Жуть какая... Вот деление 32 / 16. Добавить по одному регистру в делимое, частное и остаток, будет требуемые 40 / 24...

;----------------------------------------------------------------------
; Деление XH:XL:YH:YL / ZH:ZL
; Используются регистры r0, r1, temp
;----------------------------------------------------------------------

Div32:
          clr     r0
          clr     r1
          ldi     temp,32             ; счетчик
Div32_1:
          lsl     YL
          rol     YH
          rol     XL
          rol     XH                  ; сдвиг делимого
          rol     r1
          rol     r0                  ; и остатка (r0:r1)
          cp      r1,ZL
          cpc     r0,ZH               ; можно вычесть делитель ?
          brlo    Div32_2             ; нет
          ori     YL,$01              ; иначе "1" в частное
          sub     r1,ZL
          sbc     r0,ZH
Div32_2:
          dec     temp
          brne    Div32_1             ; цикл деления

; В XH:XL:YH:YL содержится результат деления

          ret

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Жуть какая... Вот деление 32 / 16. Добавить по одному регистру в делимое, частное и остаток, будет требуемые 40 / 24...

Огромное спасибо за пример..

Но я все равно под запутался. Выше писали:

Правильно так: (5050/10^8)*2^28 =0x13BA 0000 000/0x5F5E100=0x34F4=13556

Но получается не 0x34F4, 0x34F3

Вот если взять делимое на 1 ноль больше, то результат будет 0x34f3f

Если младшую тетраду младшего байта как то обрабатывать по условию, то и получится округление.. Прав??

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но получается не 0x34F4, 0x34F3

Вот если взять делимое на 1 ноль больше, то результат будет 0x34f3f

Если младшую тетраду младшего байта как то обрабатывать по условию, то и получится округление.. Прав??

Мать-перемать... Ну сколько можно объяснять ? Надо взять делимое вдвое больше (умножить на 2^29), а потом частное поделить еще на 2 сдвигом вправо, и по состоянию переноса прибавить или не прибавляь 1 (т.е. для avr сделать adc. Для приведенной мной программы - lsr xh ror xl ror yh ror yl adc yl,temp adc yh,temp adc xl,temp adc xh temp). Конеччно, это можно сделать и контролем остатка, но так - проще. Естественно, в примере с конкретными числами разрядность можно сократить на 8 битов, поэтому достаточно деление 40 / 24.

Изменено пользователем rx3apf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мать-перемать... Ну сколько можно объяснять ? Надо взять делимое вдвое больше (умножить на 2^29), а потом частное поделить еще на 2 сдвигом вправо, и по состоянию переноса прибавить или не прибавляь 1 (т.е. для avr сделать adc. Для приведенной мной программы - lsr xh ror xl ror yh ror yl adc yl,temp adc yh,temp adc xl,temp adc xh temp). Конеччно, это можно сделать и контролем остатка, но так - проще. Естественно, в примере с конкретными числами разрядность можно сократить на 8 битов, поэтому достаточно деление 40 / 24.

Все, теперь понял ход вашей мысли..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все, теперь понял ход вашей мысли..

Если я правильно понял, нужно вычислять выражение вида a*b/c, где a - частота, которую нужно получить, b - разрядность 28 bit, c - частота кварца. Причём, b и c - константы. вычисляем b/c = 2^28/10^8 = 2.68435456. Получается, нужно только одно умножение a*k, где k=2.68435456. проверяем для 5050*k=13555.990528.

Так как плавающая точка всё равно не нужна и в синтезатор загружаем целые числа, то вместо k надо взять N=k<<16 или k<<24 или сколько там нужно разрядов для этого синтезатора, и работаем только с целочисленным умножением. Пример для 16-bit результата: N=k*2^16=0x2AF32, 5050*N=0x34F40054, старшие два байта и есть искомое 0x34F4

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если я правильно понял, нужно вычислять выражение вида a*b/c, где a - частота, которую нужно получить, b - разрядность 28 bit, c - частота кварца. Причём, b и c - константы. вычисляем b/c = 2^28/10^8 = 2.68435456. Получается, нужно только одно умножение a*k, где k=2.68435456. проверяем для 5050*k=13555.990528.

Так как плавающая точка всё равно не нужна и в синтезатор загружаем целые числа, то вместо k надо взять N=k<<16 или k<<24 или сколько там нужно разрядов для этого синтезатора, и работаем только с целочисленным умножением. Пример для 16-bit результата: N=k*2^16=0x2AF32, 5050*N=0x34F40054, старшие два байта и есть искомое 0x34F4

Изящный способ, но у него с округлением проблемы... А у меня это критично.. Хотя так конечно было бы проще..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Изящный способ, но у него с округлением проблемы... А у меня это критично.. Хотя так конечно было бы проще..

С округлением всё просто, стрший бит отбрасываемой части прибавляем к результату, и всё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С одним вроде как все понятно теперь, но вот теперь засада с другим вычислением..

 

Для вычисления значения фазы существует формула:

значение регистра фазы = (значение фазы *4096)/2Пи и Но получается полная ерунда.. С их расчетами никак не сходится.. Например значение регистра для фазы 90 градусов получается 0х0400 в их примерах.

Если же делать по этой формуле то получается 58671 или 0xE52F

Что не так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...