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.

TMS320F28377D-EP: CLA implementation of floor and ceil functions

Part Number: TMS320F28377D-EP

Please could you suggest the best way how to implement floor and ceil functions in CLA-C ?

Such functions are not part of CLAmath library.

Regards,

Miroslav

  • Hi Miroslav,

    I think the below code snippets should work:

    float32_t floor(float32_t val)
    
    {
    
        volatile uint32_t temp = (uint32_t)val;
    
        if(val < 0.0f)
        {
            temp = temp - 1;
        }
    
        return((float32_t)temp);
    }
    
    float32_t ceil(float32_t val)
    
    {
    
        volatile uint32_t temp = (uint32_t)val;
    
        if(val > 0.0f)
        {
            temp = temp + 1;
        }
    
        return((float32_t)temp);
    }

    Let me know if this works.

    sal

  • Sal,

    thanks for the response, however the provided code does not seem to be a solution which I'm looking for. I was looking rather for something similar as the implementation in the standard math library (e.g. s_floorf.c as part of the C2000 compiler tools). I'm wondering if the implementation from the standard math library could be taken over and compiled for CLA or whether there is some other "trick", e.g. using some CLA-compiler intrinsics as per document spru514p (e.g. float __mfracf32(float src)).

  • Do the functions provided above not work?

    You are free to create your own functions with source code. The compiler does not support math.h functions for the CLA. This is partially the purpose of the CLA math library.

    sal

  • Sal,

    thank you once more for your response, however it is not straightforward to say if the code you provided is working. I'm tending to say it is working for the floating point numbers whose size fits within int32 type. Because of the float to int32 cast I'm almost sure the proposed implementation can't deal with the floating point numbers which are too large to fit within int32 representation.

    I was really looking for the code which can deal with whole range of IEEE Single precision numbers. I can find such code in the s_floorf.c file which is distributed with the C2000 compiler, however I'm not sure if the logic inside is applicable to CLA and I don't have the time to understand IEEE single precision implementation to the level where I can implement round and ceil functions on my own.

    If you can provide whatever help with this, it would be greatly appreciated.

    Regards,

    Miroslav 

  • Hi,

    You are correct that it will not account for floats which are beyond the value range of int32_t. So, this would have to me accounted for.

    I don't have any reason at this point to suspect the source code would not work for CLA.

    Can you post it here, so we can discuss if you have any more concerns with it?

    sal

  • Hi,

    Using compiler intrinsic __mfracf32()

    float cla_ceil(float x)
    {
    	// get fractional part
    	float frac = __mfracf32(x);
    	
    	x -= frac; // get integer part
    	if(frac > 0.0) // for positive x and non zero fraction do +1
    		x += 1.0;
    	return x;
    }
    
    float cla_floor(float x)
    {
        // get fractional part
        float frac = __mfracf32(x);
    
        x -= frac; // get integer part
        if(frac < 0.0) // for negative x and <0 fraction do -1
            x -= 1.0;
        return x;
    }
    

    Edward

  • Hi Edward,

    I believe your ceil function is correct. The floor should be the below since I do not believe frac will every be less than 0.0. frac will never be negative.

    float cla_floor(float x)
    {
        // get fractional part
        float frac = __mfracf32(x);
        x -= frac; // get integer part
     
        return x;
    }
    So, I believe your original floor function would work, but the if condition would never be true. So, you can simplify it to above.
    sal
  • Hi,

    I verified that frac works as expected and returns either 0 or follows the sign of x. Negative frac is normal for negative x, always less than or equals 0. Without "if" you get the same result as converting to integer then back to float. ceil() and floor() have different purpose.

     

    Regards,

    Edward

  • Hi Edward,

    Thanks for the clarification. 

    In that case, I believe your original implementation will work.

    I have filed this away (ceil and floor) for potential CLA math library enhancements.

    Thank you,

    sal

  • Hi Sal and EK,

    thank you both for your support.

    I have finally chosen to use the implementation from s_floorf.c and s_ceilf.c from the C2000 compiler version 18.12.1.

    Did some very brief testing on CLA and it seems to be working.

    Anyway if the floor and ceil functions would be released in future as part of the CLAMath library, that would be great.

  • Very last point to ask...just for curiosity.

    In the code e.g. for floor function, there are some non-clear comparisons:  if(huge+x>(float)0.0) and some notes about raising inexact flag. Could you explain little bit? Thanks a lot.

    /*
     * Copyright (c) 2015-2015 Texas Instruments Incorporated
     *
     * s_floorf.c -- float version of s_floor.c.
     * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
     */

    /*
     * ====================================================
     * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
     *
     * Developed at SunPro, a Sun Microsystems, Inc. business.
     * Permission to use, copy, modify, and distribute this
     * software is freely granted, provided that this notice
     * is preserved.
     * ====================================================
     */

    /*
     * floorf(x)
     * Return x rounded toward -inf to integral value
     * Method:
     * Bit twiddling.
     * Exception:
     * Inexact flag raised if x not equal to floorf(x).
     */

    #include <float.h>
    #include <stdint.h>
    #include "math.h"
    #include "math_private.h"

    _DATA_ACCESS static const float huge = 1.0e30;

    float
    floorf(float x)
    {
     int32_t i0,j0;
     uint32_t i;
     GET_FLOAT_WORD(i0,x);
     j0 = ((i0>>23)&0xff)-0x7f;
     if(j0<23) {
         if(j0<0) {  /* raise inexact if x != 0 */
      if(huge+x>(float)0.0) {/* return 0*sign(x) if |x|<1 */
          if(i0>=0) {i0=0;}
          else if((i0&0x7fffffff)!=0)
       { i0=0xbf800000;}
      }
         } else {
      i = (0x007fffff)>>j0;
      if((i0&i)==0) return x; /* x is integral */
      if(huge+x>(float)0.0) { /* raise inexact flag */
          if(i0<0) i0 += (0x00800000)>>j0;
          i0 &= (~i);
      }
         }
     } else {
         if(j0==0x80) return x+x; /* inf or NaN */
         else return x;  /* x is integral */
     }
     SET_FLOAT_WORD(x,i0);
     return x;
    }

    #if DBL_MANT_DIG == FLT_MANT_DIG
    double floor(double x) __attribute__((__alias__("floorf")));
    #endif

    #if LDBL_MANT_DIG == FLT_MANT_DIG
    long double floorl(long double x) __attribute__((__alias__("floorf")));
    #endif

  • Hi

    s_floorf implementation will be much slower than using compiler intrinsic for fractional part, which is just a single CLA instruction. BTW functions I suggested don't get fooled with infinities or any big numbers. ceil(+-inf) returns +-inf.

    s_floorf.c seems being taken from Newlib, which according to Wikipedia "is a conglomeration of several library parts, all under free software licenses that make them easily usable on embedded products."

    huge in s_floorf.c seems being very big number but not infinity. I wonder why 1E30 and not FLT_MAX from float.h, perhaps it was just a less digits to type than real FLT_MAX or from the times when FLT_MAX was not yet known or was different on different float machines?

    Inexact is when result doesn't equal to what is expected in real math. For example float 16777216.0 + 1.0 = 16777216.0, which is inexact. Add 2.0 instead of 1.0 and you'll get exact result. Adding huge to any not so big as huge number most likely will trigger inexact, though it won't for example if x == -huge.

    I very doubt floor and ceil should produce any exceptions, except of when argument is Inf or NaN. floor(Inf) could perhaps trigger inexact because infinity is inexact. I don't follow the logics of s_floorf, if(j0<0) case is for negative float exponent. Result should be either +0 or -1 (0xBF800000). Why there's a test for huge+x > 0.0? Inexact certainly will trigger because x is quite small and huge is large. But floor/ceil result is certainly exact, no bits can be lost calculating floor/ceil result!

    Edward

  • Edward,

    thank you for analysis of the code. I also don't follow some pieces of logic around huge.

    Anyway, I think I have enough information to decide what to use. Both approaches (using either intrinsics or library functions) seems to be valid and this e2e thread describes both of them quite comprehensively.

    Thanks and regards,

    Miroslav