minxomat

Details on how AutoIt handles fractional exponents.

5 posts in this topic

I've implemented a certain algorithm which uses fractional exponents (PowF(float, float)) to calculate intermediate values.

Now I'm trying to convert this calculation (from AutoIt) to simple ASM instructions. Since PowF is quite a complex operation in ASM, because you have to balance instruction count and error (which should be less than 16bit precision in this case), I'd like to know more about the implementation of fractional exponents in AutoIt itself. The goal is to accurately recreate the results AutoIt would produce given the same input values :)

If there are multiple different ways each calculation is handled given the size of the exponent, I'll only need the details for n^{0.9..1.5}. My approach would be to use a simple cvtps2dq SSE cycle, but I'm curious  :sorcerer:


I will answer every single PM, and you are free to ask anything anytime.

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

According to the latest (...) AutoIt 3.1 source code

case OPR_POW:                           // ^
            vOp2 = valStack.top();  valStack.pop();
            vOp1 = valStack.top();  valStack.pop();

            if ( vOp2.fValue() == 0.0 )
                vOp1 = 1.0;
            else if ( vOp1.fValue() == 0.0 && vOp2.fValue() < 0.0)
            {
                //double fTmp = 0.0;    // needed to prevent compiler error.

                //vOp1 = 1.0/fTmp;  // invalid.  Return 1.#INF by forcing divide by 0. GIVES COMPILER WARNING
                vOp1 = 0.0;
            }
            else if ( vOp1.fValue() < 0.0 && (vOp2.type() == VAR_INT32 || vOp2.type() == VAR_INT64) ) // integer (32 or 64 bit)
            {
#ifdef _MSC_VER
                // MS Compiler
                vOp1 = qmathPow(qmathFabs(vOp1.fValue()), vOp2.fValue());
#else
                vOp1 = pow(fabs(vOp1.fValue()), vOp2.fValue());
#endif
                if (vOp2.nValue() & 1) // odd number
                {
                    vOp2 = -1.0;
                    vOp1 *= vOp2;
                }
            }
            else
#ifdef _MSC_VER
                // MS Compiler
                vOp1 = qmathPow(vOp1.fValue(), vOp2.fValue());
#else
                vOp1 = pow(vOp1.fValue(), vOp2.fValue());
#endif

            valStack.push(vOp1);
            break;
, AutoIt uses 

double _QMATH_LINK qmathPow(double __x, double __y)
{
    __asm fld       qword ptr [esp + 12]
    __asm fld       qword ptr [esp +  4]
    __asm ftst
    __asm fstsw     ax
    __asm sahf
    __asm jz        pow_zero

    __asm fyl2x
    __asm fld1
    __asm fld       st(1)
    __asm fprem
    __asm f2xm1
    __asm faddp     st(1), st(0)
    __asm fscale

pow_zero:

    __asm fstp      st(1)
    __asm ret       16
}
as long as it is compiled using a MSVC compliant compiler. Is this still the case? Edited by minx

I will answer every single PM, and you are free to ask anything anytime.

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

I'll just answer this for myself by testing. It seems to still use MSVCs qmath.h or similar native library implementation:

 

#include <AssembleIt.au3>

Local $double_qmathPow
Local $asmstrc = DllStructCreate("double __x;double __y;")
$asmstrc.__x = 5.8
$asmstrc.__y = 0.9535

Func _QMATH_NAKED__QMATH_INLINE_double__QMATH_LINK_qmathPow()
    _("             use32               ")

    _("             fld qword[esp+12]   ")
    _("             fld qword[esp+4]    ")
    _("             ftst                ")
    _("             fstsw ax            ")
    _("             sahf                ")
    _("             jz pow_zero         ")

    _("             fyl2x               ")
    _("             fld1                ")
    _("             fld st1             ")
    _("             fprem               ")
    _("             f2xm1               ")
    _("             faddp st1, st0      ")
    _("             fscale              ")

    _(" pow_zero:                       ")
    _("             fstp st1            ")
    _("             ret                 ")
EndFunc

;_AssembleIt($double_qmathPowurntype, $Name_of_Func_with_code, $Type1 = "type", $Param1 = 0, $Type2 = "type", $Param2 = 0....up to 20 params)
$double_qmathPow    = _AssembleIt("double", "_QMATH_NAKED__QMATH_INLINE_double__QMATH_LINK_qmathPow", "double", $asmstrc.__x, "double", $asmstrc.__y)  ;thats all^^
$double_autoit      = $asmstrc.__x ^ $asmstrc.__y

ConsoleWrite(@LF)
ConsoleWrite("+> (FASM)qmathPow: " & $double_qmathPow & @LF)
ConsoleWrite("+> (AutoIt)^     : " & $double_autoit & @LF)
Edited by minx

I will answer every single PM, and you are free to ask anything anytime.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

K, but the results are effectively the same :) (It works fine in this scenario.)

Edited by minx

I will answer every single PM, and you are free to ask anything anytime.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now