Search code examples
floating-pointverilogsystem-verilog

Stray decimal values in real numbers


I have a real number delay which I would like to convert to the first multiple of 10. For example, if delay = 0.0024, I want the output to be 240.

In the following code snippet, delay = 1.52e-6. After while loop execution, I was expecting delay to be 1520. However, I'm seeing that delay = 1.52e17 after while loop. I checked the waveform, and it looks like the value of delay was 1.5200000000000001e-6 to begin with. Why is it so? Am I doing something wrong?

Here is the code:

  real delay = 1.52e-6;

  function real mod (real a, real b);
      mod = a - b*$floor(a/b);
  endfunction

  initial begin
      while (mod(delay, 10) != 0) delay = delay*10;
  end

Solution

  • In the following code snippet, delay = 1.52e-6

    Note quite.

    Floating point types are commonly encoded using binary64 or the like. This 64-bit encoding can encode about 264 different values exactly. 1.52e-6 is not one of them as it is not a Dyadic rational (some integer times a power of 2). Instead code starts working with a nearby value of 1.5200000000000000582720720634921640623815619619563e-06 or 0x198059AC99A685 * 2-72.

    Further complications occurs because many of the delay = delay*10 incur a rounding error.

    Amend goal or use a different approach.

    "convert to the first multiple of 10" sounds like a secondary goal. What is the higher level goal?

    Note: All finite floating point values are exact. It is how we operate on them that often leading to a result that differs from the exact math result we learned in school.