This post will help you to understand the difference between

**real, realtime and shortreal**data types of SystemVerilog and its usage.
We faced some issue with real and realtime variable while writing a timing check.

Below is a simplified example of that check.

`timescale 1ns/1fs;

module test;

real a,b;

realtime t1, t2;

initial

begin

#1ns;

t1 = $realtime;

#1.8ns;

t2 = $realtime;

b = 1.8;

a = t2 - t1;

if(a == b)

$display("PASS a = %f b = %f", a,b);

else

$display("FAIL a = %f b = %f", a,b);

end

endmodule

and here is what we got the display

FAIL a = 1.800000 b = 1.800000

How that happened !!! is really

*1.800000 != 1.800000 !!!!*

Now let's try something else, instead of using

**real**we use

**shortreal**

`timescale 1ns/1fs;

module test;

shortreal a,b;

realtime t1, t2;

initial

begin

#1ns;

t1 = $realtime;

#1.8ns;

t2 = $realtime;

b = 1.8;

a = t2 - t1;

if(a == b)

$display("PASS a = %f b = %f", a,b);

else

$display("FAIL a = %f b = %f", a,b);

end

endmodule

Now the result was as expected !!

PASS a = 1.800000 b = 1.800000

To understand this lets go to SystemVerilog LRM. As per LRM

The real data type is from Verilog-2001, and is the same as a

**C double**.
The shortreal data type is a SystemVerilog data type, and is the same as a

**C float**.
So float is 32 bit data type and double is 64 bit data type. This sounds cool but still how 1.800000 != 1.800000

No ! it's not only about being 32 or 64 bit data type its more about precision.

*"**.***Precision**is the main difference where**float**is a single precision (**32 bit**) floating point data type,**double**is a double precision (**64 bit**) floating point data type "
To understand this difference let's go beyond and print the values with more number of digits after decimal point.

In below example we have used both real and shortreal to see the difference.

`timescale 1ns/1fs;

module test;

real a,b;

shortreal c,d;

realtime t1, t2, t3, t4;

initial

begin

#1ns;

t1 = $realtime;

#1.8ns;

t2 = $realtime;

b = 1.8;

a = t2-t1;

if(a == b)

$display("Case1: PASS \na = %1.100f \nb = %1.100f", a,b);

else

$display("Case1: FAIL \na = %1.100f \nb = %1.100f", a,b);

end

initial

begin

#1ns;

t3 = $realtime;

#1.8ns;

t4 = $realtime;

d = 1.8;

c = t2-t1;

if(c == d)

$display("Case2: PASS \nc = %1.100f \nd = %1.100f", c,d);

else

$display("Case2: FAIL \nc = %1.100f \nd = %1.100f", c,d);

end

endmodule

Here is what the display is

Case1: FAIL

a = 1.7999999999999998223643160599749535322189331054687500000000000000000000000000000000000000000000000000

b = 1.8000000000000000444089209850062616169452667236328125000000000000000000000000000000000000000000000000

Case2: PASS

c = 1.7999999523162841796875000000000000000000000000000000000000000000000000000000000000000000000000000000

d = 1.7999999523162841796875000000000000000000000000000000000000000000000000000000000000000000000000000000

It's clearly seen that the

**64 bit real variable has more precision that that or 32 bit shortreal variable**.
Here one more thing to consider is that we are taking difference of time.

**Simple values like 0.1 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations or the precision of intermediates can change the result. That means that comparing two floats to see if they are equal is usually not what you want.***Floating point math is not exact*.
The things will not matter much if you are doing calculations in

**nanoseconds**so we suggest to use**shortreal**instead of**real**.
Thank you for this great example. Im new to systemverilog and was looking for such a concrete explanation. Normally when you need to compare to floating point numbers, you should consider comparing if their difference is greater/less than a certain machine/standard specific epsilon value (eps).

ReplyDeleteChristian