Algorithm 将整数除以固定常数的最快方法是什么?
我有一个16位的数字,我想除以100。假设是50000美元。目标是获得500英镑。然而,我试图避免在我的FPGA上使用推断除法器,因为它们会破坏时序要求。结果不一定要准确;近似值就可以了Algorithm 将整数除以固定常数的最快方法是什么?,algorithm,division,system-verilog,Algorithm,Division,System Verilog,我有一个16位的数字,我想除以100。假设是50000美元。目标是获得500英镑。然而,我试图避免在我的FPGA上使用推断除法器,因为它们会破坏时序要求。结果不一定要准确;近似值就可以了 我尝试过硬件乘法0.01,但不支持实数。我现在正在研究流水线除法器,但我希望不会出现这种情况。概念上:乘以655(=65536/100),然后右移16位。当然,在硬件中,右移是免费的 如果需要更快,可以将除法硬连接为除法之和乘以二的幂(移位)。例如: 在C代码中,上面的最后一个示例是: uint16_t div
我尝试过硬件乘法0.01,但不支持实数。我现在正在研究流水线除法器,但我希望不会出现这种情况。概念上:乘以655(=65536/100),然后右移16位。当然,在硬件中,右移是免费的 如果需要更快,可以将除法硬连接为除法之和乘以二的幂(移位)。例如: 在C代码中,上面的最后一个示例是:
uint16_t divideBy100 (uint16_t input)
{
return (input >> 7) + (input >> 9) + (input >> 12);
}
假设
- 整数除法用于截断,而不是四舍五入(例如599/ 100=5)
- FPGA中有一个16x16的乘法器是可以的(上有一个固定值) 一个输入)
uint16_t divideBy100( uint16_t input )
{
uint32_t temp;
temp = input;
temp *= 0xA3D7; // compute the 32-bit product of two 16-bit unsigned numbers
temp += 0x8000; // adjust the 32-bit product since 0xA3D7 is actually a little low
temp >>= 22; // the upper 10-bits are the answer
return( (uint16_t)temp );
}
一般情况下,您可以乘以逆和移位。编译器一直都在这样做,即使对于软件也是如此。
这里有一个页面可以帮你做到这一点:
在您的例子中,这似乎是乘以0x431BDE83,然后右移17
这里有一个解释:乘以倒数通常是一个很好的方法,正如您所指出的,尽管不支持实数。您需要使用定点实数而不是浮点实数 Verilog没有固定点的定义,但它只使用一个字长,您可以决定有多少位是整数,有多少位是小数 二进制的0.01(0.0098876953125)将是
0\u000000 1010001
。单词长度越大,精度越高
// 1Int, 13Frac
wire ONE_HUNDREDTH = 14'b0_0000001010001 ;
input a [15:0]; //Integer (no fractional bits)
output result [15+14:0]; //13 fractional bits inherited form ONE_HUNDREDTH
output result_int [15:0]; //Integer result
always @* begin
result = ONE_HUNDREDTH * a;
result_int = result >>> 13;
end
使用ruby gem定点完成实数到二进制的转换
ruby irb会话(通过gem安装固定点安装):
由于65536/100不是一个精确的值,您需要进行一些分析,以确保结果在您的误差范围内。更多的位可能会有所帮助,或者你可以用更少的位来解决问题。你是在暗示实现一个移位-加法体系结构,用“除以二的幂作为除法的和”吗?在多个时钟周期内实现这一点是很常见的。@Morgan,你当然可以使用流水线技术,每个周期进行一次加法,或者你可以使用一些不动产来制作一个3输入加法器,然后在一个周期内进行加法。@Morgan实际上先除后加是非常不准确的-对于0-65535的输入范围,36016被1(两个方向)关闭和5580的差距是2!如果将表达式更改为((n@Mark,是的,尽管有C代码,但在我的脑海中,我想象的是一个加法器,在“小数点”的右边扩展到12位,即a(16-7+12=)21位加法器。您的表达式是一个很好的表达方式,因为它清楚地表明,我们需要至少16+5位才能达到完全的精度。感谢您的分析。请注意,原始问题包括“结果不必精确,近似即可。”这可能适用于装配级优化,但OPs“计时”指的是通过逻辑的传播延迟。与此处表示的数字相乘将导致需要一个大的乘法器,32x32,这可能不可用。@Morgan:我理解,但我打算为实现该目标简化一个级别.乘法逻辑比除法逻辑更容易进行近似和优化,因此,如果OP想要在速度和精度之间进行权衡,则需要操纵常数和右移以满足该要求。
// 1Int, 13Frac
wire ONE_HUNDREDTH = 14'b0_0000001010001 ;
input a [15:0]; //Integer (no fractional bits)
output result [15+14:0]; //13 fractional bits inherited form ONE_HUNDREDTH
output result_int [15:0]; //Integer result
always @* begin
result = ONE_HUNDREDTH * a;
result_int = result >>> 13;
end
require 'fixed_point'
#Unsigned, 1 Integer bit, 13 fractional bits
format = FixedPoint::Format.new(0, 1, 13)
fix_num = FixedPoint::Number.new(0.01, format )
=> 0.0098876953125
fix_num.to_b
=> "0.0000001010001"