473,413 Members | 1,807 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,413 software developers and data experts.

mixing signed and unsigned

I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.

john
Feb 17 '07 #1
26 2719
John Harrison wrote:
I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
Use the next size up, int64_t?

--
Ian Collins.
Feb 17 '07 #2
Ian Collins wrote:
John Harrison wrote:
>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.

Use the next size up, int64_t?
Well a further problem is that the signed type is ptrdiff_t and the
unsigned type is size_t. So I can't say what the next size up is, or
even if it exists.

In the past I've ranted against the very existance of unsigned types on
this group. I promise I'll repent if someone can show me an elegant way
to do this.

john
Feb 17 '07 #3
>
In the past I've ranted against the very existance of unsigned types on
this group. I promise I'll repent if someone can show me an elegant way
to do this.

john
Answering my own question here, but this is the best I've come up with

if (A <= std::numeric_limits<ptrdiff_t>::max() &&
n < -static_cast<ptrdiff_t>(A))
{
// out of range
}
else if (n < 0)
{
// range 1
}
else if (n < static_cast<ptrdiff_t><(B))
{
// range 2
}
else if (C <= std::numeric_limits<ptrdiff_t>::max() &&
n < static_cast<ptrdiff_t>(C))
{
// range 3
}
else
{
// out of range
}

Not quite a bad as I feared but still pretty ugly.

john
Feb 17 '07 #4
John Harrison wrote:
>>
In the past I've ranted against the very existance of unsigned types
on this group. I promise I'll repent if someone can show me an elegant
way to do this.

john


Answering my own question here, but this is the best I've come up with

if (A <= std::numeric_limits<ptrdiff_t>::max() &&
n < -static_cast<ptrdiff_t>(A))
{
// out of range
}
else if (n < 0)
{
// range 1
}
else if (n < static_cast<ptrdiff_t><(B))
{
// range 2
}
else if (C <= std::numeric_limits<ptrdiff_t>::max() &&
n < static_cast<ptrdiff_t>(C))
{
// range 3
}
else
{
// out of range
}

Not quite a bad as I feared but still pretty ugly.

john
Spoke too soon, here's the corrected version with a couple more casts

if (A <= static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max())
&& n < -static_cast<ptrdiff_t>(A))
{
// out of range
}
else if (n < 0)
{
// range 1
}
else if (n < static_cast<ptrdiff_t>(B))
{
// range 2
}
else if (C <= static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max())
&& n < static_cast<ptrdiff_t>(C))
{
// range 3
}
else
{
// out of range
}

john
Feb 17 '07 #5
John Harrison wrote:
John Harrison wrote:
>>>

if (A <= static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max())
&& n < -static_cast<ptrdiff_t>(A))
{
// out of range
}
else if (n < 0)
{
// range 1
}
else if (n < static_cast<ptrdiff_t>(B))
{
// range 2
}
else if (C <= static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max())
&& n < static_cast<ptrdiff_t>(C))
{
// range 3
}
else
{
// out of range
}

john
Yet another correction. Just proves how horrible this signed/unsigned
stuff is, or am I missing a trick?

else if (C static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max())
|| n < static_cast<ptrdiff_t>(C))

john
Feb 17 '07 #6
John Harrison wrote:
I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is large
enough to represent the absolute values of the signed type, you will be
fine.
Best

Kai-Uwe Bux
Feb 17 '07 #7
John Harrison wrote:
I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
In that case, the values of the range limits need to be adjusted. If A
is greater than INT_MAX, replace it with INT_MAX. Same for C. Then do
everything signed.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Feb 18 '07 #8
In article <3w******************@newsfe2-gui.ntli.net>,
jo*************@hotmail.com says...
I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
If you can't count on having a type with a large enough range to hold
all the possible values, you probably need to work primarily with
unsigned values:

bool in_range_u(ptrdiff_t value, size_t min, size_t max) {
if (value < 0)
return false;
return (static_cast<size_t>(value) >= min) &&
(static_cast<size_t>(value) < max);
}

if (in_range_u(x, 0, B))
first_range();
else if (in_range_u(-x, 0, A+1)
second_range();
else if (in_range_u(x, B, C)
third_range();
else
fourth_range();

The two casts aren't really necessary, but I'd prefer them over a
warning, which would be normal for a mixed signed/unsigned comparsison.

Although I believe the code should work, it is _quite_ fragile. For
example in_range_u(-x, 0, A+1) does NOT really work correctly. We get
around that by testing the second range first, and only testing the
first range if we've determined that x!=0.

To be pedantically correct, you might need to add special case code for
a couple of possibilities: one is for magnitude(A) == magnitude
(INT_MIN), and the other is for A==std::numeric_limits<size_t>::max. It
isn't hard to do these without warnings or casts, but it does make the
code a bit ugly.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 18 '07 #9
Kai-Uwe Bux wrote:
John Harrison wrote:

>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.


What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is large
enough to represent the absolute values of the signed type, you will be
fine.
I thought of something like that, but two problems.

-x would overflow if x == std::numeric_limits<ptrdiff_t>::min()

"above all" and "below all" are the same outcome and I'd prefer not to
write the same code twice

john
Feb 18 '07 #10
Pete Becker wrote:
John Harrison wrote:
>I have a problem. I want to compare an integral value, n, against
three half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral
value isn't within any of the ranges, that's a fourth outcome. So far
so easy, the problem is that n is a signed quantity and A, B, C are
unsigned quantities. Apart from this obscure corner of my code this
makes perfect sense, so I don't want to change the signedness of
anything.

How to I write these tests so that my code is reasonably
understandable, rather than a horrible mess of casts and compiler
warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.

In that case, the values of the range limits need to be adjusted. If A
is greater than INT_MAX, replace it with INT_MAX. Same for C. Then do
everything signed.
If A equals INT_MAX + 1, then -A == INT_MIN so I have to deal with that
(unlikely) case too.

john
Feb 18 '07 #11
Jerry Coffin wrote:
In article <3w******************@newsfe2-gui.ntli.net>,
jo*************@hotmail.com says...
>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.


If you can't count on having a type with a large enough range to hold
all the possible values, you probably need to work primarily with
unsigned values:

bool in_range_u(ptrdiff_t value, size_t min, size_t max) {
if (value < 0)
return false;
return (static_cast<size_t>(value) >= min) &&
(static_cast<size_t>(value) < max);
}

if (in_range_u(x, 0, B))
first_range();
else if (in_range_u(-x, 0, A+1)
second_range();
else if (in_range_u(x, B, C)
third_range();
else
fourth_range();

The two casts aren't really necessary, but I'd prefer them over a
warning, which would be normal for a mixed signed/unsigned comparsison.

Although I believe the code should work, it is _quite_ fragile. For
example in_range_u(-x, 0, A+1) does NOT really work correctly. We get
around that by testing the second range first, and only testing the
first range if we've determined that x!=0.

To be pedantically correct, you might need to add special case code for
a couple of possibilities: one is for magnitude(A) == magnitude
(INT_MIN), and the other is for A==std::numeric_limits<size_t>::max. It
isn't hard to do these without warnings or casts, but it does make the
code a bit ugly.
Pedantically correct is what I'm aiming for. Here's my latest effort, it
took me several goes but I believe its correct.

static size_t MAX_A = std::numeric_limits<ptrdiff_t>::max() + 1;
static size_t MAX_C = std::numeric_limits<ptrdiff_t>::max();
if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||
C <= MAX_C && n >= static_cast<ptrdiff_t>(C))
{
}
else if (n < 0)
{
}
else if (n < static_cast<ptrdiff_t>(B))
{
}
else
{
}

It does produce one stupid warning on my compiler 'unary minus operator
applied to unsigned type, result still unsigned' but I can turn that off.

john
Feb 18 '07 #12
John Harrison wrote:
Kai-Uwe Bux wrote:
>John Harrison wrote:

>>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.


What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is large
enough to represent the absolute values of the signed type, you will be
fine.

I thought of something like that, but two problems.

-x would overflow if x == std::numeric_limits<ptrdiff_t>::min()
Oops, you'r right. I forgot a cast.

"above all" and "below all" are the same outcome and I'd prefer not to
write the same code twice
The two cases are, of course, not the same. You just want them to be the
same. In that case, just use a goto :-)
So, the corrected code is:

#include <iostream>
#include <limits>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
int x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
out_of_range:
std::cout << "out_of_range";
}
} else {
// we cast first so that unary - does not cause an overflow.
if ( -static_cast<unsigned long>(x) <= A ) {
std::cout << "range 1";
} else {
// we do not distinguish underflow and overflow:
goto out_of_range;
}
}
std::cout << '\n';
}
}
Of course, there are ways to get around the goto, e.g., you could put the
common code into a function.
Best

Kai-Uwe Bux
Feb 18 '07 #13
John Harrison wrote:
Jerry Coffin wrote:
>In article <3w******************@newsfe2-gui.ntli.net>,
jo*************@hotmail.com says...
>>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.


If you can't count on having a type with a large enough range to hold
all the possible values, you probably need to work primarily with
unsigned values:

bool in_range_u(ptrdiff_t value, size_t min, size_t max) {
if (value < 0)
return false;
return (static_cast<size_t>(value) >= min) &&
(static_cast<size_t>(value) < max);
}

if (in_range_u(x, 0, B))
first_range();
else if (in_range_u(-x, 0, A+1)
second_range();
else if (in_range_u(x, B, C)
third_range();
else
fourth_range();

The two casts aren't really necessary, but I'd prefer them over a
warning, which would be normal for a mixed signed/unsigned comparsison.

Although I believe the code should work, it is _quite_ fragile. For
example in_range_u(-x, 0, A+1) does NOT really work correctly. We get
around that by testing the second range first, and only testing the
first range if we've determined that x!=0.

To be pedantically correct, you might need to add special case code for
a couple of possibilities: one is for magnitude(A) == magnitude
(INT_MIN), and the other is for A==std::numeric_limits<size_t>::max. It
isn't hard to do these without warnings or casts, but it does make the
code a bit ugly.

Pedantically correct is what I'm aiming for. Here's my latest effort, it
took me several goes but I believe its correct.

static size_t MAX_A = std::numeric_limits<ptrdiff_t>::max() + 1;
That looks like undefined behavior: the RHS computes a signed integer
overflow _before_ it is cast to unsigned.

Ok, this depends on whether 1 is signed or unsigned. I think the type of 1
is int, not unsigned. Let's test this:

#include <iostream>
#include <string>

std::string type ( int ) {
return ( "int" );
}

std::string type ( unsigned ) {
return ( "unsigned" );
}

int main ( void ) {
std::cout << type(1) << '\n';
}

And the winner is:

news_groupa.out
int

static size_t MAX_C = std::numeric_limits<ptrdiff_t>::max();
if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||
This, too, looks fishy. What if A == numeric_limits<ptrdiff_t>::max()?
Assuming that ptrdiff_t and size_t have the same number of bits, this value
would be the middle of size_t and it would be a fixed point w.r.t. unary -.
I.e., -A == A. Then, the static_cast will not change the value to the
negative side. If n == -numeric_limits<ptrdiff_t>::max(), you get the wrong
answer.
C <= MAX_C && n >= static_cast<ptrdiff_t>(C))
{
}
else if (n < 0)
{
}
else if (n < static_cast<ptrdiff_t>(B))
{
}
else
{
}

It does produce one stupid warning on my compiler 'unary minus operator
applied to unsigned type, result still unsigned' but I can turn that off.

Best

Kai-Uwe Bux
Feb 18 '07 #14
"John Harrison" <jo*************@hotmail.comwrote in message
news:RF******************@newsfe6-gui.ntli.net
Kai-Uwe Bux wrote:
>John Harrison wrote:

>>I have a problem. I want to compare an integral value, n, against
three half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral
value isn't within any of the ranges, that's a fourth outcome. So
far so easy, the problem is that n is a signed quantity and A, B, C
are unsigned quantities. Apart from this obscure corner of my code
this makes perfect sense, so I don't want to change the signedness
of anything. How to I write these tests so that my code is reasonably
understandable, rather than a horrible mess of casts and compiler
warnings? One more point, of the unsigned quantity, only B is guaranteed
small
enough that it could be safely cast to a signed integer.


What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is
large enough to represent the absolute values of the signed type,
you will be fine.

I thought of something like that, but two problems.

-x would overflow if x == std::numeric_limits<ptrdiff_t>::min()
How about -(x+1) <= A-1? Executing this conditional on x being negative
looks OK to me.
--
John Carson
Feb 18 '07 #15
Kai-Uwe Bux wrote:
>>
Pedantically correct is what I'm aiming for. Here's my latest effort, it
took me several goes but I believe its correct.

static size_t MAX_A = std::numeric_limits<ptrdiff_t>::max() + 1;


That looks like undefined behavior: the RHS computes a signed integer
overflow _before_ it is cast to unsigned.
Yes you're right, yet another cast will fix that.
>>if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||


This, too, looks fishy. What if A == numeric_limits<ptrdiff_t>::max()?
Assuming that ptrdiff_t and size_t have the same number of bits, this value
would be the middle of size_t and it would be a fixed point w.r.t. unary -.
I.e., -A == A. Then, the static_cast will not change the value to the
negative side. If n == -numeric_limits<ptrdiff_t>::max(), you get the wrong
answer.
Doe you mean A == numeric_limits<ptrdiff_t>::max() + 1 ? Then A is at
the fixed point but in that case the static_cast does change the value
to the negative side.

size_t x = static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max()) + 1;
std::cout << x << '\n';
std::cout << -x << '\n';
std::cout << static_cast<ptrdiff_t>(-x) << '\n';

output (on my platform)

2147483648
2147483648
-2147483648

john
Feb 18 '07 #16
John Carson wrote:
"John Harrison" <jo*************@hotmail.comwrote in message
news:RF******************@newsfe6-gui.ntli.net
>Kai-Uwe Bux wrote:
>>John Harrison wrote:
I have a problem. I want to compare an integral value, n, against
three half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral
value isn't within any of the ranges, that's a fourth outcome. So
far so easy, the problem is that n is a signed quantity and A, B, C
are unsigned quantities. Apart from this obscure corner of my code
this makes perfect sense, so I don't want to change the signedness
of anything. How to I write these tests so that my code is reasonably
understandable, rather than a horrible mess of casts and compiler
warnings? One more point, of the unsigned quantity, only B is
guaranteed small
enough that it could be safely cast to a signed integer.
What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is
large enough to represent the absolute values of the signed type,
you will be fine.

I thought of something like that, but two problems.

-x would overflow if x == std::numeric_limits<ptrdiff_t>::min()

How about -(x+1) <= A-1? Executing this conditional on x being negative
looks OK to me.
Runs into trouble for A == 0: it would accept everything where it should
reject everything; A is unsigned, if A==0 then A-1 is _very_ large.
Best

Kai-Uwe Bux
Feb 18 '07 #17
John Harrison wrote:
Kai-Uwe Bux wrote:
[snip]
>>>if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||


This, too, looks fishy. What if A == numeric_limits<ptrdiff_t>::max()?
Assuming that ptrdiff_t and size_t have the same number of bits, this
value would be the middle of size_t and it would be a fixed point w.r.t.
unary -. I.e., -A == A. Then, the static_cast will not change the value
to the negative side. If n == -numeric_limits<ptrdiff_t>::max(), you get
the wrong answer.

Doe you mean A == numeric_limits<ptrdiff_t>::max() + 1 ? Then A is at
the fixed point but in that case the static_cast does change the value
to the negative side.

size_t x = static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max()) + 1;
std::cout << x << '\n';
std::cout << -x << '\n';
std::cout << static_cast<ptrdiff_t>(-x) << '\n';

output (on my platform)

2147483648
2147483648
-2147483648

Feb 18 '07 #18
"Kai-Uwe Bux" <jk********@gmx.netwrote in message
news:er**********@murdoch.acc.Virginia.EDU
John Carson wrote:
>"John Harrison" <jo*************@hotmail.comwrote in message
news:RF******************@newsfe6-gui.ntli.net
>>Kai-Uwe Bux wrote:
John Harrison wrote:
I have a problem. I want to compare an integral value, n, against
three half open ranges as follows
>
[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3
>
Each range corresponds to a different outcome and if the integral
value isn't within any of the ranges, that's a fourth outcome. So
far so easy, the problem is that n is a signed quantity and A, B,
C are unsigned quantities. Apart from this obscure corner of my
code this makes perfect sense, so I don't want to change the
signedness of anything. How to I write these tests so that my
code is reasonably understandable, rather than a horrible mess of
casts and compiler warnings? One more point, of the unsigned
quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
What about:

#include <iostream>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
long x = 0;
while ( std::cin >x ) {
if ( x >= 0 ) {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
std::cout << "above all ranges";
}
} else {
if ( ( -x ) <= A ) {
std::cout << "range 1";
} else {
std::cout << "below all ranges";
}
}
std::cout << '\n';
}
}

This only compares positive values. As long as the unsigned type is
large enough to represent the absolute values of the signed type,
you will be fine.
I thought of something like that, but two problems.

-x would overflow if x == std::numeric_limits<ptrdiff_t>::min()

How about -(x+1) <= A-1? Executing this conditional on x being
negative looks OK to me.

Runs into trouble for A == 0: it would accept everything where it
should reject everything; A is unsigned, if A==0 then A-1 is _very_
large.
I was assuming A is positive, i.e., that all intervals are non-empty. If
that is not the case, then a separate check for A 0 would deal with the
problem.

[for x<0]

if (A>0 && -(x+1) <= A-1)
std::cout << "range 1";

--
John Carson
Feb 18 '07 #19
Sorry for the missing body in the previous attempt to post. My head starts
spinning :-)

John Harrison wrote:
Kai-Uwe Bux wrote:
[snip]
>>>if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||


This, too, looks fishy. What if A == numeric_limits<ptrdiff_t>::max()?
Assuming that ptrdiff_t and size_t have the same number of bits, this
value would be the middle of size_t and it would be a fixed point w.r.t.
unary -. I.e., -A == A. Then, the static_cast will not change the value
to the negative side. If n == -numeric_limits<ptrdiff_t>::max(), you get
the wrong answer.

Doe you mean A == numeric_limits<ptrdiff_t>::max() + 1 ?
You are right. I did not get the fixed point right.
Then A is at
the fixed point but in that case the static_cast does change the value
to the negative side.
Why? See [4.7./3] which tells you that the result of this conversion is
implementation defined.
size_t x = static_cast<size_t>(std::numeric_limits<ptrdiff_t> ::max()) + 1;
std::cout << x << '\n';
std::cout << -x << '\n';
std::cout << static_cast<ptrdiff_t>(-x) << '\n';

output (on my platform)

2147483648
2147483648
-2147483648
Ok, let me think this through carefully. I just feel in my bones that
something is wrong with the line

if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||

as a means of checking whether n below [A,0).
We know A is unsigned and

A <= MAX_A

where MAX_A == 1+static_cast<size_t>(std::numeric_limits<ptrdiff_ t>::max())

i.e.

A in [0,MAX_A]

Thus -A in [2^N-1,2^N-MAX_A] or -A == 0.

Now, what happens if we cast -A to the signed type? For values of -A above
numeric_limits<ptrdiff_t(and that is almost all values that occur here),
we have an implementation defined value [4.7/3].

This is probably bad.
Best

Kai-Uwe Bux
Feb 18 '07 #20
Ok, let me think this through carefully. I just feel in my bones that
something is wrong with the line

if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||

as a means of checking whether n below [A,0).
We know A is unsigned and

A <= MAX_A

where MAX_A == 1+static_cast<size_t>(std::numeric_limits<ptrdiff_ t>::max())

i.e.

A in [0,MAX_A]

Thus -A in [2^N-1,2^N-MAX_A] or -A == 0.

Now, what happens if we cast -A to the signed type? For values of -A above
numeric_limits<ptrdiff_t(and that is almost all values that occur here),
we have an implementation defined value [4.7/3].

This is probably bad.
Best

Kai-Uwe Bux
Oh well, back to the drawing board. Why can't the standard just say that
result of signed/unsigned comparisons is the mathematically correct one?

john

Feb 18 '07 #21
John Harrison wrote:
>
>Ok, let me think this through carefully. I just feel in my bones that
something is wrong with the line

if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||

as a means of checking whether n below [A,0).
We know A is unsigned and

A <= MAX_A

where MAX_A ==
1+static_cast<size_t>(std::numeric_limits<ptrdiff _t>::max())

i.e.

A in [0,MAX_A]

Thus -A in [2^N-1,2^N-MAX_A] or -A == 0.

Now, what happens if we cast -A to the signed type? For values of -A
above numeric_limits<ptrdiff_t(and that is almost all values that occur
here), we have an implementation defined value [4.7/3].

This is probably bad.
Best

Kai-Uwe Bux

Oh well, back to the drawing board. Why can't the standard just say that
result of signed/unsigned comparisons is the mathematically correct one?

Now, that would take all the fun out of the built-in types, wouldn't it?

As far as I can tell, the standard make the following choice: the signed
types are supposed to be the machines native types. Accordingly, there are
very few guarantees about what they do. Being cynical, once coud say that
the best thing about them, is that it is mathematically defined how they
convert to the unsigned types. The unsigned types make string guarantees:
they implement arithmetic mod 2^N (N is the bitlength). This goes even for
multiplication. Thus unsigned arithmetic is perfectly well-defined.

The standard then had to decide what to do about mixed expressions. The
choice was made that in this case, predictability comes before performance.
The way to ensure predictability is to cast all operands in a mixed binary
expression to unsigned. You have a point with regard to the comparison
operators: it is rather un-natural.

My way to deal with this, is to test first whether the signed value is
negative. Then, the very next step has to be a cast. From then on,
everything is well-defined.
BTW: now, I think, I got a somewhat way of doing the problem. The code
reflects the natural order of the ranges, and uses only one cast. It may
trigger tons of warnings, though, about mixed comparisons.
#include <iostream>
#include <limits>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
int x = 0;
while ( std::cin >x ) {

if ( x < 0 ) {
// we cast first so that unary - does not cause an overflow:
if ( -static_cast<unsigned long>(x) A ) {
// underflow: treated like overflow!
goto out_of_range;
} else {
std::cout << "range 1";
}
} else {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
// overflow:
out_of_range:
std::cout << "out of range";
}
}
std::cout << '\n';
}
}
(You may consider the goto a hook for the maintenace programmer should the
need arise in the future to distinguish between overflow and underflow :-)

Best

Kai-Uwe Bux
Feb 18 '07 #22
Kai-Uwe Bux wrote:
John Harrison wrote:

>>>Ok, let me think this through carefully. I just feel in my bones that
something is wrong with the line

if (A <= MAX_A && n < static_cast<ptrdiff_t>(-A) ||

as a means of checking whether n below [A,0).
We know A is unsigned and

A <= MAX_A

where MAX_A ==
1+static_cast<size_t>(std::numeric_limits<ptrdi ff_t>::max())

i.e.

A in [0,MAX_A]

Thus -A in [2^N-1,2^N-MAX_A] or -A == 0.

Now, what happens if we cast -A to the signed type? For values of -A
above numeric_limits<ptrdiff_t(and that is almost all values that occur
here), we have an implementation defined value [4.7/3].

This is probably bad.
Best

Kai-Uwe Bux

Oh well, back to the drawing board. Why can't the standard just say that
result of signed/unsigned comparisons is the mathematically correct one?

Now, that would take all the fun out of the built-in types, wouldn't it?

As far as I can tell, the standard make the following choice: the signed
types are supposed to be the machines native types. Accordingly, there are
very few guarantees about what they do. Being cynical, once coud say that
the best thing about them, is that it is mathematically defined how they
convert to the unsigned types. The unsigned types make string guarantees:
they implement arithmetic mod 2^N (N is the bitlength). This goes even for
multiplication. Thus unsigned arithmetic is perfectly well-defined.

The standard then had to decide what to do about mixed expressions. The
choice was made that in this case, predictability comes before performance.
The way to ensure predictability is to cast all operands in a mixed binary
expression to unsigned. You have a point with regard to the comparison
operators: it is rather un-natural.

My way to deal with this, is to test first whether the signed value is
negative. Then, the very next step has to be a cast. From then on,
everything is well-defined.
BTW: now, I think, I got a somewhat way of doing the problem. The code
reflects the natural order of the ranges, and uses only one cast. It may
trigger tons of warnings, though, about mixed comparisons.
#include <iostream>
#include <limits>

int main ( void ) {
unsigned long A = 30;
unsigned long B = 20;
unsigned long C = 100;
int x = 0;
while ( std::cin >x ) {

if ( x < 0 ) {
// we cast first so that unary - does not cause an overflow:
if ( -static_cast<unsigned long>(x) A ) {
// underflow: treated like overflow!
goto out_of_range;
} else {
std::cout << "range 1";
}
} else {
if ( x < B ) {
std::cout << "range 2";
} else if ( x < C ) {
std::cout << "range 3";
} else {
// overflow:
out_of_range:
std::cout << "out of range";
}
}
std::cout << '\n';
}
}
(You may consider the goto a hook for the maintenace programmer should the
need arise in the future to distinguish between overflow and underflow :-)

Best

Kai-Uwe Bux

Yes, I think that's the way to go. Thanks for your help.

john
Feb 18 '07 #23
On Feb 17, 2:41 pm, John Harrison <john_androni...@hotmail.comwrote:
I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
As long as the comparisons return the expected results - the values
being compared need not match the original ones:

if (( n - (-A)) >= 0 and n < 0)
{
// 1
}
else
if ( n >= 0 and n < B - 0 )
{
// 2
}
else
if ( n - B >= 0 and n - B < C - B))
{
// 3
}
else
{
// 4
}

Greg

Feb 18 '07 #24
Greg Herlihy wrote:
On Feb 17, 2:41 pm, John Harrison <john_androni...@hotmail.comwrote:
>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.

As long as the comparisons return the expected results - the values
being compared need not match the original ones:

if (( n - (-A)) >= 0 and n < 0)
Does not work for n == -40, A == 30: Will yield true where it should say
false.
{
// 1
}
else
if ( n >= 0 and n < B - 0 )
What is the "-0" supposed to accomplish?
{
// 2
}
else
if ( n - B >= 0 and n - B < C - B))
This also looks fishy: in "n - B" the signed n will be cast to unsigned
first. The difference will then be taken mod 2^N (N is the bitlength). The
result will _always_ be >= 0. Thus, the first test has no chance to fail.
It would be really surprising if a one-sided test can check membership in
an interval.
{
// 3
}
else
{
// 4
}

Best

Kai-Uwe Bux

Feb 18 '07 #25

On 2/18/07 12:15 PM, in article er**********@murdoch.acc.Virginia.EDU,
"Kai-Uwe Bux" <jk********@gmx.netwrote:
Greg Herlihy wrote:
>On Feb 17, 2:41 pm, John Harrison <john_androni...@hotmail.comwrote:
>>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.

As long as the comparisons return the expected results - the values
being compared need not match the original ones:

if (( n - (-A)) >= 0 and n < 0)

Does not work for n == -40, A == 30: Will yield true where it should say
false.
True, the first test should be:

n >= -A and n - (-A) < 0 - (-A)

....which can be simplified (see below).
> {
// 1
}
else
if ( n >= 0 and n < B - 0 )

What is the "-0" supposed to accomplish?
Perhaps another 0 would help:

if ( n >= 0 and n - 0 < B - 0 )

The goal is to illustrate the formula being applied - which is:

(n >= lower) and ((n - lower) (upper - lower))
> {
// 2
}
else
if ( n - B >= 0 and n - B < C - B))

This also looks fishy: in "n - B" the signed n will be cast to unsigned
first. The difference will then be taken mod 2^N (N is the bitlength). The
result will _always_ be >= 0. Thus, the first test has no chance to fail.
It would be really surprising if a one-sided test can check membership in
an interval.
True, I misapplied the formula in the last case. So with the corrections,
the entire sequence of tests would be:

if ( n >= -A and n + A < A )
{
// 1
}
else
if ( n >= 0 and n - 0 < B - 0 )
{
// 2
}
else
if ( n >= B and n - B < C - B )
{
// 3
}
else
{
// 4
}

Greg

Feb 18 '07 #26
On 18 Feb 2007 10:29:48 -0800, "Greg Herlihy" <gr****@pacbell.netwrote:
>On Feb 17, 2:41 pm, John Harrison <john_androni...@hotmail.comwrote:
>I have a problem. I want to compare an integral value, n, against three
half open ranges as follows

[-A, 0) // range 1
[0, B) // range 2
[B, C} // range 3

Each range corresponds to a different outcome and if the integral value
isn't within any of the ranges, that's a fourth outcome. So far so easy,
the problem is that n is a signed quantity and A, B, C are unsigned
quantities. Apart from this obscure corner of my code this makes perfect
sense, so I don't want to change the signedness of anything.

How to I write these tests so that my code is reasonably understandable,
rather than a horrible mess of casts and compiler warnings?

One more point, of the unsigned quantity, only B is guaranteed small
enough that it could be safely cast to a signed integer.
Not the most efficient technique, but quite understandable:

if (n < 0) // signed comparison
{
if (n >= -A) // signed
{
// 1
}
else
{
// 4
}
}
else if (n < B) // unsigned
{
// 2
}
else if (n < C) // unsigned
{
// 3
}
else
{
// 4
}

Note that case 4 appears twice--hence the inefficiency. But I don't think you
can state the logic in any simpler manner.

-dr
Feb 18 '07 #27

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

10
by: tinesan | last post by:
Hello fellow C programmers, I'm just learning to program with C, and I'm wondering what the difference between signed and unsigned char is. To me there seems to be no difference, and the...
3
by: T | last post by:
Given: typedef unsigned short u16; typedef signed int i32; u16 u0 = 0xFFFF; i32 i1 = u0; u16 u1 = 0; i32 i2 = u1 - (u16)1;
10
by: =?iso-8859-2?B?SmFuIFJpbmdvuQ==?= | last post by:
Hello everybody, this is my first post to a newsgroup at all. I would like to get some feedback on one proposal I am thinking about: --- begin of proposal --- Proposal to add...
7
by: somenath | last post by:
Hi All, I am trying to undestand "Type Conversions" from K&R book.I am not able to understand the bellow mentioned text "Conversion rules are more complicated when unsigned operands are...
6
by: Kislay | last post by:
Consider the following code snippet unsigned int i=10; int j= - 2; // minus 2 if(i>j) cout<<"i is greater"; else cout<<"j is greater"; Since i is unsigned , j is greater . I know why , but...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.