Jamming a very large long into a double

 

ChartID() returns a long.

In general, it seems to be a rather large number.

When I put it into a double, e.g. into a Global Variable of the Client Terminal, it gets changed due to loss of precision.

So . . . I was thinking . . . I don't really need to know the exact ChartID() number. I just want to compare it against the current ChartID() number. Each ChartID() is unique.

This is what I have come up with:

// Transposes a chartID to something storable with full precision in a double.
// This way I can store in the Global Terminal Variables.
double StorableChartID(const long cid)
{
    const long transposedChartID = cid % 9007199254740991;        // should fit in double w/o loss of precision
    const double storedChartID = (double) transposedChartID;

    if ( debug ) PrintFormat(   "cid [%I64d] transposedChartID [%I64d] storedChartID [%.0f]",
                                cid,
                                transposedChartID,
                                storedChartID );
    return storedChartID;
}

This seems to work so far.

1. Can you think of any conditions where this will fail?

2. Can you think of a better way to do this?

Depending upon the answer(s) to 1, I suppose I could just store the long into a flat file.

 

Use an union to map your chartID (long) to a double using bits representation.

EDIT: In a similar way I showed you here.

 
Alain Verleyen:
Use an union to map your chartID (long) to a double using bits representation.

I played with that a little.

What I found was that the double (from the union) was always 0 for very large values of longs (large = of the size ChartID() returns).

Maybe I was doing something wrong. I'll give it some more thought tomorrow.

 
Anthony Garot:

I played with that a little.

What I found was that the double (from the union) was always 0 for very large values of longs (large = of the size ChartID() returns).

Maybe I was doing something wrong. I'll give it some more thought tomorrow.

Bug in your code ;-)
 
Alain Verleyen:
Bug in your code ;-)

Not 100% sure what's going on.

union _64bits
{
private:
   double            d;
   long              l;
public:
   void _64bits(double v) : d(v)    { };
   void _64bits(long v) : l(v)      { };
   void operator=(double v)         { d=v; };
   void operator=(long v)           { l=v; };
   bool operator==(_64bits &v)      { return d==v.d && l==v.l; };
   long sign(void) const            { return(l>>63); };
   void dump(void)                  { PrintFormat("long [%I64d] double [%f]", l, d); }
};

void OnStart()
{
    // Large # of the size of ChartID()
    _64bits a(128968168951084038);
    a.dump();

    // Small number
    _64bits b(5000);
    b.dump();

    // larger number
    _64bits c(4662219572839972864);
    c.dump();
}

2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [128968168951084038] double [0.000000]
2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [5000] double [0.000000]
2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [4662219572839972864] double [5000.000000]

Depending upon what I put in for a long, I often get 0. for the double value.

(Unless maybe I don't have the right settings for printf() )

 
union _64bits
  {
private:
   double            d;
   ulong             ul;
   long              l;
public:
   void   _64bits(double v) : d(v)     { };
   void   _64bits(long v) : l(v)       { };
   void operator=(double v)            { d=v; };
   bool operator==(_64bits &v) const   { return ul==v.ul; };
   bool operator==(_64bits &v)         { return d==v.d; };
   ulong sign(void) const              { return(ul>>63); };
   double AsDouble(void) const         { return(d); };
   long AsLong(void) const             { return(l); };
  };
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   string gv   = "TEST_CHART_ID_STORAGE";
   _64bits id  = ChartID();

   GlobalVariableSet(gv,id.AsDouble());
   _64bits sid=GlobalVariableGet(gv);

   printf("Chart ID = %lli\n'64 bits' id = %lli\n'64 bits' restored id = %lli",
          ChartID(),id.AsLong(),sid.AsLong());

  }
320999 (GBPUSD,H1)    Chart ID = 131726726208823083
320999 (GBPUSD,H1)    '64 bits' id = 131726726208823083
320999 (GBPUSD,H1)    '64 bits' restored id = 131726726208823083
 
Anthony Garot:

Not 100% sure what's going on.

2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [128968168951084038] double [0.000000]
2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [5000] double [0.000000]
2019.08.27 16:46:45.467    64BitUnion (GBPJPY,H4)    long [4662219572839972864] double [5000.000000]

Depending upon what I put in for a long, I often get 0. for the double value.

(Unless maybe I don't have the right settings for printf() )

The double value doesn't matter. What matters is : the bits.

void dump(void)                  { PrintFormat("long [%I64d] double [%E]", l, d); }
 
Alain Verleyen:

The double value doesn't matter. What matters is the bits.

Yup. I see that now.

What I saw as a printed 0. wasn't really a 0.

Using a union is indeed the preferred solution.

Thanks for proving this for me. :-D


EDIT: I didn't know about %E. I've always used %f. I tried thinks like %.100f . . . but just got more zeroes.
 
Anthony Garot:

Yup. I see that now.

What I saw as a printed 0. wasn't really a 0.

Using a union is indeed the preferred solution.

Thanks for proving this for me. :-D


EDIT: I didn't know about %E. I've always used %f. I tried thinks like %.100f . . . but just got more zeroes.
Always happy to answer you :-)
Reason: