cancel
Showing results for
Show  only  | Search instead for
Did you mean:
Highlighted
Voyager
5,335 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
Highlighted
9,999 Views
Registered: ‎04-26-2015

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
Highlighted
10,000 Views
Registered: ‎04-26-2015

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>".

Highlighted
Voyager
5,320 Views
Registered: ‎07-06-2016

Many thanks, it worked.

Best regards.

Highlighted
Xilinx Employee
5,305 Views
Registered: ‎08-17-2011
```...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.
Highlighted
5,246 Views
Registered: ‎04-26-2015

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.

Highlighted
Voyager
5,234 Views
Registered: ‎07-06-2016

Thanks and herver, yes it really makes sense, you are right about the conversion, but in this case being Iu an ADC input, I did this conversion just to check the right voltage values given by the external hardware, as a debug purposes.

Indeed on the final code that will be optimized.

Thanks again for the help.

Best regards.