P: n/a

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  
Share this Question
P: n/a

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.  
P: n/a

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  
P: n/a

>
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  
P: n/a

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  
P: n/a

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  
P: n/a

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
KaiUwe Bux  
P: n/a

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)  
P: n/a

In article <3w******************@newsfe2gui.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.  
P: n/a

KaiUwe 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  
P: n/a

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  
P: n/a

Jerry Coffin wrote:
In article <3w******************@newsfe2gui.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  
P: n/a

John Harrison wrote:
KaiUwe 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
KaiUwe Bux  
P: n/a

John Harrison wrote:
Jerry Coffin wrote:
>In article <3w******************@newsfe2gui.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
KaiUwe Bux  
P: n/a

"John Harrison" <jo*************@hotmail.comwrote in message
news:RF******************@newsfe6gui.ntli.net
KaiUwe 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) <= A1? Executing this conditional on x being negative
looks OK to me.

John Carson  
P: n/a

KaiUwe 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  
P: n/a

John Carson wrote:
"John Harrison" <jo*************@hotmail.comwrote in message
news:RF******************@newsfe6gui.ntli.net
>KaiUwe 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) <= A1? 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 A1 is _very_ large.
Best
KaiUwe Bux  
P: n/a

John Harrison wrote:
KaiUwe 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
 
P: n/a

"KaiUwe Bux" <jk********@gmx.netwrote in message
news:er**********@murdoch.acc.Virginia.EDU
John Carson wrote:
>"John Harrison" <jo*************@hotmail.comwrote in message news:RF******************@newsfe6gui.ntli.net
>>KaiUwe 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) <= A1? 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 A1 is _very_
large.
I was assuming A is positive, i.e., that all intervals are nonempty. 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) <= A1)
std::cout << "range 1";

John Carson  
P: n/a

Sorry for the missing body in the previous attempt to post. My head starts
spinning :)
John Harrison wrote:
KaiUwe 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^N1,2^NMAX_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
KaiUwe Bux  
P: n/a

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^N1,2^NMAX_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
KaiUwe 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  
P: n/a

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^N1,2^NMAX_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
KaiUwe 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 builtin 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 welldefined.
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 unnatural.
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 welldefined.
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
KaiUwe Bux  
P: n/a

KaiUwe 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^N1,2^NMAX_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
KaiUwe 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 builtin 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 welldefined.
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 unnatural.
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 welldefined.
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
KaiUwe Bux
Yes, I think that's the way to go. Thanks for your help.
john  
P: n/a

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  
P: n/a

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 onesided test can check membership in
an interval.
{
// 3
}
else
{
// 4
}
Best
KaiUwe Bux  
P: n/a

On 2/18/07 12:15 PM, in article er**********@murdoch.acc.Virginia.EDU,
"KaiUwe 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 onesided 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  
P: n/a

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 twicehence the inefficiency. But I don't think you
can state the logic in any simpler manner.
dr   This discussion thread is closed Replies have been disabled for this discussion.   Question stats  viewed: 2169
 replies: 26
 date asked: Feb 17 '07
