将整数除以3的简便方法

时间:2015-10-08 04:46:44

标签: vhdl boolean-logic circuit

我正在开发一个在FPGA上制作简单音乐播放器的项目。它从PC获取指定格式的音乐文件,并在循环中大声播放。

我们需要实现标准音符长度,即半个节拍的Quaver,2个节拍的Minim等。目前我们在不同的BPM值下有一个节拍长度表的时钟周期数。我们需要将它们乘以这些音符长度以产生正确的时钟周期。唯一的问题是 Tuplet ,这是一个完整节拍的三分之一。

如果没有实现完整的分频器电路,是否有任何数学技巧可以将大约3的整数除以?

3 个答案:

答案 0 :(得分:1)

以下是来自Hank Warren的Hacker's Delight的一些代码的VHDL翻译。它将无符号整数除以常数值3,仅使用常数值3和5的移位,加法和乘法(也可以减少为移位和加法)。

-- q is quotient, d is dividend
q := (d srl 2) + (d srl 4); -- q = d*0.0101 (approx)
q := q + (q srl 4); -- q = d*0.01010101
q := q + (q srl 8);
q := q + (q srl 16);
r := resize(d - q * 3, 32); -- 0 <= r <= 15.
q := resize(q + (5 * (r + 1) srl 4), 32);

答案 1 :(得分:0)

如果长度为x / 3的无符号值需要整数除以3(LEN)的确切结果,则可以使用截断整数运算。 1/3的常量应为LEN + 1长度,并且应添加1。然后可以使用截断。伪代码为:

C = 2 ** (LEN + 1) / 3 + 1
y = (x * C) / 2 ** (LEN + 1)

显示和测试所有值的算法的Python函数是:

def div_by_3_test(LEN):
    DIVISOR = 3
    C = 2 ** (LEN + 1) // DIVISOR + 1
    for x in range(2 ** LEN):
        if (x * C) // 2 ** (LEN + 1) != x // DIVISOR: exit('Failed') 

实现此目的的VHDL模块:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity div_by_3 is
  generic(
    LEN : natural := 12);
  port(
    x_i   : in  std_logic_vector(LEN - 1 downto 0);
    y_o   : out std_logic_vector(LEN - 1 downto 0));
end entity;

architecture syn of div_by_3 is
  -- Constant to multiply, basically 1/3, but adding 1 to avoid error
  constant C : std_logic_vector(LEN - 1 + 1 downto 0) :=
    std_logic_vector(to_unsigned(2 ** (LEN + 1) / 3 + 1, LEN + 1));
  -- Intermediate, with length as 2 * LEN + 1
  signal t : std_logic_vector(2 * LEN + 1 - 1 downto 0);
begin
  -- Intermediate with full length result
  t <= std_logic_vector(unsigned(C) * unsigned(x_i));
  -- Result after truncation for division by LEN + 1
  y_o <= t(2 * LEN + 1 - 1 downto LEN + 1);
end architecture;

优点是只使用一个LEN位乘法就可以在一个周期内除以3 2 * LEN + 1位数。

可以添加寄存器以允许管道进行高速设计。

请注意,任何除数都可以采用类似的方案,但C的长度必须为LEN + ceil(log2(DIVISOR))C相应缩放。有关数学基础,请参阅https://math.stackexchange.com/q/2444306/275980

答案 2 :(得分:0)

正如dieli所说,乘以0.333333。

但是,不是使用2的几个负幂(即a,b,c,..),而是将1/3乘以2的某个大幂,例如: 2 ^ 24 *(1/3)=5592405。将时钟周期乘以5592405之后,只需除以2 ^ 24。

B =(时钟周期)* 5592405

结果= B / 2 ^ 24

B的大小取决于时钟周期的最大大小,并且可以通过以下方式计算

B的最大寄存器大小=((log10((时钟周期的最大大小)* 5592405)/ log10(2))+ 0.5)的整数