Shortest way to calculate difference between two numbers? - c++

I'm about to do this in C++ but I have had to do it in several languages, it's a fairly common and simple problem, and this is the last time. I've had enough of coding it as I do, I'm sure there must be a better method, so I'm posting here before I write out the same long winded method in yet another language;
Consider the (lilies!) following code;
// I want the difference between these two values as a positive integer
int x = 7
int y = 3
int diff;
// This means you have to find the largest number first
// before making the subtract, to keep the answer positive
if (x>y) {
diff = (x-y);
} else if (y>x) {
diff = (y-x);
} else if (x==y) {
diff = 0;
}
This may sound petty but that seems like a lot to me, just to get the difference between two numbers. Is this in fact a completely reasonable way of doing things and I'm being unnecessarily pedantic, or is my spidey sense tingling with good reason?

Just get the absolute value of the difference:
#include <cstdlib>
int diff = std::abs(x-y);

Using the std::abs() function is one clear way to do this, as others here have suggested.
But perhaps you are interested in succinctly writing this function without library calls.
In that case
diff = x > y ? x - y : y - x;
is a short way.
In your comments, you suggested that you are interested in speed. In that case, you may be interested in ways of performing this operation that do not require branching. This link describes some.

#include <cstdlib>
int main()
{
int x = 7;
int y = 3;
int diff = std::abs(x-y);
}

All the existing answers will overflow on extreme inputs, giving undefined behaviour. #craq pointed this out in a comment.
If you know that your values will fall within a narrow range, it may be fine to do as the other answers suggest, but to handle extreme inputs (i.e. to robustly handle any possible input values), you cannot simply subtract the values then apply the std::abs function. As craq rightly pointed out, the subtraction may overflow, causing undefined behaviour (consider INT_MIN - 1), and the std::abs call may also cause undefined behaviour (consider std::abs(INT_MIN)). It's no better to determine the min and max of the pair and to then perform the subtraction.
More generally, a signed int is unable to represent the maximum difference between two signed int values. The unsigned int type should be used for the output value.
I see 3 solutions. I've used the explicitly-sized integer types from stdint.h here, to close the door on uncertainties like whether long and int are the same size and range.
Solution 1. The low-level way.
// I'm unsure if it matters whether our target platform uses 2's complement,
// due to the way signed-to-unsigned conversions are defined in C and C++:
// > the value is converted by repeatedly adding or subtracting
// > one more than the maximum value that can be represented
// > in the new type until the value is in the range of the new type
uint32_t difference_int32(int32_t i, int32_t j) {
static_assert(
(-(int64_t)INT32_MIN) == (int64_t)INT32_MAX + 1,
"Unexpected numerical limits. This code assumes two's complement."
);
// Map the signed values across to the number-line of uint32_t.
// Preserves the greater-than relation, such that an input of INT32_MIN
// is mapped to 0, and an input of 0 is mapped to near the middle
// of the uint32_t number-line.
// Leverages the wrap-around behaviour of unsigned integer types.
// It would be more intuitive to set the offset to (uint32_t)(-1 * INT32_MIN)
// but that multiplication overflows the signed integer type,
// causing undefined behaviour. We get the right effect subtracting from zero.
const uint32_t offset = (uint32_t)0 - (uint32_t)(INT32_MIN);
const uint32_t i_u = (uint32_t)i + offset;
const uint32_t j_u = (uint32_t)j + offset;
const uint32_t ret = (i_u > j_u) ? (i_u - j_u) : (j_u - i_u);
return ret;
}
I tried a variation on this using bit-twiddling cleverness taken from https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax but modern code-generators seem to generate worse code with this variation. (I've removed the static_assert and the comments.)
uint32_t difference_int32(int32_t i, int32_t j) {
const uint32_t offset = (uint32_t)0 - (uint32_t)(INT32_MIN);
const uint32_t i_u = (uint32_t)i + offset;
const uint32_t j_u = (uint32_t)j + offset;
// Surprisingly it helps code-gen in MSVC 2019 to manually factor-out
// the common subexpression. (Even with optimisation /O2)
const uint32_t t = (i_u ^ j_u) & -(i_u < j_u);
const uint32_t min = j_u ^ t; // min(i_u, j_u)
const uint32_t max = i_u ^ t; // max(i_u, j_u)
const uint32_t ret = max - min;
return ret;
}
Solution 2. The easy way. Avoid overflow by doing the work using a wider signed integer type. This approach can't be used if the input signed integer type is the largest signed integer type available.
uint32_t difference_int32(int32_t i, int32_t j) {
return (uint32_t)std::abs((int64_t)i - (int64_t)j);
}
Solution 3. The laborious way. Use flow-control to work through the different cases. Likely to be less efficient.
uint32_t difference_int32(int32_t i, int32_t j)
{ // This static assert should pass even on 1's complement.
// It's just about impossible that int32_t could ever be capable of representing
// *more* values than can uint32_t.
// Recall that in 2's complement it's the same number, but in 1's complement,
// uint32_t can represent one more value than can int32_t.
static_assert( // Must use int64_t to subtract negative number from INT32_MAX
((int64_t)INT32_MAX - (int64_t)INT32_MIN) <= (int64_t)UINT32_MAX,
"Unexpected numerical limits. Unable to represent greatest possible difference."
);
uint32_t ret;
if (i == j) {
ret = 0;
} else {
if (j > i) { // Swap them so that i > j
const int32_t i_orig = i;
i = j;
j = i_orig;
} // We may now safely assume i > j
uint32_t magnitude_of_greater; // The magnitude, i.e. abs()
bool greater_is_negative; // Zero is of course non-negative
uint32_t magnitude_of_lesser;
bool lesser_is_negative;
if (i >= 0) {
magnitude_of_greater = i;
greater_is_negative = false;
} else { // Here we know 'lesser' is also negative, but we'll keep it simple
// magnitude_of_greater = -i; // DANGEROUS, overflows if i == INT32_MIN.
magnitude_of_greater = (uint32_t)0 - (uint32_t)i;
greater_is_negative = true;
}
if (j >= 0) {
magnitude_of_lesser = j;
lesser_is_negative = false;
} else {
// magnitude_of_lesser = -j; // DANGEROUS, overflows if i == INT32_MIN.
magnitude_of_lesser = (uint32_t)0 - (uint32_t)j;
lesser_is_negative = true;
}
// Finally compute the difference between lesser and greater
if (!greater_is_negative && !lesser_is_negative) {
ret = magnitude_of_greater - magnitude_of_lesser;
} else if (greater_is_negative && lesser_is_negative) {
ret = magnitude_of_lesser - magnitude_of_greater;
} else { // One negative, one non-negative. Difference is sum of the magnitudes.
// This will never overflow.
ret = magnitude_of_lesser + magnitude_of_greater;
}
}
return ret;
}

Well it depends on what you mean by shortest. The fastet runtime, the fastest compilation, the least amount of lines, the least amount of memory. I'll assume you mean runtime.
#include <algorithm> // std::max/min
int diff = std::max(x,y)-std::min(x,y);
This does two comparisons and one operation (this one is unavoidable but could be optimized through certain bitwise operations with specific cases, compiler might actually do this for you though). Also if the compiler is smart enough it could do only one comparison and save the result for the other comparison. E.g if X>Y then you know from the first comparison that Y < X but I'm not sure if compilers take advantage of this.

Related

How to safely compare two unsigned integer counters?

We have two unsigned counters, and we need to compare them to check for some error conditions:
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a/2 > b) {
perror("Error happened!");
return -1;
}
The problem is that a and b will overflow some day. If a overflowed, it's still OK. But if b overflowed, it would be a false alarm. How to make this check bulletproof?
I know making a and b uint64_t would delay this false-alarm. but it still could not completely fix this issue.
===============
Let me clarify a little bit: the counters are used to tracking memory allocations, and this problem is found in dmalloc/chunk.c:
#if LOG_PNT_SEEN_COUNT
/*
* We divide by 2 here because realloc which returns the same
* pointer will seen_c += 2. However, it will never be more than
* twice the iteration value. We divide by two to not overflow
* iter_c * 2.
*/
if (slot_p->sa_seen_c / 2 > _dmalloc_iter_c) {
dmalloc_errno = ERROR_SLOT_CORRUPT;
return 0;
}
#endif
I think you misinterpreted the comment in the code:
We divide by two to not overflow iter_c * 2.
No matter where the values are coming from, it is safe to write a/2 but it is not safe to write a*2. Whatever unsigned type you are using, you can always divide a number by two while multiplying may result in overflow.
If the condition would be written like this:
if (slot_p->sa_seen_c > _dmalloc_iter_c * 2) {
then roughly half of the input would cause a wrong condition. That being said, if you worry about counters overflowing, you could wrap them in a class:
class check {
unsigned a = 0;
unsigned b = 0;
bool odd = true;
void normalize() {
auto m = std::min(a,b);
a -= m;
b -= m;
}
public:
void incr_a(){
if (odd) ++a;
odd = !odd;
normalize();
}
void incr_b(){
++b;
normalize();
}
bool check() const { return a > b;}
}
Note that to avoid the overflow completely you have to take additional measures, but if a and b are increased more or less the same amount this might be fine already.
The posted code actually doesn’t seem to use counters that may wrap around.
What the comment in the code is saying is that it is safer to compare a/2 > b instead of a > 2*b because the latter could potentially overflow while the former cannot. This particularly true of the type of a is larger than the type of b.
Note overflows as they occur.
uint32_t a, b;
bool aof = false;
bool bof = false;
if (condition_to_increase_a()) {
a++;
aof = a == 0;
}
if (condition_to_increase_b()) {
b++;
bof = b == 0;
}
if (!bof && a/2 + aof*0x80000000 > b) {
perror("Error happened!");
return -1;
}
Each a, b interdependently have 232 + 1 different states reflecting value and conditional increment. Somehow, more than an uint32_t of information is needed. Could use uint64_t, variant code paths or an auxiliary variable like the bool here.
Normalize the values as soon as they wrap by forcing them both to wrap at the same time. Maintain the difference between the two when they wrap.
Try something like this;
uint32_t a, b;
// a increased in some conditions
// b increased in some conditions
if (a or b is at the maximum value) {
if (a > b)
{
a = a-b; b = 0;
}
else
{
b = b-a; a = 0;
}
}
if (a/2 > b) {
perror("Error happened!");
return -1;
}
If even using 64 bits is not enough, then you need to code your own "var increase" method, instead of overload the ++ operator (which may mess your code if you are not careful).
The method would just reset var to '0' or other some meaningfull value.
If your intention is to ensure that action x happens no more than twice as often as action y, I would suggest doing something like:
uint32_t x_count = 0;
uint32_t scaled_y_count = 0;
void action_x(void)
{
if ((uint32_t)(scaled_y_count - x_count) > 0xFFFF0000u)
fault();
x_count++;
}
void action_y(void)
{
if ((uint32_t)(scaled_y_count - x_count) < 0xFFFF0000u)
scaled_y_count+=2;
}
In many cases, it may be desirable to reduce the constants in the comparison used when incrementing scaled_y_count so as to limit how many action_y operations can be "stored up". The above, however, should work precisely in cases where the operations remain anywhere close to balanced in a 2:1 ratio, even if the number of operations exceeds the range of uint32_t.

Cheking a pattern of bits in a sequence

So basically i need to check if a certain sequence of bits occurs in other sequence of bits(32bits).
The function shoud take 3 arguments:
n right most bits of a value.
a value
the sequence where the n bits should be checked for occurance
The function has to return the number of bit where the desired sequence started. Example chek if last 3 bits of 0x5 occur in 0xe1f4.
void bitcheck(unsigned int source, int operand,int n)
{
int i,lastbits,mask;
mask=(1<<n)-1;
lastbits=operand&mask;
for(i=0; i<32; i++)
{
if((source&(lastbits<<i))==(lastbits<<i))
printf("It start at bit number %i\n",i+n);
}
}
Your loop goes too far, I'm afraid. It could, for example 'find' the bit pattern '0001' in a value ~0, which consists of ones only.
This will do better (I hope):
void checkbit(unsigned value, unsigned pattern, unsigned n)
{
unsigned size = 8 * sizeof value;
if( 0 < n && n <= size)
{
unsigned mask = ~0U >> (size - n);
pattern &= mask;
for(int i = 0; i <= size - n; i ++, value >>= 1)
if((value & mask) == pattern)
printf("pattern found at bit position %u\n", i+n);
}
}
I take you to mean that you want to take source as a bit array, and to search it for a bit sequence specified by the n lowest-order bits of operand. It seems you would want to perform a standard mask & compare; the only (minor) complication being that you need to scan. You seem already to have that idea.
I'd write it like this:
void bitcheck(uint32_t source, uint32_t operand, unsigned int n) {
uint32_t mask = ~((~0) << n);
uint32_t needle = operand & mask;
int i;
for(i = 0; i <= (32 - n); i += 1) {
if (((source >> i) & mask) == needle) {
/* found it */
break;
}
}
}
There are some differences in the details between mine and yours, but the main functional difference is the loop bound: you must be careful to ignore cases where some of the bits you compare against the target were introduced by a shift operation, as opposed to originating in source, lest you get false positives. The way I've written the comparison makes it clearer (to me) what the bound should be.
I also use the explicit-width integer data types from stdint.h for all values where the code depends on a specific width. This is an excellent habit to acquire if you want to write code that ports cleanly.
Perhaps:
if((source&(maskbits<<i))==(lastbits<<i))
Because:
finding 10 in 11 will be true for your old code. In fact, your original condition will always return true when 'source' is made of all ones.

Using rand() to get a number but that number can't be the number that was last generated

I want to use std::rand() to generate a number between 0 and amountOfNumbers, but the generated number can't be the same number that was last generated.
I wrote this function:
void reroll() {
int newRand;
while (true) {
newRand = std::rand() % (amountOfNumbers);
if (newRand == lastNumber) {
continue;
}
lastNumber = newRand;
break;
}
// do something with newRand
// ...
}
amountOfNumbers is just an int (> 1) that defines the upper bound (e.g. 5 so the possible number range is 0 to 4). lastNumber which is initially -1 stores the last generated number.
I was wondering if there's a better way to write this.
The function seems to be working so far, but I'm not sure if my code is flawless... it looks kind of bad. That while (true) makes me feel a bit uneasy.
The code works but I'd structure it like this
int reroll(int n, int last) {
while(true) {
int v = std::rand() % n;
if(v!=last)
return v;
}
}
void reroll() {
...
int v = reroll(n, last);
...
}
Also you can avoid the need for the while loop altogether by generating values in a smaller range (1 less) and adjusting around last.
int reroll(int n, int last) {
if(last==-1)
return std::rand() % n;
int v = std::rand() % (n-1);
if (v<last) return v
return v+1;
}
I have a few suggestions.
Since you never declare lastNumber and amountOfNumbers, I am going to assume they are global. It would be better to pass these as variables to the function instead. Also, you should return the new number from the function instead of setting it as void.
The following code below will calculate a new roll. Instead of rerolling until there is a new roll, we will just take the random of the set of numbers, but one less. If the number is greater than or equal, we will add the one back in, thus avoiding the lastNumber. The function then returns the newRand. Doing it this way will avoid the (albeit low) risk of an infinite loop, and it will always run in constant time.
int reroll(int lastNumber, int amountOfNumbers)
{
int newRand;
newRand = std::rand() % (amountOfNumbers - 1);
if (newRand >= lastNumber) {
newRand++;
}
return newRand;
}
The while true loop is definitely not good practise, I'd suggest doing something like this. But you should make it in the same structure as Michael's answer above like this:
void reroll(int lastNumber, int amountOfNumbers) {
int newRand = std::rand() % (amountOfNumbers);
while (newRand == lastNumber) {
newRand = std::rand() % (amountOfNumbers);
}
lastNumber = newRand;
return newRand;
}
Depending on your value for amountOfNumbers, the modulus operation you've used might not guarantee an even distribution (which is a small part of your problem).
For a start, if amountOfNumbers is greater than RAND_MAX there will be numbers you'll never see using this.
Next, consider if you're using this to generate values between 0 and 6 ([0,1,2,3,4,5]) for a dice, and RAND_MAX is 7. You'll see the values 0 and 1 twice as often as the rest! In reality, RAND_MAX must be at least 32767 (whatever that means, which according to the standard isn't really much)... but that isn't evenly divisible by 6, either, so of course there will be some values that have a slight bias.
You can use modulus to reduce that range, but you'll probably want to discard the bias in the second problem. Unfortunately, due to the common implementation of rand, extending the range beyond max will introduce further bias.
unsigned int rand_range(unsigned int max) {
double v = max > RAND_MAX ? max : RAND_MAX;
v /= RAND_MAX;
int n;
do {
n = rand();
} while (RAND_MAX - n <= RAND_MAX % (unsigned int)(max / v));
return (unsigned int)(v * n) % max;
}
This still doesn't guarantee that there won't be any repeating values, but at least any bias causing repeating values will have been reduced significantly. We can use a similar approach to the (currently) accepted answer to remove any repeated values, with minimal bias, now:
unsigned int non_repetitive_rand_range(unsigned int max) {
if (max <= 1) {
return 0; // Can't avoid repetitive values here!
}
static unsigned int previous;
unsigned int current;
do {
current = rand_range(max);
} while (current != previous);
previous = current;
return current;
}
On a technical note, this doesn't necessarily guarantee a problem to the solution either. This quote from the standard explains why:
There are no guarantees as to the quality of the random sequence produced and some implementations are known to produce sequences with distressingly non-random low-order bits. Applications with particular requirements should use a generator that is known to be sufficient for their needs.
As a result, it is possible that some silly, obscure implementation might implement rand like so:
int rand(void) {
return 0;
}
For such an implementation, there's no avoiding it: This implementation of rand would cause the code in this answer (and all the other current answers) to go into an infinite loop. Your only hope would be to re-implement rand and srand. Here's an example implementation given within the standard, should you ever have to do that:
static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void srand(unsigned int seed)
{
next = seed;
}
You'll probably want to rename them to my_rand and my_srand respectively, and use #define rand my_rand and #define srand my_srand or use a find/replace operation.

How to put integer bits in a float?

I have vertices coming in as float_3's. I want to add an integer to them and then ship them out as float_4's. I don't want to convert the integer into a float with the same value, I need the bits to be exactly the same (the integer is a bucket xyz value bit shifted together).
Here is what I tried:
void tagVerts (vector<float_3> &Verts, vector<float_4> &Output) {
int len = Verts.size();
for (int i = 0; i < len; i++) {
Output[i].xyz = Verts[i];
Output[i].w = reinterpret_cast<float>(XYZTag(Verts[i]));
}
}
it says invalid type conversion :/
EDIT:
float_3 and float_4 are from amp.h, as far as I can tell they are just 3 or 4 floats in a struct with a bunch of conversion and assignment helper functions.
XYZTag is as follows:
int XYZTag(float_3 pos) {
pos = pos * mul + add;
int_3 posi (static_cast<int>(pos.x), static_cast<int>(pos.y), static_cast<int>(pos.z));
return((posi.x << 10) + posi.y << 10) + posi.z;
}
You must not interpret the bits of an int as a float as doing so would violate strict aliasing rules and therefore invoke undefined behavior. The correct way to do this is to copy the bits over using memcpy.
#include <cstring>
inline float
int_bits_to_float(const int bits)
{
static_assert(sizeof(int) >= sizeof(float), "too few bits");
float target;
std::memcpy(&target, &bits, sizeof(float));
return target;
}
As terrible a solution as it might seem to be at a first glance, we should really expect the compiler to figure out that this can be optimized down to a few move instructions. GCC does this even at default optimization level.
You cannot reinterpret_cast<> the int directly. The static_cast<> will not do what you want.
To copy the bit pattern to another type, you need something like:
int val = 23;
float bitCopy = *reinterpret_cast<float*>(&val);
Now, for this to work at all, you better have sizeof(float) and sizeof(int) the same.
Further, we'll have to assume you know what you are doing to want this at all.
reinterpret_cast will not reinterpret an int as a float, but it can reinterpret a pointer.
int temp = XYZTag(Verts[i]);
Output[i].w = *reinterpret_cast<float*>(&temp);
// ^ ^ ^
This will stuff the exact bits of your int into the float Output[i].w. It will be your responsibility to ensure that those types are the same size.

How to safely convert unsigned value to signed?

As I read, in signed arithmetic there are many cases of undefined behaviour. Thus, I prefer to calculate results (even signed ones) using unsigned arithmetic, which is specified without undefined cases.
However, when the result is obtained using unsigned arithmetic, the last step, the conversion to the signed value remains to be done.
Here is a code I wrote and my question is if the code works in accordance with the rules, i.e., whether it is safe, not relying on some undefined/unspecified behaviour?
/*
function to safely convert given unsigned value
to signed result having the required sign
sign == 1 means the result shall be negative,
sign == 0 means the result shall be nonnegative
returns 1 on success, 0 on failure
*/
int safe_convert(unsigned value, int sign, int *result) {
if (sign) {
if (value > -(unsigned)INT_MIN) return 0; // value too big
if (!value) return 0; // cannot convert zero to negative int
*result = INT_MIN + (int)((-(unsigned)INT_MIN) - value);
} else {
if (value > (unsigned)INT_MAX) return 0; //value too big
*result = (int)value;
}
return 1;
}
Eventually, is there a way that is simpler, not relying on undefined/unspecified behaviour and doing the same thing?
Eventually, is there a way that is simpler, not relying on undefined behaviour and doing the same thing?
short x = (short) value;
int y = (int) value;
But be sure on what integral type you are casting to. value may go out of the range of the signed type used.
The only value that could be problematic is INT_MIN. Therefore I would just do something like
int safe_convert(unsigned value, int sign, int *result) {
if (sign) {
if (value > -(unsigned)INT_MIN) return 0; // value too big
if (-(unsigned)INT_MIN > (unsigned)INT_MAX // compile constant
&&
value == -(unsigned)INT_MIN) // special case
*result = INT_MIN;
else *result = -(int)value;
} else {
if (value > (unsigned)INT_MAX) return 0; //value too big
*result = (int)value;
}
return 1;
}
I don't think that the case of asking for a negative zero justifies an error return.
Conversion from unsigned to signed is not undefined, but implementation defined. From C++ Standard, chapter 4.7 Integral conversions, paragraph 3:
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and
bit-field width); otherwise, the value is implementation-defined
Therefore the following is implementation defined and on many platforms exactly what you may expect (wrap around):
unsigned u = -1;
int i = (int)u;
The condition when sign is false (a positive number) is all ready well handled, it is when sign is true (a negative number) is tricky. So rather than:
if (value > -(unsigned)INT_MIN) return 0; // value too big
*result = INT_MIN + (int)((-(unsigned)INT_MIN) - value);
suggest
// 1st half is for 2's compliment machines
// 2nd half is for symmetric ints like 1's compliment and signed ints
// Optimization will simplify the real code to 1 compare
if ((((INT_MIN + 1) == -INT_MAX) && (value > ((unsigned)INT_MAX + 1u))) ||
(( INT_MIN == -INT_MAX) && (value > (unsigned)INT_MAX ))) return 0;
int i = (int) value;
*result = -i;
The INT_MIN == -INT_MAX tests could be used to conditionally allow a signed zero.