Программирование вычислительных алгоритмов

Тема в разделе "WASM.ASSEMBLER", создана пользователем 1212, 7 янв 2009.

  1. Partner

    Partner Павел

    Публикаций:
    0
    Регистрация:
    28 фев 2008
    Сообщения:
    917
    Адрес:
    Los Angeles
    Хочу знать :)
     
  2. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    В том контексте всё-таки "х*й знает"
     
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.787
  4. Ken

    Ken New Member

    Публикаций:
    0
    Регистрация:
    24 янв 2009
    Сообщения:
    7
    Уф, не поленился, написал.

    Код (Text):
    1. org 100h
    2.  
    3. mov ax, 0xFFFF          ; ffff = 1.999999
    4. push ax
    5.  
    6. mov bx, 0x2AAA          ; 1/6 factor
    7.  
    8. mul ax                  ; ax = x*x : ffff = 3,9999
    9. xchg ax, dx             ; dx = ax
    10. push ax
    11.  
    12.         mul bx
    13.         shr dx, 2
    14.         xor dx, 0x0FFF
    15.         mov cx, dx              ; cx = 1 - x*x/6 (в рамках, что ffff = 15,9999)
    16.  
    17. pop ax
    18.  
    19. mov bx, 0x0222
    20. mul ax                          ; ax = x^4
    21. xchg ax, dx
    22. mul bx                          ; dx = x^4 / 120 (рамки ffff = 15,9999)
    23. add cx, dx                      ; cx = 1 - x^2/6 + x^4/120
    24.  
    25. pop ax                          ; ax = x
    26. mul cx                          ; ax = x*(1 - x^2/6 + x^4/120)
    27. xchg ax, dx
    28.  
    29. ; выход: диапазон ax: ffff = 31,999...
    30. ;                     0001 = 0,00048828125
    31.  
    32. ; знак ставить в зависимости от того, какой был знак изначально
    33. ; то есть лучше брать положительное значение
    34.  
    35. ; Такая вот точность на 16-ти разрядных вычислениях
    Конечно, оптимизацию по скорости не делал, но точность приличная. Это еще с учетом того, что сам x-x^3/6+x^5/120 не очень хорошую точность выдает. Сам от себя не ожидал, если честно.
     
  5. 1212

    1212 New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2009
    Сообщения:
    21
    Добрый вечер всем Ассемблерщикам!
    Прошу простить за долгое молчание! Государева служба выбила из колеи на три недели!
    Большое спасибо всем, кто просматривал тему, особое спасибо всем, кто принял участие в обсуждении.
    Уважаемый Mikl___! Ваш пример можно брать за основу! Но следует быть осторожным с операцией деления содержимого таблицы на 10000. Дело в том, что если делить «в лоб» BX на 10000d по классическим правилам деления для процессоров ix86, то получим все нули. Необходимо продумать о перемещение содержимого выбранной ячейки таблицы в удвоенное делимое DX:AX для получения наилучшей точности. То есть поиграть с масштабами представления результатов. Вообще-то можно отказаться от деления, если в ячейки сразу записать двоичные значения синусов.
    И еще один нюанс! Практически во всех технических расчетах используют углы в радианах, а не в градусах.
    Быстродействие табличного метода получения значения функции самое большое. Однако сама таблица занимает очень много место в памяти!
    Уважаемый murder! Откровенно говоря, я мало, что понял в Вашей демке! Не могли бы Вы прокомментировать ее работу!?
    Уважаемый Ken! Будет ли Ваше программа (ой простите - разумеется прога) работать для отрицательных промежуточных переменных. Например,
    после mov cx, dx ; cx = 1 - x*x/6 (в рамках, что ffff = 15,9999) – в сх может быть отрицательное число. Как быть дальше?
    Вот мой пример реализации полинома y= x^5/120 -x^3/6+x для аргумента изменяющегося в диапазоне от -2 до +2.
    После упрощения имеем y=x*((x^2/6)*((x^2/20)-1)+1)
    mov ax,x
    mov bx,ax
    mov di,ax
    imul bx
    shld dx,ax,1
    sal ax,1
    push dx ;y1=x*x
    push ax
    ;----------------------------
    mov cx,5000h
    idiv cx ;y2=y1/20
    ;-------------------------------
    sar ax,3
    sub ax,4000h ;y3=y2-1
    mov bx,ax
    ;----------------------------
    pop ax
    pop dx
    mov cx,6000h
    idiv cx ;y4=y1/6
    ;--------------------------
    imul bx
    shld dx,ax,1 ; y5=y3*y4
    ;---------------------------------
    add dx,4000h ;y6=y5+1
    ;-------------------------------
    mov ax,di
    imul dx
    shld dx,ax,3 ; y=y7=y6*x
    mov y,dx
    В этом случае не надо думать о логике запоминания знака аргумента, выбора квадранта синуса, аргумент может изменяться во всем диапазоне с шагом 0001F. Ошибка 16-ти разрядной программы по сравнению с Exel-полином - 0,01%. Ошибка по сравнению с Exel-SIN(X) – 2,4% на краях интервала. Если сократить интервал до +-1,65, то есть приблизить к +- ПИ/2, при этом программу не переделывать - ошибка по SIN(X) уменьшится до 0,5% . Если чуть доработать программу для укороченного интервала аргумента с целью увеличения точности – ошибка уменьшиться до 0,2%
    Жду ваши комментарии коллеги!
    С уважением, 1212
     
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.787
    1212
    1) Фраза "Они должны быть разделены на 10000 перед использованием" подразумевала, что деление должно производится после умножения Sin(x) на что-то т.е. Y*Sin(x)/10000
    2) "Практически во всех технических расчетах используют углы в радианах, а не в градусах" ну и заполните таблицу значениями от Sin(x) в радианах :)
    3) "Однако сама таблица занимает очень много место в памяти!" в примере показано, как используя симметрию и значения синуса от 0 до 90º расчитывают синус от 0 до 360º - первоначальный вариант таблицы сокращен в 4 раза - аналогично, используя например тригонометрическое преобразование Sin(2*x)=2*Sin(x)*Cos(x)= 2*Sin(x)*Sin(x+90º) можно сократить число значений и в этой таблице в два раза - держать в таблице нечетные значения x, а четные равные 2*x считать по формуле либо расчитывать значение для четного значения х как среднее от двух нечетных значений между которыми он находится - уменьшение величины таблицы приведет в свою очередь к увеличению вычислительного алгоритма, продолжая уменьшать количество значений в таблице прийдем в конечном итоге к формуле Sin(x) = x - x³/3! + (x^5)/5! - (x^7)/7! + (x^9)/9! - ... уменьшение размера таблицы, приведет к пропроциональному возрастанию времени обработки и увеличению размера программы - ищите компромиссное решение
     
  7. 1212

    1212 New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2009
    Сообщения:
    21
    Уважаемый Mikl___ , спасибо за ответ!
    Вы совершенно правы, когда советуете искать оптимальный вариант программы определения значения функции в соединении табличного и вычислительного методов. В каждом конкретном случае необходимо искать свой оптимум.
    Методы сокращения объема таблиц функций хорошо описаны, например, в книге А.М. Оранского «Аппаратные методы в цифровой вычислительной технике» .
    Известные свойства синуса-косинуса можно использовать для сокращения числа основных ячеек таблицы. Достаточно рассмотреть значения в диапазоне от 0 до ПИ/4. Более подробно этот алгоритм расписан у Григорьева «Микропроцессор i486». Однако в приводимом у него практическом варианте есть ошибка в логике. Очень интересна книга В.В. Чекушин, О.В. Юрин, В.В. Булкин «Реализация вычислительных процессов в информационно-измерительных системах» (2005 года). Авторы этой книги, как я (я с ними не знаком), пришли к выводу, что для многих современных микропроцессоров лучше программировать вычислительные алгоритмы, тратя время на разработку математики.
    В этом смысле и была мною открыта тема. Мои примеры - вычисление с высокой точностью полиномов на машинах с фиксированной запятой, то есть с малой разрядностью. Меня очень интересует, вполне ли мои подходы приемлемы, есть ли другие подходы?