Bas Arts Posted August 27, 2014 Report Share Posted August 27, 2014 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 Quote Link to comment Share on other sites More sharing options...
karthickg Posted August 27, 2014 Report Share Posted August 27, 2014 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? Quote Link to comment Share on other sites More sharing options...
Bas Arts Posted August 27, 2014 Author Report Share Posted August 27, 2014 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 Quote Link to comment Share on other sites More sharing options...
karthickg Posted August 27, 2014 Report Share Posted August 27, 2014 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. Quote Link to comment Share on other sites More sharing options...
ralph.goergen Posted August 27, 2014 Report Share Posted August 27, 2014 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 Quote Link to comment Share on other sites More sharing options...
dakupoto Posted August 28, 2014 Report Share Posted August 28, 2014 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. David Black 1 Quote Link to comment Share on other sites More sharing options...
David Black Posted September 14, 2014 Report Share Posted September 14, 2014 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; } Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.