Forum Discussion
Multiplication Rounding
Hey guys,
I am multiplying two 32 bit numbers using LPM_MULT. Each number is in Q16.16 fixed point format. The product is a 64 bit Q32.32 number. I then shift the product to the right by 16 bits to get a Q32.16 bit number. Now, I would like to round the number to get a Q16.16 bit number. Large inputs are possible, so the product needs to be rounded. Does anyone know a simple and effective algorithm that could be implemented in Verilog? In my old rounding system I would simply divide by 65536. Since I am using Q16.16 format, I don't think it will work anymore.17 Replies
- Altera_Forum
Honored Contributor
Firstly, the interpretation of a value on 64 bits is only a mental perspective. In the past most fpga engineers used the perspective of integer interpretation. Today and as result of software mindset invasion through their tools we have at times to shift between both concepts(integer or fractional).
if you discard 32 lsbs off 64 bits then in effect you are dividing the whole result by 2^32. Rounding will give nearest value. You don't round in the middle of bits at the imagined fractional point. In short you better think of 64 bits here as integer only(no decimal point). You round the 32 bits and it is the duty of receiving module to interpret the decimal point. if your value is so small (relatively) that it only occupies 32 LSBs then you are going to get either 0 or 1 effect on the 32 MSBs. You then interpret that as 0.0 or 0.1/2^16 in Q16.16 format if next module is going to look at it that way. - Altera_Forum
Honored Contributor
Just some clarification,
Lets say you have Q2.2 notation. You have two numbers: 01.11=1.75 x 10.00=2.00 The product should be 3.50 If I do the binary multiplication in my calculator I get a Q4.4 result: 00111000 Now I perform the rounding by adding P(3) to P(7:4) I get: 0011+0001=0100 If I'm interpreting this correctly, it appears that my 3.5 rounded to a 4. But, there isn't any fractional part of the number. The rounding forced the result to Q4.0. Instead of getting 11.10=3.5, I got 0100=4. Now if I didn't do any rounding at all and just performed a shift to the right to align the decimal point, I would get: 00001110 = 000011.10 = 3.5 Maybe I'm confusing the concept of rounding. I want to get a rounded value, but I still want to have a fractional value. If I perform this rounding without the shift, then the output 0100 will go throughout the rest of the system and get interpreted as 01.00=1, since the decimal point is aligned throughout the rest of the system. - Altera_Forum
Honored Contributor
Regarding shift idea, you don't need to think that way, just discard 32 LSBs. shift is applicable if you keep 64 bits and want to shift divide or shift multiply.
- Altera_Forum
Honored Contributor
Thanks for your help Kaz. Added to your reputation.
- Altera_Forum
Honored Contributor
It is much simpler than your thoughts.
Rounding is done when you divide a value and in your case when you discard 32 bits. (= /2^32). you can either discard directly without any else since your datawidth is 32 bits. or you round up to nearest value. The issues of deimal point is matter of interpretation of value, nothing else. - Altera_Forum
Honored Contributor
Thanks for the reply Kaz. My concern was that the fractional part would cause the product to be huge. For example, if you have 111.010=7.25, it can be interpreted as 111010=58. Performing a rounding on a rather small number like 7.25 with a fraction might be the same as performing the rounding on a large number. Basically, I'm afraid that such a rounding algorithm would cause small numbers to become rounded as large numbers.
Another concern is whether I should even shift at all after multiplication. Anytime you multiply a number you get 2*N decimal places, where N is the number of decimal places in the inputs. Since I only want N precision, I would the product by the right by N bits to discard them. With the method you gave, do I even need to do this at all? Would it be better just to round only? I know this question may seem kind of stupid, but I'm still learing about fixed point for the first time. - Altera_Forum
Honored Contributor
Most basic rounding is:
if your result is 64 bits then add result(31) to result(61 : 32) Alternatively add '1' to result(61:31) then take result(61:32) Thats all.