比较VHDL中的实数

时间:2015-01-08 09:43:22

标签: vhdl

我当前比较两个实数(计算后)的方法是取差值并转换为整数并比较为0,例如(只是为了突出显示问题,示例可能在模拟器中有效)

variable a : real := 0.1;
constant epsilon : real := 1.0E-5; -- Whatever accuracy needed, not too low though
a := a + 5.3;

assert a = 5.4;                -- Yields intermitent errors
assert integer(a - 5.4) = '0'; -- Erroneous if 4.8 < a < 5.9 due to cast rounding
assert abs(a - 5.4) < epsilon;    -- Will work everytime, but seems a bit forced

这种方式的原因是我在我编写的测试平台中得到了很多断言错误(比示例代码更多的补充文本)。我将这些错误视为GHDL模拟器中的浮点错误。有没有更好的方法来比较两个实物,比如使用机器epsilon或任何方法构建?

2 个答案:

答案 0 :(得分:3)

如@Philippe所示,实数的比较需要一些余量来解释有限精度和最低有效位中的累积误差。使用简单的epsilon值是一种常见的方法,但它有一个限制,即它的值与被比较的数字相关是绝对的。您需要事先知道您要比较的预期值以选择合适的epsilon。

如果您需要比较的数字集涵盖了各种各样的幅度,您最终会得到一个太大而无法正确比较小值的ε。在这种情况下,你需要一个小的epsilon来比较小的实数和一个更大的epsilon更大的数字。这是通过使用考虑相对误差的比较来实现的。

This page给出了一个方法的概述,该方法允许使用相对误差而不是绝对误差来比较实数。以下函数是VHDL中相对比较的实现:

-- Adapted from: http://floating-point-gui.de/errors/comparison/
function relatively_equal(a, b, epsilon : real) return boolean is
begin
  if a = b then -- Take care of infinities
    return true;
  elsif a * b = 0.0 then -- Either a or b is zero
    return abs(a - b) < epsilon ** 2;
  else -- Relative error
    return abs(a - b) / (abs(a) + abs(b)) < epsilon;
  end if;
end function;

这里的epsilon参数是一个分数,它指定要比较相对相等的有效位数。

-- Compare for relative equality to three significant digits
-- These are all considered equal while using the same epsilon parameter
assert relatively_equal(1.001, 1.002, 1.0E-3) report "1.001 != 1.002";
assert relatively_equal(100.1, 100.2, 1.0E-3) report "100.1 != 100.2";
assert relatively_equal(1001.0, 1002.0, 1.0E-3) report "1001 != 1002";

-- Compare for relative equality to four significant digits
-- This will raise the assertion
assert relatively_equal(1.001, 1.002, 1.0E-4) report "1.001 != 1.002";

答案 1 :(得分:1)

这个问题对任何使用&#34; real&#34;的编程语言都是通用的。值(a.k.a.浮点数)。

在自动测试中比较实数的标准方法是定义一个小值epsilon。然后检查两个实数之间的绝对差值是否小于epsilon。如果要编写简洁的测试平台,可以定义自己的过程assertEqual(x,y, epsilon)

procedure assertEquals(
    x, y    : real; epsilon : real := 1.0E-5;
    message : string               := "";
    level   : severity_level       := error) is
begin
    assert (abs (x - y) < epsilon) report message severity level;
end procedure assertEquals;