443,889 Members | 1,373 Online Need help? Post your question and get tips & solutions from a community of 443,889 IT Pros & Developers. It's quick & easy.

# mixing signed and unsigned

 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 Feb 17 '07 #1
26 Replies

 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. Feb 17 '07 #2

 P: n/a Ian Collins wrote: John Harrison wrote: >>I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough 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

 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::max() && n < -static_cast(A)) { // out of range } else if (n < 0) { // range 1 } else if (n < static_cast<(B)) { // range 2 } else if (C <= std::numeric_limits::max() && n < static_cast(C)) { // range 3 } else { // out of range } Not quite a bad as I feared but still pretty ugly. john Feb 17 '07 #4

 P: n/a John Harrison wrote: >>In the past I've ranted against the very existance of unsigned typeson this group. I promise I'll repent if someone can show me an elegantway to do this.john Answering my own question here, but this is the best I've come up with if (A <= std::numeric_limits::max() && n < -static_cast(A)) { // out of range } else if (n < 0) { // range 1 } else if (n < static_cast<(B)) { // range 2 } else if (C <= std::numeric_limits::max() && n < static_cast(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(std::numeric_limits ::max()) && n < -static_cast(A)) { // out of range } else if (n < 0) { // range 1 } else if (n < static_cast(B)) { // range 2 } else if (C <= static_cast(std::numeric_limits ::max()) && n < static_cast(C)) { // range 3 } else { // out of range } john Feb 17 '07 #5

 P: n/a John Harrison wrote: John Harrison wrote: >>> if (A <= static_cast(std::numeric_limits ::max()) && n < -static_cast(A)) { // out of range } else if (n < 0) { // range 1 } else if (n < static_cast(B)) { // range 2 } else if (C <= static_cast(std::numeric_limits ::max()) && n < static_cast(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(std::numeric_limits ::max()) || n < static_cast(C)) john Feb 17 '07 #6

 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 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

 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) Feb 18 '07 #8

 P: n/a 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(value) >= min) && (static_cast(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::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

 P: n/a Kai-Uwe Bux wrote: John Harrison wrote: >>I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough that it could be safely cast to a signed integer. What about: #include 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::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

 P: n/a Pete Becker wrote: John Harrison wrote: >I have a problem. I want to compare an integral value, n, againstthree half open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integralvalue isn't within any of the ranges, that's a fourth outcome. So farso easy, the problem is that n is a signed quantity and A, B, C areunsigned quantities. Apart from this obscure corner of my code thismakes perfect sense, so I don't want to change the signedness ofanything.How to I write these tests so that my code is reasonablyunderstandable, rather than a horrible mess of casts and compilerwarnings?One more point, of the unsigned quantity, only B is guaranteed smallenough 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

 P: n/a 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 threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough 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(value) >= min) && (static_cast(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::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::max() + 1; static size_t MAX_C = std::numeric_limits::max(); if (A <= MAX_A && n < static_cast(-A) || C <= MAX_C && n >= static_cast(C)) { } else if (n < 0) { } else if (n < static_cast(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

 P: n/a John Harrison wrote: Kai-Uwe Bux wrote: >John Harrison wrote: >>>I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough that it could be safely cast to a signed integer. What about:#include 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 largeenough to represent the absolute values of the signed type, you will befine. I thought of something like that, but two problems. -x would overflow if x == std::numeric_limits::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 #include 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(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

 P: n/a 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 threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough 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 holdall the possible values, you probably need to work primarily withunsigned values:bool in_range_u(ptrdiff_t value, size_t min, size_t max) {if (value < 0)return false;return (static_cast(value) >= min) &&(static_cast(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();elsefourth_range();The two casts aren't really necessary, but I'd prefer them over awarning, which would be normal for a mixed signed/unsigned comparsison.Although I believe the code should work, it is _quite_ fragile. Forexample in_range_u(-x, 0, A+1) does NOT really work correctly. We getaround that by testing the second range first, and only testing thefirst range if we've determined that x!=0.To be pedantically correct, you might need to add special case code fora couple of possibilities: one is for magnitude(A) == magnitude(INT_MIN), and the other is for A==std::numeric_limits::max. Itisn't hard to do these without warnings or casts, but it does make thecode 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::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 #include 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::max(); if (A <= MAX_A && n < static_cast(-A) || This, too, looks fishy. What if A == numeric_limits::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::max(), you get the wrong answer. C <= MAX_C && n >= static_cast(C)) { } else if (n < 0) { } else if (n < static_cast(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

 P: n/a "John Harrison" John Harrison wrote: >>I have a problem. I want to compare an integral value, n, againstthree half open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integralvalue isn't within any of the ranges, that's a fourth outcome. Sofar so easy, the problem is that n is a signed quantity and A, B, Care unsigned quantities. Apart from this obscure corner of my codethis makes perfect sense, so I don't want to change the signednessof anything. How to I write these tests so that my code is reasonablyunderstandable, rather than a horrible mess of casts and compilerwarnings? One more point, of the unsigned quantity, only B is guaranteedsmallenough that it could be safely cast to a signed integer. What about:#include 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 islarge 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::min() How about -(x+1) <= A-1? Executing this conditional on x being negative looks OK to me. -- John Carson Feb 18 '07 #15

 P: n/a Kai-Uwe Bux wrote: >>Pedantically correct is what I'm aiming for. Here's my latest effort, ittook me several goes but I believe its correct.static size_t MAX_A = std::numeric_limits::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(-A) || This, too, looks fishy. What if A == numeric_limits::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::max(), you get the wrong answer. Doe you mean A == numeric_limits::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(std::numeric_limits ::max()) + 1; std::cout << x << '\n'; std::cout << -x << '\n'; std::cout << static_cast(-x) << '\n'; output (on my platform) 2147483648 2147483648 -2147483648 john Feb 18 '07 #16

 P: n/a John Carson wrote: "John Harrison" Kai-Uwe Bux wrote: >>John Harrison wrote: I have a problem. I want to compare an integral value, n, againstthree half open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integralvalue isn't within any of the ranges, that's a fourth outcome. Sofar so easy, the problem is that n is a signed quantity and A, B, Care unsigned quantities. Apart from this obscure corner of my codethis makes perfect sense, so I don't want to change the signednessof anything. How to I write these tests so that my code is reasonablyunderstandable, rather than a horrible mess of casts and compilerwarnings? One more point, of the unsigned quantity, only B isguaranteed smallenough that it could be safely cast to a signed integer. What about:#include 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 islarge 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::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

 P: n/a John Harrison wrote: Kai-Uwe Bux wrote: [snip] >>>if (A <= MAX_A && n < static_cast(-A) || This, too, looks fishy. What if A == numeric_limits::max()?Assuming that ptrdiff_t and size_t have the same number of bits, thisvalue 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 valueto the negative side. If n == -numeric_limits::max(), you getthe wrong answer. Doe you mean A == numeric_limits::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(std::numeric_limits ::max()) + 1; std::cout << x << '\n'; std::cout << -x << '\n'; std::cout << static_cast(-x) << '\n'; output (on my platform) 2147483648 2147483648 -2147483648 Feb 18 '07 #18

 P: n/a "Kai-Uwe Bux" "John Harrison" >Kai-Uwe Bux wrote:John Harrison wrote: I have a problem. I want to compare an integral value, n, againstthree 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 integralvalue isn't within any of the ranges, that's a fourth outcome. Sofar so easy, the problem is that n is a signed quantity and A, B,C are unsigned quantities. Apart from this obscure corner of mycode this makes perfect sense, so I don't want to change thesignedness of anything. How to I write these tests so that mycode is reasonably understandable, rather than a horrible mess ofcasts and compiler warnings? One more point, of the unsignedquantity, only B is guaranteed smallenough that it could be safely cast to a signed integer. What about:#include 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 islarge 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::min() How about -(x+1) <= A-1? Executing this conditional on x beingnegative 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

 P: n/a 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(-A) || This, too, looks fishy. What if A == numeric_limits::max()?Assuming that ptrdiff_t and size_t have the same number of bits, thisvalue 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 valueto the negative side. If n == -numeric_limits::max(), you getthe wrong answer. Doe you mean A == numeric_limits::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(std::numeric_limits ::max()) + 1; std::cout << x << '\n'; std::cout << -x << '\n'; std::cout << static_cast(-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(-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(std::numeric_limits::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

 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(-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(std::numeric_limits::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

 P: n/a John Harrison wrote: > >Ok, let me think this through carefully. I just feel in my bones thatsomething is wrong with the line if (A <= MAX_A && n < static_cast(-A) ||as a means of checking whether n below [A,0). We know A is unsigned andA <= MAX_Awhere MAX_A ==1+static_cast(std::numeric_limits::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 -Aabove numeric_limits #include 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(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

 P: n/a Kai-Uwe Bux wrote: John Harrison wrote: >>>Ok, let me think this through carefully. I just feel in my bones thatsomething is wrong with the line if (A <= MAX_A && n < static_cast(-A) ||as a means of checking whether n below [A,0). We know A is unsigned andA <= MAX_Awhere MAX_A ==1+static_cast(std::numeric_limits::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 -Aabove numeric_limits #include 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(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

 P: n/a On Feb 17, 2:41 pm, John Harrison = 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

 P: n/a Greg Herlihy wrote: On Feb 17, 2:41 pm, John Harrison I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough 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

 P: n/a On 2/18/07 12:15 PM, in article er**********@murdoch.acc.Virginia.EDU, "Kai-Uwe Bux" On Feb 17, 2:41 pm, John Harrison >I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough that it could be safely cast to a signed integer. As long as the comparisons return the expected results - the valuesbeing 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

 P: n/a On 18 Feb 2007 10:29:48 -0800, "Greg Herlihy" On Feb 17, 2:41 pm, John Harrison I have a problem. I want to compare an integral value, n, against threehalf open ranges as follows[-A, 0) // range 1[0, B) // range 2[B, C} // range 3Each range corresponds to a different outcome and if the integral valueisn'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 unsignedquantities. Apart from this obscure corner of my code this makes perfectsense, 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 smallenough 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 discussion thread is closed

Replies have been disabled for this discussion. 