Jump to content

Writing / reading unsigned long long using double channel


Bas Arts

Recommended Posts

I tried to write and read an unsigned long long value over a double channel, using a double value as starting point.

Code snippet:

 

    double d = 3.1415926535897931;

    unsigned long long * ullp = (unsigned long long *) &d;

    out_port.write(*ullp); // sc_out<double> out_port; connected via sc_signal<double> to in_port

    unsigned long long ull = in_port.read(); // sc_in<double> in_port; connected via sc_signal<double> to out_port

    double * dp = (double *) &ull;

 

When I print the values of d, *ullp, ull and *dp, I notice the following:

 

    d:     3.1415926535897931;

    *ullp: 4614256656552045848;

    ull:   4614256656552045568;

    *dp:   3.1415926535896688;

 

However, plain casting without SystemC (double d -> ull* ullp = (ull*) &d -> ull u = *ullp -> double* dp = (double*) &u -> double d2 = *dp) returns d2 with exactly the same value as d.

 

Any idea what is happening and why the channel of type double seems to loose a bit of its precision when using it in this way?

 

-- 

greetz,

Bas

Link to comment
Share on other sites

Hi Bas,

 

Did you mean to say:

 

    double d = 3.1415926535897931;

    unsigned long long * ullp = (unsigned long long *) &d;

    out_port.write(*ullp); // sc_out<doubleunsigned long long> out_port; connected via sc_signal<doubleunsigned long long> to in_port

    unsigned long long ull = in_port.read(); // sc_in<doubleunsigned long long> in_port; connected via sc_signal<doubleunsigned long long> to out_port

    double * dp = (double *) &ull;

 

Also, what is the output of sizeof(double) and sizeof(unsigned long long) in your case?

Link to comment
Share on other sites

Hi Karthick,

 

Thanks for your reply. I did mean sc_out<double> out_port and sc_in<double> in_port, because I was deliberately using a double channel.

 

The sizeof() operator returns 8 both for double and unsigned long long on my system.

 

In the meantime, I found that it is not related to SystemC anyway:

 

    double d = 3.1415926535897931;

    unsigned long long *ullp = (unsigned long long *) &d;

    unsigned long long ull = *ullp; // ull = 4614256656552045848

    double d2 = (double) ull; // d2 = 4614256656552045568.0000000000000000 !!

    unsigned long long ull2 = (unsigned long long) d2; // ull2 = 4614256656552045568

    double * dp = (double *) &ull2; // *dp = 3.1415926535896688

 

Hence, the casting of an unsigned long long to a double seems to cause the problem.

 

--

greetz,

Bas

Link to comment
Share on other sites

Hi Bas,

 

In trying to explain this a bit more, I looked up the double format. As per http://en.wikipedia.org/wiki/Double-precision_floating-point_format, the 8-byte double format can handle 15-17 significant decimal digits without loss of precision.

 

When assigning,

   double d2 = (double) ull;

the width of ull (4614 2566 5655 2045 848) is 19 significant decimal digits, which causes loss in precision.

Link to comment
Share on other sites

Hi, 

 

as you mentioned before, casting values is the problem here. If you want to keep the bit representation independent from the data types, you have to rely on casting pointers. 

unsigned long long ull = in_port.read();

This line converts the value and changes the bit representation. 

double d = in_port.read();
unsigned long long * ullp = (unsigned long long *)&d;
unsigned long long ull = *ullp;

Should work in the same way as before when you did write to the out port.

 

Greetings

Ralph

Link to comment
Share on other sites

I tried to write and read an unsigned long long value over a double channel, using a double value as starting point.

Code snippet:

 

    double d = 3.1415926535897931;

    unsigned long long * ullp = (unsigned long long *) &d;

    out_port.write(*ullp); // sc_out<double> out_port; connected via sc_signal<double> to in_port

    unsigned long long ull = in_port.read(); // sc_in<double> in_port; connected via sc_signal<double> to out_port

    double * dp = (double *) &ull;

 

When I print the values of d, *ullp, ull and *dp, I notice the following:

 

    d:     3.1415926535897931;

    *ullp: 4614256656552045848;

    ull:   4614256656552045568;

    *dp:   3.1415926535896688;

 

However, plain casting without SystemC (double d -> ull* ullp = (ull*) &d -> ull u = *ullp -> double* dp = (double*) &u -> double d2 = *dp) returns d2 with exactly the same value as d.

 

Any idea what is happening and why the channel of type double seems to loose a bit of its precision when using it in this way?

 

-- 

greetz,

Bas

Hello Sir,

Have you considered the possibility of using bit vectors of sizes specified by

you, instead of using 'long long' etc., After all, in a real world hardware, all

numbers are stored as bit vectors, so although it might appear somewhat

of a low-level approach, it would be far more intuitive, and there would not

be any of the casting issues that you face. Hope that helps.

Link to comment
Share on other sites

  • 3 weeks later...

Basic question: Why are you not just using a port that carries doubles? When modeling, you can assign timing independent of what the data format is. I make the presumption that you are doing high-level modeling rather than RTL.

 

If your answer is to store it in a memory model that uses unsigned long long int or as its base type, then you should consider:

// C++ program to test using unsigned long long int to carry data across a connection
#include <iostream>
#include <cassert>
using namespace std;
int main() {

  bool success = true; // innocent until proven otherwise

  typedef unsigned long long int  data_t; //< generic definition of the data passed over port
  assert(sizeof(double)<=sizeof(data_t)); //< ensure it is big enough

  for (size_t i=0; i!=1000; ++i) {
    // Create a random number
    double xmit_double = double(random())/double(1<<(random()%32));

    data_t& xmit_data = reinterpret_cast<data_t&>(xmit_double);

    // Send the data to the "other" end
    data_t  recv_data = xmit_data;

    double& recv_double = reinterpret_cast<double&>(recv_data);

    success &= (recv_double == xmit_double);
  }
  cout << (success?"PASSED":"FAILED") << endl;
  return success?0:1;
}
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...