Hashing Function for Three Signed Integers - c++

I'm trying to use an unordered_map with three signed integers as a key (this is because I wish to use tbb's concurrent_unordered_map).
I put together this little (3x16-bit => 64-bit) function:
// to hash
int64_t result = int16_t(x);
result = int64_t(result << 16) + int16_t(y);
result = int64_t(result << 16) + int16_t(z);
// from hash
int16_t x_ = int16_t(result >> 32);
int16_t y_ = int16_t(result >> 16);
int16_t z_ = int16_t(result & 0xFFFF);
This isn't working, what mistake have I made here?
My distribution of numbers is such that negative or positive number closer to zero is more likely (typically less than +/- 2^8), but I would like to extend this to work with a range up to 2^32, rather than my 2^16 example here. Ideally, I'm looking for as very few collisions within the typical range and preferably a simple algorithm. Any suggestions?

Your problem is that you are performing bit manipulations and adding on signed numbers. If the numbers are negative, the addition operation will translate into a subtraction. It will be difficult to tease out the correct original values after that happens.
Consider:
int16_t x = -1, y = 2, z = -3;
int64_t result = x; // result: FFFFFFFFFFFFFFFF
result = (result << 16) + y; // result: FFFFFFFFFFFF0000 + 0002
result = (result << 16) + z; // result: FFFFFFFF00020000 - 0003
return result; // result: FFFFFFFF0001FFFD
Thus, while -1 and -3 has been preserved, the result of the subtraction has reduced 2 to 1.
Instead, you should limit your operations on unsigned values. With unsigned values, + and | will be equivalent in your code since you are adding into the part of the number that is being 0 filled.
int64_t hash () {
uint64_t result = uint16_t(x_);
result = (result << 16) + uint16_t(y_);
result = (result << 16) + uint16_t(z_);
return result;
}

Related

Multiply two uint64_ts and store result to uint64_t doesnt seem to work?

I am trying to multiply two uint64_ts and store the result to uint64_t. I found an existing answer on Stackoverflow which splits the inputs in to their four uint32_ts and joins the result later:
https://stackoverflow.com/a/28904636/1107474
I have created a full example using the code and pasted it below.
However, for 37 x 5 I am getting the result 0 instead of 185?
#include <iostream>
int main()
{
uint64_t a = 37; // Input 1
uint64_t b = 5; // Input 2
uint64_t a_lo = (uint32_t)a;
uint64_t a_hi = a >> 32;
uint64_t b_lo = (uint32_t)b;
uint64_t b_hi = b >> 32;
uint64_t a_x_b_hi = a_hi * b_hi;
uint64_t a_x_b_mid = a_hi * b_lo;
uint64_t b_x_a_mid = b_hi * a_lo;
uint64_t a_x_b_lo = a_lo * b_lo;
uint64_t carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
(uint64_t)(uint32_t)b_x_a_mid +
(a_x_b_lo >> 32) ) >> 32;
uint64_t multhi = a_x_b_hi +
(a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
carry_bit;
std::cout << multhi << std::endl; // Outputs 0 instead of 185?
}
I'm merging your code with another answer in the original link.
#include <iostream>
int main()
{
uint64_t a = 37; // Input 1
uint64_t b = 5; // Input 2
uint64_t a_lo = (uint32_t)a;
uint64_t a_hi = a >> 32;
uint64_t b_lo = (uint32_t)b;
uint64_t b_hi = b >> 32;
uint64_t a_x_b_hi = a_hi * b_hi;
uint64_t a_x_b_mid = a_hi * b_lo;
uint64_t b_x_a_mid = b_hi * a_lo;
uint64_t a_x_b_lo = a_lo * b_lo;
/*
This is implementing schoolbook multiplication:
x1 x0
X y1 y0
-------------
00 LOW PART
-------------
00
10 10 MIDDLE PART
+ 01
-------------
01
+ 11 11 HIGH PART
-------------
*/
// 64-bit product + two 32-bit values
uint64_t middle = a_x_b_mid + (a_x_b_lo >> 32) + uint32_t(b_x_a_mid);
// 64-bit product + two 32-bit values
uint64_t carry = a_x_b_hi + (middle >> 32) + (b_x_a_mid >> 32);
// Add LOW PART and lower half of MIDDLE PART
uint64_t result = (middle << 32) | uint32_t(a_x_b_lo);
std::cout << result << std::endl;
std::cout << carry << std::endl;
}
This results in
Program stdout
185
0
Godbolt link: https://godbolt.org/z/97xhMvY53
Or you could use __uint128_t which is non-standard but widely available.
static inline void mul64(uint64_t a, uint64_t b, uint64_t& result, uint64_t& carry) {
__uint128_t va(a);
__uint128_t vb(b);
__uint128_t vr = va * vb;
result = uint64_t(vr);
carry = uint64_t(vr >> 64);
}
In the title of this question, you said you wanted to multiply two integers. But the code you found on that other Q&A (Getting the high part of 64 bit integer multiplication) isn't trying to do that, it's only trying to get the high half of the full product. For a 64x64 => 128-bit product, the high half is product >> 64.
37 x 5 = 185
185 >> 64 = 0
It's correctly emulating multihi = (37 * (unsigned __int128)5) >> 64, and you're forgetting about the >>64 part.
__int128 is a GNU C extension; it's much more efficient than emulating it manually with pure ISO C, but only supported on 64-bit targets by current compilers. See my answer on the same question. (ISO C23 is expected to have _BitInt(128) or whatever width you specify.)
In comments you were talking about floating-point mantissas. In an FP multiply, you have two n-bit mantissas (usually with their leading bits set), so the high half of the 2n-bit product will have n significant bits (more or less; maybe actually one place to the right IIRC).
Something like 37 x 5 would only happen with tiny subnormal floats, where the product would indeed underflow to zero. But in that case, it would be because you only get subnormals at the limits of the exponent range, and (37 * 2^-1022) * (5 * 2^-1022) would be 186 * 2^-2044, an exponent way too small to be represented in an FP format like IEEE binary64 aka double where -1022 was the minimum exponent.
You're using integers where a>>63 isn't 1, in fact they're both less than 2^32 so there are no significant bits outside the low 64 bits of the full 128-bit product.

Carry bits in incidents of overflow

/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y)
{
int msbX = x>>31;
int msbY = y>>31;
int sum_xy = (y+(~x+1));
int twoPosAndNegative = (!msbX & !msbY) & sum_xy; //isLessOrEqual is FALSE.
// if = true, twoPosAndNegative = 1; Overflow true
// twoPos = Negative means y < x which means that this
int twoNegAndPositive = (msbX & msbY) & !sum_xy;//isLessOrEqual is FALSE
//We started with two negative numbers, and subtracted X, resulting in positive. Therefore, x is bigger.
int isEqual = (!x^!y); //isLessOrEqual is TRUE
return (twoPosAndNegative | twoNegAndPositive | isEqual);
}
Currently, I am trying to work through how to carry bits in this operator.
The purpose of this function is to identify whether or not int y >= int x.
This is part of a class assignment, so there are restrictions on casting and which operators I can use.
I'm trying to account for a carried bit by applying a mask of the complement of the MSB, to try and remove the most significant bit from the equation, so that they may overflow without causing an issue.
I am under the impression that, ignoring cases of overflow, the returned operator would work.
EDIT: Here is my adjusted code, still not working. But, I think this is progress? I feel like I'm chasing my own tail.
int isLessOrEqual(int x, int y)
{
int msbX = x >> 31;
int msbY = y >> 31;
int sign_xy_sum = (y + (~x + 1)) >> 31;
return ((!msbY & msbX) | (!sign_xy_sum & (!msbY | msbX)));
}
I figured it out with the assistance of one of my peers, alongside the commentators here on StackOverflow.
The solution is as seen above.
The asker has self-answered their question (a class assignment), so providing alternative solutions seems appropriate at this time. The question clearly assumes that integers are represented as two's complement numbers.
One approach is to consider how CPUs compute predicates for conditional branching by means of a compare instruction. "signed less than" as expressed in processor condition codes is SF ≠ OF. SF is the sign flag, a copy of the sign-bit, or most significant bit (MSB) of the result. OF is the overflow flag which indicates overflow in signed integer operations. This is computed as the XOR of the carry-in and the carry-out of the sign-bit or MSB. With two's complement arithmetic, a - b = a + ~b + 1, and therefore a < b = a + ~b < 0. It remains to separate computation on the sign bit (MSB) sufficiently from the lower order bits. This leads to the following code:
int isLessOrEqual (int a, int b)
{
int nb = ~b;
int ma = a & ((1U << (sizeof(a) * CHAR_BIT - 1)) - 1);
int mb = nb & ((1U << (sizeof(b) * CHAR_BIT - 1)) - 1);
// for the following, only the MSB is of interest, other bits are don't care
int cyin = ma + mb;
int ovfl = (a ^ cyin) & (a ^ b);
int sign = (a ^ nb ^ cyin);
int lteq = sign ^ ovfl;
// desired predicate is now in the MSB (sign bit) of lteq, extract it
return (int)((unsigned int)lteq >> (sizeof(lteq) * CHAR_BIT - 1));
}
The casting to unsigned int prior to the final right shift is necessary because right-shifting of signed integers with negative value is implementation-defined, per the ISO-C++ standard, section 5.8. Asker has pointed out that casts are not allowed. When right shifting signed integers, C++ compilers will generate either a logical right shift instruction, or an arithmetic right shift instruction. As we are only interested in extracting the MSB, we can isolate ourselves from the choice by shifting then masking out all other bits besides the LSB, at the cost of one additional operation:
return (lteq >> (sizeof(lteq) * CHAR_BIT - 1)) & 1;
The above solution requires a total of eleven or twelve basic operations. A significantly more efficient solution is based on the 1972 MIT HAKMEM memo, which contains the following observation:
ITEM 23 (Schroeppel): (A AND B) + (A OR B) = A + B = (A XOR B) + 2 (A AND B).
This is straightforward, as A AND B represent the carry bits, and A XOR B represent the sum bits. In a newsgroup posting to comp.arch.arithmetic on February 11, 2000, Peter L. Montgomery provided the following extension:
If XOR is available, then this can be used to average
two unsigned variables A and B when the sum might overflow:
(A+B)/2 = (A AND B) + (A XOR B)/2
In the context of this question, this allows us to compute (a + ~b) / 2 without overflow, then inspect the sign bit to see if the result is less than zero. While Montgomery only referred to unsigned integers, the extension to signed integers is straightforward by use of an arithmetic right shift, keeping in mind that right shifting is an integer division which rounds towards negative infinity, rather than towards zero as regular integer division.
int isLessOrEqual (int a, int b)
{
int nb = ~b;
// compute avg(a,~b) without overflow, rounding towards -INF; lteq(a,b) = SF
int lteq = (a & nb) + arithmetic_right_shift (a ^ nb, 1);
return (int)((unsigned int)lteq >> (sizeof(lteq) * CHAR_BIT - 1));
}
Unfortunately, C++ itself provides no portable way to code an arithmetic right shift, but we can emulate it fairly efficiently using this answer:
int arithmetic_right_shift (int a, int s)
{
unsigned int mask_msb = 1U << (sizeof(mask_msb) * CHAR_BIT - 1);
unsigned int ua = a;
ua = ua >> s;
mask_msb = mask_msb >> s;
return (int)((ua ^ mask_msb) - mask_msb);
}
When inlined, this adds just a couple of instructions to the code when the shift count is a compile-time constant. If the compiler documentation indicates that the implementation-defined handling of signed integers of negative value is accomplished via arithmetic right shift instruction, it is safe to simplify to this six-operation solution:
int isLessOrEqual (int a, int b)
{
int nb = ~b;
// compute avg(a,~b) without overflow, rounding towards -INF; lteq(a,b) = SF
int lteq = (a & nb) + ((a ^ nb) >> 1);
return (int)((unsigned int)lteq >> (sizeof(lteq) * CHAR_BIT - 1));
}
The previously made comments regarding use of a cast when converting the sign bit into a predicate apply here as well.

C++ bitwise operation reverse

I got the following operation:
uint8_t input = 10;
uint8_t output = ((0x190 - (input * 8)) & 0xFF);
// newInput should be 10 again, but is 255
uint8_t newInput = (((output * 8) + 0x190) | 0xFF);
How can I correct the operation setting newInput so that it will result back in 10?
You want to invert the transformation that got you output from input but unfortunately the logic is flawed. | is not an inverse of & and * 8 is absolutely not inverse to another * 8. Also, if you want to reverse the action of y = 0x190 - x, it's not a + but rather another x = 0x190 - y (try it on paper!) Finally, if you had all the operations all right, the order of the operations would need to be reversed in order to undo them (first in, last out).
In fact, your transformation can not be inverted, because it loses part of the information that defines input. (Mathematically speaking, it is not injective.) Consider:
uint8_t input = 10;
uint8_t output = ((0x190 - (input * 8)) & 0xFF); /* 0x40 */
uint8_t input2 = 42;
uint8_t output2 = ((0x190 - (input2 * 8)) & 0xFF); /* also 0x40! */
If you had a function that would undo the operation, what would it be expected to return for an output of 0x40, 10 or 42? This has no solution. If you want the original input you'll need to keep a copy of that variable somewhere.
Examples of operations that can be undone in unsigned 8-bit calculations are
addition and subtraction OF a constant: y = x + a ⇔ x = y - a,
subtraction FROM a constant: y = c - x ⇔ x = c - y, including plain negation (c = 0),
XOR: y = x ^ p ⇔ x = y ^ p, including ~x (that's x ^ 0xFF),
multiplication by a constant in some cases (by odd numbers), but the inverse is not obvious.
An inverse operation to a compound like y = -((x + 0x17) ^ 0x15) would look like x = ((-y) ^ 0x15) - 0x17, notice the reverse order in which the steps are undone.
On the other hand, these are not invertible:
AND,
OR,
multiplication by an even number,
bit shifts,
etc.
Sometimes you can find an inverse if that's workable for you. Here, if you are guaranteed that input is between 0 and 18 (that is 0x90 / 8), you can try
uint8_t input = 10;
uint8_t output = 0x90 - (input * 8); // spot two differences
uint8_t newInput = (0x90 - output) / 8;
But if input is larger, for example 20, it will instead give some other value that happens to produce the same output.
There are several problems why your code won't work, let me explain some of them:
You have an unsigned 8 bit integer, so you can use values between 0x00 and 0xFF. 0x190 - (10 *8) = 0x190 - 0x50 = 0x140 can be done but afterwards you cut of the leading 1 with the &FF, so you lose information that can't be restored afterwards.
The | FF is a bitwise OR, which turns every bit of your calculation to 1, so you will always get 0xFF = 255 , regardless of your output.
Your calculation is wrong.
It is dangerous to use decimal numbers (10) and hexadecimal numbers (0x190) in one calculation. It can be confusing.
I recommend to ensure that you won't overflow you variables. Use other constants so you will stay in the range of unit8_t or use another Type like int16_t which wont overflow with those little numbers.
Be aware of your bitwise operators. Like I said the last OR will always make newInput=255.
Here is an example which will work for the given parameters:
int16_t input = 10; // int16_t wont overflow
int16_t output = ((0x190 - (input * 8)) ); // without &FF there is no
// loss of information
int16_t newInput = (0x190- output) / 8; // Reshape of the line obove
Several points here:
You appear to be trying to use & 0xFF to truncate to 8-bits, you should get rid of that since the standard already guarantees this will happen for unsigned integers: https://stackoverflow.com/a/36234166/2642059
You should be doing (0x190 - output) / 8U to recover input, so even if the sizes permitted your math is wrong:
o = 400 - 8x
o - 400 = -8x
(o - 400) / -8 = x
400 in binary is 0b1'1001'0000 so since the downcast is truncating the most significant bit it may and may not be set, thus you will always have 2 potential answers (where output is positive):
const uint8_t newInputSmall = (0x190 - (output | 0b1'0000'0000)) / 8U;
cosnt uint8_t newInputLarge = (0x190 - output) / 8U;
You'll need to handle the possibility that output is negative because input * 8U is larger than 400

Dividing a 2x32 bit big integer by 1000

I have big number, time (micro seconds) stored in two 32bit variables.
I need a help, how to change micro seconds time into millisecond, so I can store result of difference in 32bit number.
More details:
I have one time in two 32bit variables. Where one variable have more significant bits and other have less significant bits. This time have microseconds resolution so I want to change it to milliseconds. So how to divide number that is stored in two variables.
If you don't have a 64-bit type, you can do it like the following:
uint32_t higher, lower; // your input
lower /= 1000;
lower += (higher % 1000) * 4294967L; // approximate 2^32 / 1000
higher /= 1000;
If the result fitted in lower itself, higher should be 0.
Just note that as #Mikhail pointed out, this solution is approximate, and has an error of 0.296 * higher + 2 ms (unless I'm missing something).
If you really want a better precision and don't care about efficiency, you can use a bit of floating-point arithmetic in the middle, and round the results correctly. I doubt if it's worth the effort:
uint32_t higher, lower; // your input
// simpler without a helper variable
if (lower % 1000 >= 500)
{
lower /= 1000;
++lower;
}
else
lower /= 1000;
lower += round((higher % 1000) * 4294967.296); // 2^32 / 1000
higher /= 1000;
You'll need to include <cmath> for round().
As a note, #Mikhail's solution in this case is probably better and may be faster. Though it's too complex for me.
If you have a 64-bit type, you can convert the split value to it:
uint64_t whole_number = higher;
whole_number <<= 32;
whole_number |= lower;
And then you can use whole_number as usual.
Note that if you only need a difference, it will be faster to subtract the values before actually dividing.
Assuming that you know which value is bigger:
uint32_t higher1, lower1; // smaller value
uint32_t higher2, lower2; // bigger value
uint32_t del_high = higher2 - higher1;
uint32_t del_low = lower2 - lower1;
if (lower2 < lower1)
--del_high;
And now you can convert the result like explained before. Or with a bit luck, del_high will be 0 (if the difference is smaller than 2^32 μs), and you will have the result in del_low (in μs).
The simplest way is to use 64-bit integer type, but I assume you cannot do this. Since you want your answer in 32-bit integer, the high-order value of microseconds cannot be greater than 999, or it would not fit in 32-bit after division by 1000. So the bigger number of microseconds you're operating with is 999 * 2^32 + (2^32 - 1) = 4294967295999. It gives you 13 decimal digits and you can use double to handle precise division.
If you are forced for some reason to use only 32-bit integers, the answer of Michał Górny gives you an approximate solution. E.g. for whole_number = 1234567890123 it will give a result of 1234567805. Because dividing of max 32-bit int on 1000 have a reminder.
The only way to have an exact answer with 32-bit integer is by using long arithmetic. It requires long digits to be stored in a type which can be extended to store a reminder. You have to split your two 32-bit integers in four 16-bit digits. After that you can divide it as on paper and you have enough bits to store a reminder. See the code of micro2milli:
#include <iostream>
typedef unsigned __int32 uint32;
typedef unsigned __int64 uint64;
const uint32 MAX_INT = 0xFFFFFFFF;
uint32 micro2milli(uint32 hi, uint32 lo)
{
if (hi >= 1000)
{
throw std::runtime_error("Cannot store milliseconds in uint32!");
}
uint32 r = (lo >> 16) + (hi << 16);
uint32 ans = r / 1000;
r = ((r % 1000) << 16) + (lo & 0xFFFF);
ans = (ans << 16) + r / 1000;
return ans;
}
uint32 micro2milli_simple(uint32 hi, uint32 lo)
{
lo /= 1000;
return lo + (hi % 1000) * 4294967L;
}
void main()
{
uint64 micro = 1234567890123;
uint32 micro_high = micro >> 32;
uint32 micro_low = micro & MAX_INT;
// 1234567805
std::cout << micro2milli_simple(micro_high, micro_low) << std::endl;
// 1234567890
std::cout << micro2milli(micro_high, micro_low) << std::endl;
}
First, put your two variables into 3 with 22 significant bits each.
uint32_t x0 = l & 0x3FFFFF;
uint32_t x1 = ((l >> 22) | (h << 10)) & 0x3FFFFF;
uint32_t x2 = h >> 12;
Now do the division (there is 10 available bits per x?, and 1000 < 2^10 = 1024 so there is no overflow possible)
uint32_t t2 = x2 / 1000;
x1 |= (x2 % 1000) << 22;
uint32_t t1 = x1 / 1000;
x0 |= (x1 % 1000) << 22;
uint32_t t0 = (x0 + 500) / 1000;
/* +0 for round down, +500 for round to nearest, +999 for round up */
Now put back things together.
uint32_t r0 = t0 + t1 << 22;
uint32_t r1 = (t1 >> 10) + (t2 << 12) + (r0 < t0);
Using the same technique but with four variables holding 16 bits, you can do it for divisor up to 65535. Then it becomes harder to do it with 32 bits arithmetic.
Assuming you can not use a 64 bit int for this, I would suggest using a multiple precision library, like GMP.

Checking whether a number is positive or negative using bitwise operators

I can check whether a number is odd/even using bitwise operators. Can I check whether a number is positive/zero/negative without using any conditional statements/operators like if/ternary etc.
Can the same be done using bitwise operators and some trick in C or in C++?
Can I check whether a number is positive/zero/negative without using any conditional statements/operators like if/ternary etc.
Of course:
bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
If the high bit is set on a signed integer (byte, long, etc., but not a floating point number), that number is negative.
int x = -2300; // assuming a 32-bit int
if ((x & 0x80000000) != 0)
{
// number is negative
}
ADDED:
You said that you don't want to use any conditionals. I suppose you could do this:
int isNegative = (x & 0x80000000);
And at some later time you can test it with if (isNegative).
Or, you could use signbit() and the work's done for you.
I'm assuming that under the hood, the math.h implementation is an efficient bitwise check (possibly solving your original goal).
Reference: http://en.cppreference.com/w/cpp/numeric/math/signbit
There is a detailed discussion on the Bit Twiddling Hacks page.
int v; // we want to find the sign of v
int sign; // the result goes here
// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0); // if v < 0 then -1, else 0.
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1);
// The last expression above evaluates to sign = v >> 31 for 32-bit integers.
// This is one operation faster than the obvious way, sign = -(v < 0). This
// trick works because when signed integers are shifted right, the value of the
// far left bit is copied to the other bits. The far left bit is 1 when the value
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior
// is architecture-specific.
// Alternatively, if you prefer the result be either -1 or +1, then use:
sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then -1, else +1
// On the other hand, if you prefer the result be either -1, 0, or +1, then use:
sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1)); // -1, 0, or +1
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0); // -1, 0, or +1
// If instead you want to know if something is non-negative, resulting in +1
// or else 0, then use:
sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1
// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C
// specification leaves the result of signed right-shift implementation-defined,
// so on some systems this hack might not work. For greater portability, Toby
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and
// throughout rather than assuming bytes were 8 bits long. Angus recommended
// the more portable versions above, involving casting on March 4, 2006.
// Rohit Garg suggested the version for non-negative integers on September 12, 2009.
#include<stdio.h>
void main()
{
int n; // assuming int to be 32 bit long
//shift it right 31 times so that MSB comes to LSB's position
//and then and it with 0x1
if ((n>>31) & 0x1 == 1) {
printf("negative number\n");
} else {
printf("positive number\n");
}
getch();
}
Signed integers and floating points normally use the most significant bit for storing the sign so if you know the size you could extract the info from the most significant bit.
There is generally little benefit in doing this this since some sort of comparison will need to be made to use this information and it is just as easy for a processor to tests whether something is negative as it is to test whether it is not zero. If fact on ARM processors, checking the most significant bit will be normally MORE expensive than checking whether it is negative up front.
It is quite simple
It can be easily done by
return ((!!x) | (x >> 31));
it returns
1 for a positive number,
-1 for a negative, and
0 for zero
This can not be done in a portable way with bit operations in C. The representations for signed integer types that the standard allows can be much weirder than you might suspect. In particular the value with sign bit on and otherwise zero need not be a permissible value for the signed type nor the unsigned type, but a so-called trap representation for both types.
All computations with bit operators that you can thus do might have a result that leads to undefined behavior.
In any case as some of the other answers suggest, this is not really necessary and comparison with < or > should suffice in any practical context, is more efficient, easier to read... so just do it that way.
// if (x < 0) return -1
// else if (x == 0) return 0
// else return 1
int sign(int x) {
// x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1
int x_is_not_zero = (( x | (~x + 1)) >> 31) & 0x1;
return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand
}
Here's exactly what you waht!
Here is an update related to C++11 for this old question. It is also worth considering std::signbit.
On Compiler Explorer using gcc 7.3 64bit with -O3 optimization, this code
bool s1(double d)
{
return d < 0.0;
}
generates
s1(double):
pxor xmm1, xmm1
ucomisd xmm1, xmm0
seta al
ret
And this code
bool s2(double d)
{
return std::signbit(d);
}
generates
s2(double):
movmskpd eax, xmm0
and eax, 1
ret
You would need to profile to ensure that there is any speed difference, but the signbit version does use 1 less opcode.
When you're sure about the size of an integer (assuming 16-bit int):
bool is_negative = (unsigned) signed_int_value >> 15;
When you are unsure of the size of integers:
bool is_negative = (unsigned) signed_int_value >> (sizeof(int)*8)-1; //where 8 is bits
The unsigned keyword is optional.
if( (num>>sizeof(int)*8 - 1) == 0 )
// number is positive
else
// number is negative
If value is 0 then number is positive else negative
A simpler way to find out if a number is positive or negative:
Let the number be x
check if [x * (-1)] > x. if true x is negative else positive.
You can differentiate between negative/non-negative by looking at the most significant bit.
In all representations for signed integers, that bit will be set to 1 if the number is negative.
There is no test to differentiate between zero and positive, except for a direct test against 0.
To test for negative, you could use
#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))
Suppose your number is a=10 (positive). If you shift a a times it will give zero.
i.e:
10>>10 == 0
So you can check if the number is positive, but in case a=-10 (negative):
-10>>-10 == -1
So you can combine those in an if:
if(!(a>>a))
print number is positive
else
print no. is negative
#include<stdio.h>
int checksign(int n)
{
return (n >= 0 && (n & (1<<32-1)) >=0);
}
void main()
{
int num = 11;
if(checksign(num))
{
printf("Unsigned number");
}
else
{
printf("signed Number");
}
}
Without if:
string pole[2] = {"+", "-"};
long long x;
while (true){
cin >> x;
cout << pole[x/-((x*(-1))-1)] << "\n\n";
}
(not working for 0)
if(n & (1<<31))
{
printf("Negative number");
}
else{
printf("positive number");
}
It check the first bit which is most significant bit of the n number and then & operation is work on it if the value is 1 which is true then the number is negative and it not then it is positive number