News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

A piece of code for the calculation of power.

Started by akalenuk, July 12, 2006, 03:52:24 PM

Previous topic - Next topic

akalenuk

I did this before, it was somehow like this:


                               FILD j
                               FLD1
                               FADD iVarn
                               FYL2X
                               F2XM1
                               FLD1
                               FADD         ; (i+1)^j

But now it does not work propertly.
Where am i wrong?

dioxin

This is the code I use.
' Create the control WORD TO truncate when rounding.
' Only needs to be done once, not eveytime you do the calculation
!fstcw   MaskedCW&
!OR      MaskedCW&, &b110000000000
!fstcw   SaveCW&        ;save a copy of the initial control word so it can be put back

..
..

' calculate a# ^ b#
!fld b#                 ;push the 2 operands onto the FP stack
!fld a#
!fyl2x                  ;Compute x*lg(y)

!fldcw   MaskedCW&      ;Modify the control WORD TO truncate when rounding
!fld     st(0)          ;Duplicate top of stack
!frndint                ;Compute INTEGER portion.
!fsubr    st(0), st(1)  ;Compute fractional part.

!f2xm1                  ;Compute 2**FRAC(x)-1.
!fld1
!fadd                   ;Compute 2**FRAC(x).

!fscale                 ;Compute 2**INT(x) * 2**FRAC(x).

!fldcw   SaveCW&        ;Restore rounding mode.

!fstp x#                ;pop the answer off the FP stack
!fstp  st(0)            ;clean up the stack (there's 1 value left on it)

ChrisLeslie

akalenuk,

I had adapted Ray's theory to use in a FASM macro:
Quotemacro powerFloat x,y,result  ; x^y = 2^(log2(x) * y))
{
    finit
    fld y          ; st0=y
    fld x          ; st0=x, st1=y
    fyl2x          ; st0=log2(x)*y
             ; now get the antilog2 of the logarithm in st1
      fst st1          ; st0=st1=log2(x)*y
      frndint          ; st0=int, st1=log2(x)*y. - keep only the integer in st0
      fsub st1,st0       ; st0=int, st1=fraction. - keeps only the fraction in st1
      fxch st1          ; st0=fraction, st1=int. - get the mantissa on top

      f2xm1          ; st0=2^st0-1, st1=int. - 2^(mantissa)-1
      fld1          ; st0=1, st1=2^st0-1, st2=int
      faddp          ; st0=2^st0, st1=int
      fscale          ; st0=x^y, st1=int. scale it with the integer
      fwait
    fstp result
}

I actually had not got around to testing this properly. Perhpas you could test it for me after translating to MASM if need be  :bg

Chris

zooba

I've copied this straight out of my Expression Evaluator code (the integer code simply used a loop, which is much more efficient for small integer powers):

fld     QWORD PTR [esp]
fld     QWORD PTR [esp+8]
fyl2x
fld     st
frndint
fsub    st(1),st
fxch    st(1)
f2xm1
add     esp, 8
fld1
fadd
fscale
fstp    st(1)
fstp    QWORD PTR [esp]


Note that I take the parameters directly off the stack and put one back on the stack, hence the add esp, 8 in the middle of it. The fld's and fstp's can be modified.

Cheers,

Zooba :U

akalenuk

Quote from: dioxin on July 12, 2006, 11:45:28 PM

!frndint                ;Compute INTEGER portion.
!fsubr    st(0), st(1)  ;Compute fractional part.


I simply don't understand why it is importrant to split a number to integer and fractional part. Looking at the code i see it is a thing that shoud be done, but why?

akalenuk

Quote from: ChrisLeslie on July 13, 2006, 12:28:47 AM

      faddp     ; st0=2^st0, st1=int

Here's "fadd", not "faddp". The rest is perfect! Works fine.
I still don't get this splitting issue. Looks like that is why my own code is wrong.

dioxin

akalenuk,
   it's a hardware restricion. The F2XM1 opcode only works on values between +1 and -1 so you need to split the integer part off, do the 2^x on the fractional part and then adjust the result by shifting left or right by the integer part (that's what SCALE does)

Paul.

akalenuk

Quote from: dioxin on July 13, 2006, 05:15:11 PM
   it's a hardware restricion. The F2XM1 opcode only works on values between +1 and -1 so you need to split the integer part off, do the 2^x on the fractional part and then adjust the result by shifting left or right by the integer part (that's what SCALE does)
Right! Previously i used my piece of code in economical calculation, where that powered value always been between 0 and 1. No wonder,i didn't see any bugs. Now i'm working with arbitrary numbers, so that code is no good anymore.

That's why i love assembly. Everything is so logical, when you got there  :bg

ChrisLeslie

akalenuk

QuoteHere's "fadd", not "faddp". The rest is perfect! Works fine.

There appears to be little quirk with MASM assembler where FADD without operands can also be used as FADDP ST(1),ST(0). The posted FASM code with FADDP, no operands, works fine in FASM.

Chris