convert a double keeping msb ?

D

DanSteph

hello all,

I have a problem, I have a DOUBLE value like that

4065 4000 0000 0000

and I want to convert it to a DWORD like that:
4065 4000

if I do result=(DWORD)MyDouble it end with AA(170)
wich I don't want.

Believe me or not but I spent 4 hours on this,
I cannot shift the bits, the compiler complaint with double,
it say: "bad left operand" "bad right operand" while it work
well with DWORD.

I'm puzzled, any help appreciated (VC++ 5.0)

Dan
 
D

Denis Remezov

John said:
Like this (this is not portable code)

double x = ...;
DWORD msb = *(DWORD*)&x;

if that doesn't work try

DWORD msb = *((DWORD*)&x + 1);

It is DWORD msb = *((DWORD*)&x + 1); on little endian machines
(e.g. PC).

This one got me thinking: is the result of the above undefined
or implementation-defined behaviour (assuming the size of double
and DWORD as above)? There are two things that I am unsure
about: adjusting a reinterpret_cast-ed pointer and dereferencing
the resulting value. As far as I know, neither is explicitly
condoned. Just a theoretical interest.

Denis
 
J

John Harrison

DanSteph said:
hello all,

I have a problem, I have a DOUBLE value like that

4065 4000 0000 0000

and I want to convert it to a DWORD like that:
4065 4000

if I do result=(DWORD)MyDouble it end with AA(170)
wich I don't want.

Believe me or not but I spent 4 hours on this,
I cannot shift the bits, the compiler complaint with double,
it say: "bad left operand" "bad right operand" while it work
well with DWORD.

I'm puzzled, any help appreciated (VC++ 5.0)

Dan

Like this (this is not portable code)

double x = ...;
DWORD msb = *(DWORD*)&x;

if that doesn't work try

DWORD msb = *((DWORD*)&x + 1);

In either case the trick is doing the conversion via a pointer. That avoids
the compiler converting a double value to a DWORD value.

john
 
J

John Harrison

It is DWORD msb = *((DWORD*)&x + 1); on little endian machines
(e.g. PC).

This one got me thinking: is the result of the above undefined
or implementation-defined behaviour (assuming the size of double
and DWORD as above)? There are two things that I am unsure
about: adjusting a reinterpret_cast-ed pointer and dereferencing
the resulting value. As far as I know, neither is explicitly
condoned. Just a theoretical interest.

Denis

Its the sort of thing that the standard is really bad at explaining. I
believe that it is undefined behaviour (on both counts) because I've seen
others claim that in this group, I couldn't point you to the sections of the
standard to back that up.

Copying to an array of char is explicitly allowed by the standard however,
so if the OP was concerned about UB then he should copy the double to an
array of char and construct the DWORD from that.

john
 
D

DanSteph

Many thanks for your replies,

I finaly woke up in the midle of the night (couln't sleep)
of course pointer was the solution, So I finaly went with that:

DWORD* Ptrweightshort=(DWORD*)&FsStationCrew[0].Weight; // this is double
Ptrweightshort+=1;
DWORD weightshort=*Ptrweightshort;

Nothing as elegant as somes of your solutions but it work.
I'll now try yours.

Many thanks again

Dan
 
B

Bill Seurer

John said:
Its the sort of thing that the standard is really bad at explaining. I
believe that it is undefined behaviour (on both counts) because I've seen
others claim that in this group, I couldn't point you to the sections of the
standard to back that up.

It is bad because of aliasing rules. I don't know what a "DWORD" is but
unless it is somehow related to double the code is not correct.


The C++ aliasing rules are something like this:

If the program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

1. the dynamic type of the object,
2. a cv-qualified version of the declared type of the object,
3. a type that is the signed or unsigned type corresponding to the
declared type of the object,
4. a type that is the signed or unsigned type corresponding to a
cv-qualified version of the declared type of the object,
5. an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively, a member
of a subaggregate or contained union),
6. a type that is a (possibly cv-qualified) base class type of the
declared type of the object,
7. a char or unsigned char type.
 
J

Julie

Bill said:
It is bad because of aliasing rules. I don't know what a "DWORD" is but
unless it is somehow related to double the code is not correct.

DWORD is a double-word (double meaning 2, not double as in double precision
float) in Windows, which is defined as a 32-bit unsigned integral type.
 
J

John Harrison

Bill Seurer said:
It is bad because of aliasing rules. I don't know what a "DWORD" is but
unless it is somehow related to double the code is not correct.

Its unsigned long.
The C++ aliasing rules are something like this:

If the program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined:

1. the dynamic type of the object,
2. a cv-qualified version of the declared type of the object,
3. a type that is the signed or unsigned type corresponding to the
declared type of the object,
4. a type that is the signed or unsigned type corresponding to a
cv-qualified version of the declared type of the object,
5. an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively, a member
of a subaggregate or contained union),
6. a type that is a (possibly cv-qualified) base class type of the
declared type of the object,
7. a char or unsigned char type.

Could you give me the C++ standard section? I looked up aliasing in the
index but it didn't help.

john
 
P

Prateek R Karandikar

DanSteph said:
hello all,

I have a problem, I have a DOUBLE value like that

4065 4000 0000 0000

and I want to convert it to a DWORD like that:
4065 4000

if I do result=(DWORD)MyDouble it end with AA(170)
wich I don't want.

Believe me or not but I spent 4 hours on this,
I cannot shift the bits, the compiler complaint with double,
it say: "bad left operand" "bad right operand" while it work
well with DWORD.

I'm puzzled, any help appreciated (VC++ 5.0)

Dan

Neither the Standard Library nor the language has any type with the
name "DWORD". If this is your own type, post the definition.

-- --
Abstraction is selective ignorance.
-Andrew Koenig
-- --
 
B

Bill Seurer

John said:
Could you give me the C++ standard section? I looked up aliasing in the
index but it didn't help.

In the April 1995 working paper (which I qouted above) it was section
5.0, paragraph 13
 
M

marbac

DanSteph said:
hello all,

I have a problem, I have a DOUBLE value like that

4065 4000 0000 0000

and I want to convert it to a DWORD like that:
4065 4000

if I do result=(DWORD)MyDouble it end with AA(170)
wich I don't want.

Believe me or not but I spent 4 hours on this,
I cannot shift the bits, the compiler complaint with double,
it say: "bad left operand" "bad right operand" while it work
well with DWORD.

Hi, maybe this can help (used union to split 4 bytes into 2x2 bytes:

#include <iostream>
using std::cout;
using std::endl;

union mysplit {
unsigned int d;
unsigned short int i [2];
};

void splitme (unsigned int myint, unsigned short int &low, unsigned
short int &high) {

mysplit temp;
temp.d=myint;
low=temp.i[0];
high=temp.i[1];
}

int main () {
unsigned short int testint1, testint2;
unsigned int testint = 2864434397;

//AA BB CC DD ... BUT COMPILER WARNS (C90 compatible only)
//is just for testing

splitme (testint, testint1, testint2);
cout << testint1 << " ; " << testint2 << endl;
/* testint1: CCDD = 52445,
testint2: AABB = 43707 */

return 0;
}

regards marbac
 
M

marbac

DanSteph said:
hello all,

I have a problem, I have a DOUBLE value like that

4065 4000 0000 0000

and I want to convert it to a DWORD like that:
4065 4000

Hi, maybe this can help (used union to split 4 bytes into 2x2 bytes)
But i did it with int and short int:

#include <iostream>
using std::cout;
using std::endl;

union mysplit {
unsigned int d;
unsigned short int i [2];
};

void splitme (unsigned int myint, unsigned short int &low, unsigned
short int &high) {

mysplit temp;
temp.d=myint;
low=temp.i[0];
high=temp.i[1];
}

int main () {
unsigned short int testint1, testint2;
unsigned int testint = 2864434397;

//AA BB CC DD ... BUT COMPILER WARNS (C90 compatible only)
//is just for testing

splitme (testint, testint1, testint2);
cout << testint1 << " ; " << testint2 << endl;
/* testint1: CCDD = 52445,
testint2: AABB = 43707 */

return 0;
}

regards marbac
 
M

marbac

DanSteph said:
hello all,
Believe me or not but I spent 4 hours on this,
I cannot shift the bits, the compiler complaint with double,
it say: "bad left operand" "bad right operand" while it work
well with DWORD.


Hi, maybe this can help (used union to split 4 bytes into 2x2 bytes)
But i did it with int and short int.


#include <iostream>
using std::cout;
using std::endl;

union mysplit {
unsigned int d;
unsigned short int i [2];
};

void splitme (unsigned int myint, unsigned short int &low, unsigned
short int &high) {

mysplit temp;
temp.d=myint;
low=temp.i[0];
high=temp.i[1];
}

int main () {
unsigned short int testint1, testint2;
unsigned int testint = 2864434397;

//AA BB CC DD ... BUT COMPILER WARNS (C90 compatible only)
//is just for testing

splitme (testint, testint1, testint2);
cout << testint1 << " ; " << testint2 << endl;
/* testint1: CCDD = 52445,
testint2: AABB = 43707 */

return 0;
}


I hope that i understood you correctly.

double has a sign, "mantisse" and an exponent ... maybe you want to
extract those?

regards marbac?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top