Convert 32 bit unsigned int to 16 bit signed int.

F

Fore

Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer. All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer. Any ideas/help greatly
appreciated.

Thanks.
 
R

red floyd

Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer.  All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer.  Any ideas/help greatly
appreciated.

1. Remove the word "efficient" from your lexicon. Study Knuth's/
Hoare's law.
2. Have you not studied the bitwise operators?
 
F

Fore

1. Remove the word "efficient" from your lexicon.  Study Knuth's/
Hoare's law.
2. Have you not studied the bitwise operators?

Answer to 1. I accept removal of efficient and no to ...laws.
Answer to 2. is yes, but I also want to be able to achieve this
without a host of complier warnings about the possible loss of data.
 
K

Kai-Uwe Bux

Jack said:
Aside from the obvious nonsense of "efficient", as others have already
mentioned, you haven't provided an adequate enough definition of the
problem to allow anyone to suggest ANY implementation.

You haven't told us how you plan to translate an larger unsigned value
to a smaller unsigned value. How do you decide which values are
negative?

From what you quoted, he said to use lower order bits (0..15) only and to
use bit 15 for the sign. To me that suggests something like this:

int low_16 ( unsigned long n ) {
n %= ( 1l << 16 );
if ( n >= ( 1l << 15 ) ) {
int i = n % ( 1l << 15 );
return ( - i );
} else {
return ( n );
}
}

I do agree, though, that the specs do leave room for debate.


Best

Kai-Uwe Bux
 
T

Triple-DES

From what you quoted, he said to use lower order bits (0..15) only and to
use bit 15 for the sign. To me that suggests something like this:

int low_16 ( unsigned long n ) {
  n %= ( 1l << 16 );
  if ( n >= ( 1l << 15 ) ) {
    int i = n % ( 1l << 15 );
    return ( - i );
  } else {
    return ( n );
  }

}

I interpreted the OP's specification as if he wanted to extract the
value of the lower 16 bits interpreted as a 2's complement bit
pattern.

short low_16_2sc(unsigned n)
{
return (n & 0x7fffu) - (n & 0x8000u);
}
I do agree, though, that the specs do leave room for debate.

Certainly :)
 
F

Fore

I interpreted the OP's specification as if he wanted to extract the
value of  the lower 16 bits interpreted as a 2's complement bit
pattern.

short low_16_2sc(unsigned n)
{
  return (n & 0x7fffu) - (n & 0x8000u);

}


Certainly :)- Hide quoted text -

- Show quoted text -

Thanks for the constructive criticism on the specification and
suggestions given.
I will make sure any further topics are less ambiguous.
 
J

Juha Nieminen

Fore said:
Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer. All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer. Any ideas/help greatly
appreciated.

Maybe it's just me, but I fail to see how a simple

short n = short(value);

wouldn't do what you want (well, assuming 'short' is 16 bits in your
system, which it usually is). I'm probably missing something.
 
J

James Kanze

Fore wrote:
Maybe it's just me, but I fail to see how a simple
short n = short(value);
wouldn't do what you want (well, assuming 'short' is 16 bits
in your system, which it usually is). I'm probably missing
something.

According to the standard, "If the destination type is signed,
the value is unchanged if it can be represented in the
destination type (and bit-field width); otherwise, the value is
implementation-defined." The C standard is slightly more
restrictive: "When a value with integer type is converted to
another integer type other than _Bool, if the value can be
represented by the new type, it is unchanged. [...]Otherwise,
the new type is signed and the value cannot be represented in
it; either the result is implementation-defined or an
implementation-defined signal is raised."
 
J

James Tursa

Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer. All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer. Any ideas/help greatly
appreciated.

Thanks.

Another method to consider:

short u32_to_i16( unsigned long ul ) {
const unsigned long ul1= 1UL;
if( *((short *)&ul1) )
return *((short *)&ul);
else
return *((short *)&ul + 1);
}

I don't have two different Endian machines to test on, but I think
this should be portable and work on either one. It could be made a bit
faster as follows (define LITTLEENDIAN or not as appropriate for the
particular machine/implementation in use):

#define LITTLEENDIAN

:

#ifdef LITTLEENDIAN

short u32_to_i16( unsigned long ul ) {
return *((short *)&ul);
}

#else

short u32_to_i16( unsigned long ul ) {
return *((short *)&ul + 1);
}

#endif

James Tursa
 
J

James Tursa

I hate to be harsh, but my god, what you just wrote could have simply been
written as

short u32_to_i16( unsigned long ul ) { return (short) ul; }

As with your code, this relies on the machine being two's complement,
having a 16-bit short, and simply taking the low 16 bits without any
overflow checking.

Well, I disagree (but I could be wrong). Your posted method, I
believe, *does* do a value copy and invokes undefined behavior if the
ul value overflows a short. i.e., this statement

(short) ul

of converting an unsigned integer into a signed integer is only
defined in the standard if the valut to be converted fits in the
signed integer range. It is undefined and the result is implementation
dependent if the value does not fit. Isn't that correct? My posted
method attempts to avoid this and simply do a bit copy without value
checking. So I don't believe that your post is in fact equivalent to
my post. Maybe the standard gurus could comment on this and correct me
if I am wrong here.

And yes, my post does rely on some assumptions about sizes of short
and long which I should have mentioned.

I am still trying to figure out your "two's complement" comment. Not
sure what this has to do with it. Could you elaborate?

James Tursa
 
J

James Tursa

I am still trying to figure out your "two's complement" comment. Not
sure what this has to do with it. Could you elaborate?

Let me clarify. I understand that there may be a difference in the
value of the result depending on whether the signed integer
representation on the machine is 2's complement or 1's complement or
whatever. But my understanding of OP's post was that was what he
wanted, which is why I saw the 2's complement issue as not relevant. I
could be misunderstanding OP here, though. In that case, however, OP
would need to say something like "I want the lower 16-bits interpreted
as a 2's complement signed integer and converted properly even if the
underlying representation is 1's complement and I need to check that
the lowest value is overflow checked ... " etc. etc. etc. I didn't
think he wanted that.

James Tursa
 
T

Triple-DES

Triple-DES said:
[...]
I interpreted the OP's specification as if he wanted to extract the
value of  the lower 16 bits interpreted as a 2's complement bit
pattern.
short low_16_2sc(unsigned n)
{
  return (n & 0x7fffu) - (n & 0x8000u);
}

Isn't this non-portable? It seems you'd need to cast both sub-expressions
to int, otherwise the entire return expression will be unsigned, making it
implementation-defined what you get when you convert to short a value that
should become negative. Casting both sub-expressions to int should fix
that. The first is necessary to prevent the compiler from converting the
second sub-expression back to unsigned.

    return (int) (n & 0x7fffu) - (int) (n & 0x8000u);

Yes, you're absolutely right. My mistake.
 
T

Triple-DES

[snip]
I hate to be harsh, but my god, what you just wrote could have simply been
written as
short u32_to_i16( unsigned long ul ) { return (short) ul; }
As with your code, this relies on the machine being two's complement,
having a 16-bit short, and simply taking the low 16 bits without any
overflow checking.

Well, I disagree (but I could be wrong).  Your posted method, I
believe, *does* do a value copy and invokes undefined behavior if the
ul value overflows a short.  i.e., this statement

(short) ul

of converting an unsigned integer into a signed integer is only
defined in the standard if the valut to be converted fits in the
signed integer range. It is undefined and the result is implementation
dependent if the value does not fit. Isn't that correct? My posted
method attempts to avoid this and simply do a bit copy without value
checking. So I don't believe that your post is in fact equivalent to
my post. Maybe the standard gurus could comment on this and correct me
if I am wrong here.

It's true that the result is implementation dependent, but it doesn't
invoke UB.
In your function on the other hand, the cast from unsigned* to short*
yields an unspecified pointer value, and I believe that was blargg's
point.

You are however right that the two functions are not guaranteed to be
equivalent, but again, I don't think that was the point.

DP
 
J

James Tursa

@blueyonder.co.uk> wrote:
Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer.  All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer.  Any ideas/help greatly
appreciated.

Another method to consider:
short u32_to_i16( unsigned long ul ) {
    const unsigned long ul1= 1UL;
    if( *((short *)&ul1) )
        return *((short *)&ul);
    else
        return *((short *)&ul + 1);
}

[snip]
I hate to be harsh, but my god, what you just wrote could have simply been
written as
short u32_to_i16( unsigned long ul ) { return (short) ul; }
As with your code, this relies on the machine being two's complement,
having a 16-bit short, and simply taking the low 16 bits without any
overflow checking.

Well, I disagree (but I could be wrong).  Your posted method, I
believe, *does* do a value copy and invokes undefined behavior if the
ul value overflows a short.  i.e., this statement

(short) ul

of converting an unsigned integer into a signed integer is only
defined in the standard if the valut to be converted fits in the
signed integer range. It is undefined and the result is implementation
dependent if the value does not fit. Isn't that correct? My posted
method attempts to avoid this and simply do a bit copy without value
checking. So I don't believe that your post is in fact equivalent to
my post. Maybe the standard gurus could comment on this and correct me
if I am wrong here.

It's true that the result is implementation dependent, but it doesn't
invoke UB.
In your function on the other hand, the cast from unsigned* to short*
yields an unspecified pointer value, and I believe that was blargg's
point.

Ah, thanks! I stand corrected. Although I certainly did not get that
point at all from blargg's comments.

James Tursa
 
R

Ralf Goertz

Fore said:
Hello
I am looking for some effecient way to convert a 32 bit unsigned
integer to a 16 bit signed integer. All I want is the lower 16 bits
of the 32 bit unsigned integer , with bit 15 (0..15) to used as the
sign bit for the 16 bit signed integer. Any ideas/help greatly
appreciated.

As nobody has suggested it, yet, there must be a problem with the
following approach.

signed16 to_signed_16(const unsigned32 u)
{
unsigned32 m(u%65536); //the 16 lower bits
return ((signed16) ((m>32768) ? -1 : 1)) * (signed16)(m%32768);
//15 lower bits and the 16th for signedness
}

This did not even produce any warnings (with g++ -Wall, short for
signed16 and unsigned int for unsigned32). Of course I don't know about
the efficiency.

Ralf
 
R

Ralf Goertz

blargg said:
signed16 to_signed_16(const unsigned32 u)
{
unsigned32 m(u%65536);
return (signed16) ((m > 32767 ? -32768 : 0) + (signed16)
(m%32768));
}

But you might as well just write it as

signed16 to_signed_16(const unsigned32 u)
{
return (signed16) ((int) (u & 32767) - (int) (u & 32768)); }

which is essentially how Triple-DES wrote it.

But is that really portable? The reason I chose the % operator instead
of & was that mod is not affected by endianess weirdness. I thought
there were systems which are neither big nor little endian but something
in between. Can we really be sure that (u & 32768) = (u % 32768) ?

Ralf
 
J

James Kanze

blargg wrote:
But is that really portable?
Yes.

The reason I chose the % operator instead of & was that mod is
not affected by endianess weirdness.

What endianess weirdness? You're dealing with values; no
endianness is involved.
I thought there were systems which are neither big nor little
endian but something in between.

I've used some, yes, where the order was something like 3412.
Can we really be sure that (u & 32768) = (u % 32768) ?

Actually, you can be sure that it's not:). But (u & 32767) is
guaranteed to be the same as (u % 32768).
 
R

Ralf Goertz

James said:
On Sep 15, 3:19 pm, Ralf Goertz


What endianess weirdness? You're dealing with values; no
endianness is involved.

Okay, if I use 32767 as a value instead or or'ing 1<<i, there should be
no problem.
I've used some, yes, where the order was something like 3412.

But in that case 11111111000000001111111111111111 would be 2^24-1. But
would

unsigned long two_to_the_24th_minus_1()
{
unsigned long i(0);
for (int j=0;j<24;++j)
i|=(1<<j);
return i;
}

return 16777215 on such a machine?
Actually, you can be sure that it's not:). But (u & 32767) is
guaranteed to be the same as (u % 32768).

As I am only a mathematician and not a logician, I am more familiar with
modulo arithmetics than with logical and'ing; ;)

Ralf
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top