This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

IQmath question



Hi Team,

I try to testing the IQmath performance,and get below result;

float A;

int  B;

_Iq18  temp1, temp2;

temp1 = _IQ18(A);        //this instruction  spend  248 cycle

temp2 = _IQ18(B);        //this instruction  spend  271 cycle

float to IQ and int to IQ spend too many instruction cycle, may i know  this is normal or not?

Any method to improve the _IQ(A) and _IQ(B) instruction  performance?

  • Hi, 

    The way the _IQnn(A) function is defined it casts the argument A as a long double and then multiplies it by a double precision value of 2^(nn) and then casts the result back to long- the double precision operations take a while to execute.

    Now if you know A is an int, you could cast it to long and then left shift by 18 to get the same result. If its float then just multiply it by 262144.0F - the F at the end indicates this is a single precision float value (2^18) and forces the compiler to do a single precision multiply; if you have a hardware FPU on the device this operation take 2 pipeline cycles and is pretty fast.

  • Hi Viahal,

    Thanks for your kindly help!

    From the IQmath user guide,  _IQN(float F) the argument is Floating point variable or constant.

    When A is float, I tried the methold as you mentioned A* 262144.0F , for Piccolo A without FPU the execution cycle is 166 still too long.

  • Huihuang Chen said:
    When A is float, I tried the methold as you mentioned A* 262144.0F , for Piccolo A without FPU the execution cycle is 166 still too long.

    Without the hardware FPU the multiplication must be done in software by a standard C library call; if i remember correctly the Library call is an assembly function so there may not be any way to speed it up (through optimization options). For the pic A it is advisable to stick with fixed point math whenever possible.

    There is one possibility to handle this multiplication - i haven't tried this nor do i know anyone else who has:

    IQ18(A) is the process of multiplying A by a power of 2 (2^18 = 262144.0F) it is expressed in floating point notation as +1.0 x 2^18, so the sign and mantissa are both 0 and this number just has the biased exponent of 145 (127 + 18). The hex representation is 0x48800000.

    A is represented as +-1.nnnnn x 2^(E-127). Lets say A = -0.785.....this is -1.57 x 0.5 or -1.57 x 2^-1. In IEEE 754 notation this is -1.57 x 2^126 (0xbf48f5c3)

    Multiplying the two,

      -1.57 x 2^(-1 + 127) x +1.0 x 2^(18 + 127) = -1.57 x 2^(17 + 2x127) // we have added the bias twice

                                                                         = -1.57 x 2^(271 - 127)    // normalizing

                                                                         = -1.57 x 2^144

                                                                         = -205783.04                  // correct answer A * 2^18

    Now the standard C function does not know you are multiplying by a power of two so it does the multiplication of the mantissa (-1.57 x1.0) which is uncessary in our case. All we have to do is add the exponents of the two number and normalize to get the answer, we do this as follows

    typedef union _float32_t
    {
        float f32;
        unsigned long ui32;
        long i32;
    }float32_t
    
    float32_t A = -0.785; // test
    
    #define CUSTOM_IQ18(A)  {      \
        A.ui32 |= ((A.ui32 >> 23)& 0x7F)+ 18U) << 23;   
        // A.ui32 >> 23 shifts the biasd exponent to the lowest byte
        // &7F masks off the exponent; we dont care about the sign bit
        // +18U is equivalent to multiplying by 2^18 
        // <<23 shifts the new exponent back to its expected location
        // A.ui32 |=  will just replace the original exponent with the result
    }
    
    int main()
    {
    
        float B, C;
        
        // test
        B = CUSTOM_IQ18(A)
        
        C = A * 262144.0F;
        
        if(B == C) //There might be a very small deviation 
        {
            //yay
        }
    }

    NOTE: i dont check boundary conditions here, i assume A is a normal number, and the process of converting to IQ18 results in a normal number; the downside of the method ive outlined is it doesnt check boundary conditions while the C lib function does.

  • Vishal,

    Noted and Thanks a lot!