kivantium活動日記

プログラムを使っていろいろやります

浮動小数点数の乗算

この記事はkivantium Advent Calendarの13日目です。

昨日浮動小数点数のフォーマットについて説明しました。
今日は浮動小数点数の乗算をやります。

仕組み

浮動小数点数仮数と指数で表されるので

  • 指数の和を取る
  • 仮数の積を取る
  • 仮数を丸めてフォーマットを整える

をやれば計算できることになります。

入力を正規化数のみの計算に絞って、最近接丸めを採用したコードは以下のようになります。

module testbench;
  logic clk, start;
  logic [31:0] a, b, c;
  int i;
  fmul fm(.a(a), .b(b), .c(c));

  initial begin
    a = 32'b01000000010010001111010111000011; // 3.14
    b = 32'b00111101110011001100110011001101; // 0.1
    start = 1'b1;
    clk = 1'b0;
    for(i=0; i<5; i=i+1) begin
      clk = 1'b1; #10; clk=1'b0; #10;
    end
    $display("%b %b %b", c[31], c[30:23], c[22:0]);
    $finish;
  end
endmodule

module fmul(
  input [31:0] a, b,
  output logic [31:0] c
);
  logic c_sign;
  logic [7:0] c_exp;
  logic [23:0] c_frac;
  assign c = {c_sign, c_exp, c_frac[22:0]};

  logic [8:0] c_exp_0, c_exp_1;
  logic [47:0] c_frac_0; // 48bit = 2 * 24bit
  logic [23:0] c_frac_1; // 24bit

  logic guard_bit, round_bit, sticky_bit;
  logic guard_bit1, round_bit1, sticky_bit1;


  always @* begin
    c_sign = a[31] ^ b[31];
    c_exp_0 = a[30:23] + b[30:23];
    c_frac_0 = {1'b1, a[22:0]} * {1'b1, b[22:0]};
    guard_bit = c_frac_0[23];
    round_bit = c_frac_0[22];
    sticky_bit = |c_frac_0[21:0];

    if(c_frac_0[47] == 1'b1 || &c_frac[46:24] == 1'b1) begin
      c_frac_1 = c_frac_0[46:23];
      c_exp_1 = c_exp_0 + 1;
      sticky_bit1 = sticky_bit;
      round_bit1 = round_bit;
    end else begin
      c_frac_1 = c_frac_0[47:24];
      c_exp_1 = c_exp_0 + 1;
      sticky_bit1 = sticky_bit | round_bit;
      round_bit1 = guard_bit;
    end

    if(c_exp_1 < 127) begin
      c_exp = {9{1'b0}};
    end else begin
      c_exp = c_exp_0 - 127;
    end

    if(round_bit1 == 1'b1 && (sticky_bit1 == 1'b1 || c_frac_1[0] == 1'b1)) begin
      c_frac = c_frac_1 + 1;
    end else begin
      c_frac = c_frac_1;
    end
  end
endmodule

出力は

0 01111101 01000001100010010011100

となって昨日のプログラムで求めた3.14*0.1の答えと一致しました。

丸めを適当にやっていて、Inf, NaNにも対応していないひどいコードなので後日ちゃんとしたものを書きます。