Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm: Общие вопросы > Возведение в степень


Автор: Дрон 24.4.2004, 21:24
Подскажите, пожалуйста, как написать кусок кода (на асме smile.gif ), выполняющий возведение в степень для чисел с плавающей точкой одинарной точности (4 байта, тип float в Си). Только без вызовов каких-либо функций. Но, естественно, с использованием математического сопроцессора smile.gif


Автор: Chingachguk 24.4.2004, 22:15
Цитата

  mov  eax,2 ; степень - 2
  call get_pow ; вернется в ST(0) квадрат

...

; ** get_pow: Подпрограмма возведения в целую степень числа *****
; ST(0) - аргумент, eax - степень
; result: ST(0)
; Для возведения в произвольную стпень числа следует воспользоваться
; более сложным алгоритмом с использованием fyl2x:
; см., например, П.И. Рудаков, К.Г. Финогенов
; "Программируем на языке ассемблера IBM PC"
.code
get_pow proc
  test eax,eax
  jnz  @@NoZeroPower
  fstp ST(0) ; Вытолкнуть аргумент из стека
  fld1 ; Загрузить 1.0
  ret ; Вернуть 1.0
@@NoZeroPower:
  push ecx
  mov  ecx,eax
  ; Сделать степень положительной
@@NegLoop: 
  neg  ecx
  js  @@NegLoop
  fld1 ; Загрузить 1.0, ST(0) - накопитель
@@get_pow:
  fmul ST(0),ST(1) ; Накопитель=Накопитель x arg
  loop @@get_pow
  fxch ST(1) ; Поменять накопитель и аргумент
  fstp ST(0) ; Вытолкнуть аргумент из стека
  ; Если степень отрицательна, необходимо
  ; Накопитель=1/Накопитель
  cmp  eax,0
  jge  @@NoNegPow
  fld1 ; Загрузить 1
  fxch ST(1) ; Обменять ST(1) и ST(0)
  fdivp ST(1),ST(0) ; Разделить 1 на Накопитель
@@NoNegPow:
  pop  ecx
  ret
get_pow endp 

Автор: Дрон 25.4.2004, 10:10
Это цитата из твоей статьи на WASM.RU smile.gif Ты мне её ещё год назад посоветовал, но по другому поводу smile.gif

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

Добавлено @ 10:12
Цитата
см., например, П.И. Рудаков, К.Г. Финогенов
; "Программируем на языке ассемблера IBM PC"

А вот нашёл эту книжку. Сейчас скачаю, посмотрю.

Автор: Дрон 25.4.2004, 11:25
Хмм... В том, что я скачал ничего толкового не нашёл sad.gif

Автор: Chingachguk 25.4.2004, 17:29
Там глава про сопроцессоры - ты ее видишь ? Там есть статья 82 "Использование сопроцессора для реализации операции возведения в целую положительную степень".

Автор: Дрон 25.4.2004, 20:40
Вот оно что! В том архиве было только 58 статей. Буду искать другой...

Автор: Дрон 30.4.2004, 18:06
Книжку я так и не достал.
Но, поразбиравшись с инструкциями FPU, написал вот такое:
Код
fld показатель
fld основание
fyl2x
fld st(0)
frndint
fld st(0)
fsub st(2)
fxch
f2xm1
fld1
fadd
fscale
fstp st(1)
Результат будет в st(0).
Всё оказалось очень просто.

А для возведения числа с плавающей точкой в целую степень написал вот такое.
Оно намного эффективней того, что привёл ты. Тут сложность O(log2(n)), а у тебя O(n).
Регистры si и di я использовал потому, что в контексте проги остальные были заняты.
Показатель -- слово со знаком.
Код
    mov si, показатель
    bt  si, 15
    fld основание
    fld1
    jnc Positive
    neg si      
    fdivr      
    fld1        
Positive:
    bsr di, si
    jz ZeroPower
    xor cx, cx
    jmp LoopL
DoMul:
    fxch
    fmul st(0),st(0)
    fxch
LoopL:
    bt  si, cx
    jnc SkipL
    fmul st(0), st(1)
SkipL:
    inc cx
    cmp cx, di
    jle DoMul
ZeroPower:
    fstp st(1)

Результат, опять же, в st(0)

Короче, ассемблер рулит! smile.gif

PS. Сначала во второй процедуре я написал bt si,15 непосредственно перед jnc Positive потом, подумав, переместил туда, где оно сейчас. В результате время выполнения процедуры уменьшилось на 3% smile.gif

Автор: Sail 15.5.2004, 20:07
Я чего то это не понял:
Код

fld показатель
fld основание
fyl2x
fld st(0)
frndint
fld st(0)
fsub st(2)
fxch
f2xm1
fld1
fadd
fscale
fstp st(1)

Почему нельзя проще:
Код

fld показатель
fld основание
fyl2x
f2xm1
fld1
faddp

Результат останется в ST(0)

Автор: Дрон 16.5.2004, 10:47
Sail
Так нельзя потому, что для команды f2xm1 степень должна находиться в промежутке от -1 до 1.
Поэтому в своей процедуре я отдельно возвожу в целую часть показателя (через fscale) и отдельно в дробную (через f2xm1).

Автор: Jin X 30.7.2004, 21:42
Пару дней назад как раз нужно было написать универсальную процедуру возведения в степень, так что ловите исходник!
Возводит любые числа в любую степень (ну отрицательные числа в нецелую степень, естественно, не возводит... их никто вам не возведёт biggrin.gif).
И безо всяких циклов ;)
Файл можно стянуть вот отсюда: http://filezzz.nm.ru/pub/asm/fpower.zip

Автор: Дрон 30.7.2004, 23:20
Jin X
Ну так у меня тоже безо всяких циклов -- первый пример для нецелой степени.
А второй хоть и с циклом, но работает быстрее первого для целой степени.

В моём коде, разве что, нет никаких проверок на обшибку, а в остальном моё ничем не хуже smile.gif

Автор: Jin X 31.7.2004, 17:59
Хе-хе, вот именно, что нету проверок smile.gif
К тому же, у тебя при попытке возвести в любую степень ноль или отрицательные числа будет глюк. Т.к. логарифма от этих чисел нет cool.gif

Автор: Дрон 31.7.2004, 23:13
У меня цель была написать наименьший и наибыстрейший код для динамической генерации процедуры вычисления введённой формулы, а за корректностью пусть пользователь сам следит, или её можно проверять в момент разбора выражения (т.е. один раз) smile.gif

Автор: Jin X 1.8.2004, 21:40
Ладно, проверяй. Только отрицательные числа тоже можно возводить в степень (целую), как и ноль. А на юзера рассчитывать глупо, по-моему.
Используй что хочешь, мне нужно было это сделать, я сделал, а сюда написал на случай, если кому пригодится, вот и всё smile.gif

Автор: Дрон 1.8.2004, 22:52
Jin X
Да я же не настаиваю. Просто цели были разные.
И от твоего, в общем случае толку получается больше.
Так что спасибо, может когда-нибудь и проверка понадобится smile.gif

Автор: Ratty 14.6.2005, 14:06
Так получилось, но я завязан на эмулируемой целочисленной 128 битной арифметике (фиксированная точка). Помогите, пожалуйста, получить хотя-бы табличные значения факториал / мантисса для степени 4/3 произвольного числа. У меня есть 128 бит сложение, вычитание, умножение и т.д. в пределах разумного. Вспоминая правила степеней РЕЗУЛЬТАТ = X * X * X * X. Но как из РЕЗУЛЬТАТА найти кубический корень? Где-то встречал правило извлечения квадратного корня - есть ли что-то подобное для кубического корня?
Скорость алгоритма не интересует, только точность.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)