We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for
Did you mean:
Explorer
5,122 Views
Registered: ‎07-06-2016

float operation gives 0

Hi,

I'm trying to do a simple division between two integers and I'm having a zero as a result instead a float (Iuf and Ivf variables):

```void VTransform(short Iu, short Iv, short *Ialpha, short *Ibeta)
{

int iuOverRoot3, ivOverRoot3, tempIBeta;
float Iuf,Ivf;
short Iunormalized,Ivnormalized;

Iuf=(Iu/4095);
Ivf=(Iv/4095);

*Ialpha =(short) (Iuf * 32768);
*Ibeta=(short) (Ivf * 32768);

}```

I added the library "hls_math.h" hoping that it will solve the problem but I'm having the next error:

"#error C++ is required to include this header file"

Anyone knows why?

Thanks.

1 Solution

Accepted Solutions
Scholar
9,786 Views
Registered: ‎04-26-2015

Re: float operation gives 0

That's 100% correct C behaviour. If you divide an integer by an integer, you get an integer. Integer division rounds towards zero, so if your expected value is less than 1, you'll just get zero.

Try this:

```Iuf=(Iu/4095.0f);
Ivf=(Iv/4095.0f);```

Having one variable as a float will force C to do a floating-point divide.

For the HLS math library you need to be using C++, not C. This should be as simple as renaming all the files from "*.c" to "*.cpp", and changing any instances of "uintX" to "ap_uint<X>".

5 Replies
Scholar
9,787 Views
Registered: ‎04-26-2015

Re: float operation gives 0

That's 100% correct C behaviour. If you divide an integer by an integer, you get an integer. Integer division rounds towards zero, so if your expected value is less than 1, you'll just get zero.

Try this:

```Iuf=(Iu/4095.0f);
Ivf=(Iv/4095.0f);```

Having one variable as a float will force C to do a floating-point divide.

For the HLS math library you need to be using C++, not C. This should be as simple as renaming all the files from "*.c" to "*.cpp", and changing any instances of "uintX" to "ap_uint<X>".

Explorer
5,107 Views
Registered: ‎07-06-2016

Re: float operation gives 0

Many thanks, it worked.

Best regards.

Xilinx Employee
5,092 Views
Registered: ‎08-17-2011

Re: float operation gives 0

```...short Iu, short *Ialpha,
float Iuf,
Iuf=(Iu/4095);
*Ialpha =(short) (Iuf * 32768);```

as @u4223374 rightfully pointed to you the issue and the floating point computation will give you the correct result.

However for this testcase, isn't "*Ialpha=Iu/4095*32768" mostly equivalent to *Ialpha=Iu*8 for most small values and you don't really need to use floating points but just a shift by 3?

if you care about really 8.001953601953602 (which makes a difference for large numbers over 1000) then what about 32766/4096 simplified as 4097/512- once again the usual programming tricks "multiply and shift" is easier than full divide. Moreover, multiply by 4097 is not even a difficult multiplication, that's just shift and add too.

i hope this makes some sense ;-)

- Hervé

SIGNATURE:
* New Dedicated Vivado HLS forums* http://forums.xilinx.com/t5/High-Level-Synthesis-HLS/bd-p/hls

* Give Kudos to a post which you think is helpful and reply oriented.
Scholar
5,033 Views
Registered: ‎04-26-2015

Re: float operation gives 0

Regarding @herver's point:

In certain cases, HLS will even do it automatically:

```#include "ap_int.h"

ap_uint<5> runDivision(ap_uint<8> x) {

ap_uint<5> result = x/5;
return result;
}```

Produced HDL code:

```module runDivision (        ap_start,        ap_done,        ap_idle,        ap_ready,        x_V,        ap_return);parameter    ap_const_lv18_19A = 18'b110011010;parameter    ap_const_lv32_B = 32'b1011;parameter    ap_const_lv32_F = 32'b1111;input   ap_start;output   ap_done;output   ap_idle;output   ap_ready;input  [7:0] x_V;output  [4:0] ap_return;wire   [7:0] mul_fu_30_p0;wire   [17:0] mul_fu_30_p2;wire   [17:0] mul_fu_30_p00;assign ap_done = ap_start;assign ap_idle = 1'b1;assign ap_ready = ap_start;assign ap_return = {{mul_fu_30_p2[ap_const_lv32_F : ap_const_lv32_B]}};assign mul_fu_30_p0 = mul_fu_30_p00;assign mul_fu_30_p00 = x_V;assign mul_fu_30_p2 = (mul_fu_30_p0 * \$signed('h19A));endmodule //runDivision

```

(using a total of zero LUTs, zero FFs, one DSP48).

And, simplified:

```module runDivision (
x,
ap_return
);

input  [7:0] x;
output  [4:0] ap_return;
wire   [17:0] mulOut;
assign mulOut = (x * \$signed('h19A));
assign ap_return = mulOut[15 : 11];

endmodule //runDivision```

Presumably HLS has calculated that this will guarantee correct outputs for every valid input - which is a pretty nifty thing for the software to do all by itself. Some Xilinx engineer must have been pretty pleased with himself/herself after getting that working.

Unfortunately, for a much more basic situation (converting a multiply by 4097 into a shift and add) HLS does not seem to be quite so smart. It'll default to using a DSP slice for any multiplication unless it's multiplying by a constant power of two - even, as I've found, when both inputs are only 2-bit wide. The RESOURCE directive provides a suitable workaround (with core Mul_LUT) and presumably this does actually get optimised as appropriate.

Explorer
5,021 Views
Registered: ‎07-06-2016