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 and negative zero

Other Parts Discussed in Thread: TMS320DM6435

I am having a problem working with "negative zero" and the TI IQmath library.  In particular, float negative zero isn't surviving a round trip conversion.  It starts as float -0.0, goes to its iq value, and then go back to float as -2.0.

Does anyone have any suggestions on how to work in a scenario when your floats could be negative zero?

Here is an example that demonstrates the behavior in debug mode (-g -mi1 -mv6400+ -d"_DEBUG").  I have not chosen a "Floating Point mode" in the build compiler options.

#include "IQmath.h"
#include <stdio.h>

int main()
{
    float const zero = 0.0f;
    float const negZero = -zero;
    _iq21 const negZeroIq = _FtoIQ21(negZero);
    float const negZeroIqFl = _IQ21toF(negZeroIq);

    unsigned int const negZero_bytes = *reinterpret_cast<unsigned int const *>(&negZero);
    unsigned int const negZeroIq_bytes = *reinterpret_cast<unsigned int const *>(&negZeroIq);
    unsigned int const negZeroIqFl_bytes = *reinterpret_cast<unsigned int const *>(&negZeroIq);
   
    printf("negZero: %f (0x%x) -> %d (0x%x) -> %f (0x%x)\n", double(negZero), negZero_bytes, negZeroIq, negZeroIq_bytes, double(negZeroIqFl), negZeroIqFl_bytes);
    // displays 0.000000 (0x80000000) -> -4194304 (0xffc00000) -> -2.000000 (0xbfffffff)

    return 0;
}

Basically float negative zero is represented by the bytes 0x80000000.  I believe it is the logic inside _FtoIQN that gives me a problem when dealing with this value.

Although I use _iq21, I think that the other Q formats would have a similar problem.

IQmath release ver 2.1.4

TMS320DM6435

Code Composer 3.3.82.13, Integrated Development 5.98.0.393 TI, BIOS 5.41.02.14, Code Generation Tools v6.1.20, Board Revision (00.00.84), Target Silicon Revision (00.00.02)

 

Here is the inline of _FtoIQN for easy reference:

/*;;###########################################################################
;;
;; FILE:    FtoIQN.c
;;
;; TITLE:   C Callable IQ to Float Math Function
;;
;;===========================================================================
;; Function:   _FtoIQN
;;===========================================================================
;;
;; C Usage:    extern int _FtoIQ(float A);   // no round or sat
;;
;;---------------------------------------------------------------------------
;;
;; On Entry:   A4    = IEEE 754 floating-point equivalent of A
;; On Exit:    A4    = A in IQ format
;;                      
;; Q range:    31 to 1
;;
;;---------------------------------------------------------------------------
;; Algorithm:  This operation converts an IEEE 754 Single-Precision
;;             floating-point number to equivalent IQ number. This
;;             format is shown below:
;;
;;              31  30        23 22                                 0
;;             +-----------------------------------------------------+
;;             | s |      e     |                 f                  |
;;             +-----------------------------------------------------+
;;
;;             Value = (-1)^s * 2^(e-127) * 1.f
;;
;;             where: e = 1 to 254, f = 0.000000000 to ~1.0
;;                    e = 0, f = 0, s = 0, Value = 0.0
;;                    e = 0 and f != 0 case cannot occur in IQ math
;;                    e = 255 case cannot occur in IQ math
;;         
;;--------------------------------------------------------------------------*/

static inline I32_IQ _FtoIQN(float input, U32_IQ qfmt)
{
#ifdef _TMS320C6X

    U32_IQ al, x, temp1, temp2, sbits, e, imp=1;
    I32_IQ ah;
    x = _ftoi(input);     // Re-interprits the bits in float as an unsigned int
    temp2 = x & 0xc0000000u;        //stores the sign and hidden bit
    if(x == 0)
    {
        imp = 0;
    }

    /* ======================================================================== */
    /*  extract the exponent(sbits) & hidden bit                                */
    /* ======================================================================== */
   
    sbits = _extu(x, 1u, 24u);
    if(sbits < 128u)
    {
        temp2 = temp2 ^ 0x40000000u;
    }

    /* ======================================================================== */
    /*  find the no. of bits by which the final result has to be shiftehd        */
    /* ======================================================================== */
   
    e = 127u + (30u - qfmt);
    sbits = e - sbits;

    /* ======================================================================== */
    /*  arrange for representtion in Q-Format                                   */
    /* ======================================================================== */

    temp1 = x & 0x07fffffu;
    al = temp1;
    al = al << 7u;
    al = al | temp2;

    /* ======================================================================== */
    /*  if then sign is -ve complement the bits except sign bit                 */
    /* ======================================================================== */

    if(((temp2 >> 31u) != 0) && (temp1 != 0u))
    {
        al = al ^ 0x7fffff80u;
    }
    ah = (I32_IQ)al;
    ah =  ((I32_IQ)ah >> sbits);    //shift right by sbits
    ah = ah * (I32_IQ)imp;
    return(ah);

#else /* For host. (since no equivalent of _ftoIQ() exists */
    I32_IQ res;
    res = input * (1 << qfmt);
    return(res);
#endif /* _TMS320C6X */

}

 

  • First, be careful when using float negative zero.  The TI compiler doesn't claim to support it, and I know of a few places where it would get converted to positive zero, particularly if you use the constant zero (-0.0).

    Second, I'm not very familiar with IQmath, but I don't think there is a way to represent negative zero as there is in floating-point.  IEEE floating-point is a sign-magnitude representation, but I believe IQmath is two's complement.

  • Archaeologist said:

    I know of a few places where it would get converted to positive zero, particularly if you use the constant zero (-0.0).

    Yes in release build, the above snippet doesn't reproduce the problem because the compiler replaces -0 with +0.

    Archaeologist said:

    The TI compiler doesn't claim to support it

    As it happens, I am not explicitly trying to use negative zero.  I don't really want it, it is just happens to be a result during some of the math I am doing.  In these cases the compiler is not replacing -0 with +0.  The particular application I came across this was working with the slope of a line, as defined by the "rise" and the "run".  A perpendicular line has a slope that is the inverse reciprocal.  So when I am inversing one of the components, which might happen to be zero, it becomes a TI float of -0.  To be honest, this seems correct.  I think it is how the IQmath library interprets the bits of the float is where the problem is.  Which is probably related to your second comment:

    Archaeologist said:

    Second, I'm not very familiar with IQmath, but I don't think there is a way to represent negative zero as there is in floating-point.  IEEE floating-point is a sign-magnitude representation, but I believe IQmath is two's complement.

    It seems like the TI IQmath functions that take floats as inputs should be able to handle the range of possible float values on that platform (which appears to include -0, even if TI compiler doesn't officially support it).  Preferably, if it wasn't a big performance hit, the library would just handle -0 like it was 0.  If that's not possible, maybe an assert to help warn the programmer of invalid input into the library function.  And a mention in the documentation would be nice.  Alas, as it seems the IQmath library isn't being actively supported right now.

    For the time being, in the particular spot I have mentioned above (working with slope), I have put an explicit check in to force +0 instead of -0.  I can do this here because it won't effect performance much.  However I worry about other areas where an inadvertant -0 might come up.  As TI makes the source available for IQmath, I might consider putting in a check myself into the inline version of _FtoIQN.  However I am not confident that my mechanism will be the most efficient way to do this.

    Thanks for your feedback.

    I am still open to ideas if anyone else has them.

  • 1970135 said:

    It seems like the TI IQmath functions that take floats as inputs should be able to handle the range of possible float values on that platform (which appears to include -0, even if TI compiler doesn't officially support it).

    I agree with that.  Although the compiler doesn't officially support negative zero, the IEEE format does.

    Unfortunately, I don't know who to report this issue to.