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 */
}