Explanation of the usage of std::max in that code? - c++

I am unsure whether or not I better should have posted this question on codereview.stackexchange.com. Anyway, here we go ...
Please consider the following code snippet which is a literal (I have only changed the formatting) excerpt from here and has been printed (in stripped-down form) in the German computer magazine c't, issue 23/2019:
while (lo <= hi) {
std::streamoff pos = std::streamoff((uint64_t(lo) + uint64_t(hi)) / 2);
pos -= pos % std::streamoff(PasswordHashAndCount::size);
pos = std::max<int64_t>(0, pos);
phc.read(mInputFile, pos);
++nReads;
if (hash > phc.hash) {
lo = pos + std::streamoff(PasswordHashAndCount::size);
}
else if (hash < phc.hash) {
hi = pos - std::streamoff(PasswordHashAndCount::size);
}
else {
safe_assign(readCount, nReads);
return phc;
}
}
Why do we need the fourth line pos = std::max<int64_t>(0, pos);?
From the second line, we see that pos is equal or greater to 0, because it is the half of the sum of two numbers which themselves are of type uint64_t.
The third line can't make pos lower than 0. Proof:
For simplicity, replace pos by A and std::streamoff(PasswordHashAndCount::size) by B. Then the third line reads A -= A % B which is equivalent to A = A - (A % B), where A and B are integers, A being equal to or greater than 0, and B being greater than 0 (because ::size is always greater than 0).
First, if A < B, A % B = A. In this case, the third line becomes A = A - A, that is, A = 0.
Secondly, if A == B, A % B becomes A % A which is 0. Therefore, the third line becomes A = A - 0, which is equivalent to a null operation. In other words, A does not change in that case; notably, it remains 0 or greater than that.
Third, if A > B, A - (A % B) is greater than 0. This is because A % B is smaller than B, and thus, A - (A % B) is greater than A - B. The latter in turn is greater than 0, because the condition here was A > B.
Of course, the three cases A > B, A < B and A == B are all cases which can occur. In every case, the third line assigns a new value to A which is 0 or positive.
Coming back to the original variable naming, that means that pos is always 0 or greater than that after execution of the third line.
Given that, I don't understand what the fourth line does. After all, max(0, pos) is always equivalent to pos if pos is 0 or positive.
What am I missing? Is there an error in the reasoning above?

Let's consider what exactly it does:
std::streamoff pos = std::streamoff((uint64_t(lo) + uint64_t(hi)) / 2);
pos = std::max<int64_t>(0, pos);
std::streamoff is some implementation defined signed integer type. Let's consider a case where it is a 64 bit type or smaller: The value of pos will not be changed by the conversion to int64_t because the type is wider, nor when converting back in the assignment because the original value must have been representable.
Let's consider a case where std::streamoff is a 128 bit type or wider: The value comes from (uint64_t(lo) + uint64_t(hi)) / 2 which cannot exceed maximum of int64_t. Thus, the value cannot be changed by the conversion in this case either.
Thus, the use of int64_t has no effect in any case.
The third line can't make pow lower than 0
Is there an error in the reasoning above?
I cannot find any error.
Given that, I don't understand what the fourth line does.
The line has no effect at on the behaviour of the program at all. The program would have equivalent behaviour if the line was written:
;
Besides, on most systems that you find on desktop or server, std::streamoff and int64_t have the same number of bits.

Related

Music Chairs problem implementation in C++

I am currently practicing algorithms and DS. I have stumbled upon a question that I can't figure out how to solve. So the question's link is there:
In summary, it says that there is a number of chairs in a circle, and the position of the person (relative to a certain chair), and how many M movements he should make.
So the input is as following:
3 integer numbers N, M, X , The number of chairs, the number of times the boy should move and the first chair he will start from respectively ( 1  ≤  X  ≤  N < 2^63 , 0  ≤  M < 2^63 )
So, what have I done so far? I thought about the following:
So I thought that the relative position after M movements is (x+m) % n, and since this can cause Integer overflow, I have done it like that, ((x%n) + (m%n)) % n. I have figured out that if the person has reached the last index of chair, it will be 0 so I handled that. However, it passes only 2 tests. I don't need any code to be written, I want to directed in the right way of thinking. Here is my code so far:
#include <iostream>
using namespace std;
int main() {
long long n, m, x;
cin >> n >> m >> x;
// After each move, he reaches (X+1).
// X, N chairs.
// ((X % N) + (M % N)) % N;
// Odd conideration.
if ( m % 2 == 1) {
m += 1;
}
long long position = (x % n + m % n) % n;
if (position == 0) {
position = n;
}
cout << position;
return 0;
}
If the question required specific error handling, it should have stated so (so don't feel bad).
In every real-world project, there should be a standard to dictate what to do with weird input. Do you throw? Do you output a warning? If so, does it have to be translated to the system language?
In the absence of such instructions I would err toward excluding these values after reading them. Print an error to std::cerr (or throw an exception). Do this as close to where you read them as possible.
For overflow detection, you can use the methods described here. Some may disagree, and for a lab-exercise, it's probably not important. However, there is a saying in computing "Garbage in == Garbage out". It's a good habit to check for garbage before processing, rather than attempting to "recycle" garbage as you process.
Here's the problem:
Say the value of N is 2^63-1, and X and M are both 2^63 - 2.
When your program runs untill the ((X % N) + (M % N)) % N part,
X % N evaluates into 2^63 - 2 (not changed), and so does M % N.
Then, the addition between the two results occurs, 2^63 - 2 + 2^63 - 2 there is the overflow happening.
After the comment of #WBuck, the answer is actually rather easy which is to change the long long to unsigned because there are no negative numbers and therefore, increase the MAX VALUE of long long (when using unsigned).
Thank you so much.

Two largest contiguous subarray

I'm currently doing a problem that's similar to the maximum contiguous sub-array problem. However, instead of finding just one contiguous sub-array, I can find up to two non-overlapping contiguous subarrays.
For instance for the test case below, the answer is 20 since we can take everything but -20.
5 3 -20 4 8
To do this, I implemented the following code:
long long n, nums[500500], dp[500500][2][3];
long long best(int numsLeft, int beenTaking, int arrLeft) {
if (arrLeft < 0 || numsLeft < 0) return 0;
if (dp[numsLeft][beenTaking][arrLeft] != -1)
return dp[numsLeft][beenTaking][arrLeft];
if (beenTaking) {
// continue Taking
long long c1 = best(numsLeft - 1, beenTaking, arrLeft) + nums[numsLeft];
// stop Taking
long long c2 = best(numsLeft - 1, 0, arrLeft);
return dp[numsLeft][beenTaking][arrLeft] = max(c1, c2);
} else {
// continue not Taking
long long c1 = best(numsLeft - 1, beenTaking, arrLeft);
// start Taking
long long c2 = best(numsLeft - 1, 1, arrLeft - 1) + nums[numsLeft];
return dp[numsLeft][beenTaking][arrLeft] = max(c1,c2);
}
}
This is the function call:
cout << best(n - 1, 0, 2) << endl;
The dp array has been -1 filled before the function call. The nums array contain n elements and is zero-indexed.
Ideone.com link is this: http://ideone.com/P5PB7h
While my code does work for the sample test-case shown above, it fails for some other test-cases (that are not available to me). Are there any edge cases that are not being caught by my code? Where am I going wrong? Thank you for the help.
I tried coming up with a few such edge cases, but am unable to do so.
The problem seems to be on the following lines:
if (beenTaking) {
// continue Taking
long long c1 = best(numsLeft - 1, beenTaking, arrLeft) + nums[numsLeft];
...
} else {
...
}
Adding best(numsLeft - 1, 1, arrLeft) without decrementing arrLeft implies that the "best" results from the first numsLeft - 1 values in nums[] happens at the end of nums[] (at index numsLeft - 1). This may not be true.
The code will therefore likely fail when there are more than 2 positive ranges separated by negative values.
Also, the dp array should be initialized to something clearly out of range, like LLONG_MIN, rather than -1, which could be a legitimate sum.

About random numbers in C++

I am really new to C++. I am following a free online course, and one thing I had to do was to create a program which could scramble the characters of a string.
So, I created a function who received the word as parameter and returned the scrambled word. ctime and cstdlib were included and srand(time(0)); declared in the main.
Basically, the function looked like this :
std::string mixingWord(std::string baseWord)
{
std::string mixWord;
int pos(0);
for (int i = baseWord.length; i >= 0; i--)
{
if (i != 0)
{
pos = rand() % i;
mixWord += baseWord[pos];
baseWord.erase(pos,1);
}
else
{
mixWord += baseWord[0];
}
}
return mixWord;
}
And it worked just fine. But the correct solution was
std::string mixingWord(std::string baseWord)
{
std::string mixWord;
int pos(0);
while (baseWord.size() != 0)
{
pos = rand() % baseWord.size();
mixWord += baseWord[pos];
baseWord.erase(pos, 1);
}
return mixWord;
}
And it works fine as well.
My question is :
Why is the solution working ?
From what I understood, this :
rand() % value
gives out a value between 0 and the value given.
SO, since baseWord.size() returns, let's say 5 in the event of a word like HELLO. rand will generate a number between 0 and 5. So it COULD be 5. and baseWord[5] is out of bound, so it should crash once in a while, but I tried it over 9000 times (sorry, dbz reference), and it never crashed.
Am I just unlucky, or am I not understanding something ?
x % y gives the remainder of x / y. The result can never be y, because if it was, then that would mean y could go into x one more time, and the remainder would actually be zero, because y divides x evenly. So to answer your question:
Am I just unlucky, or am I not understanding something ?
You're misunderstanding something. rand() % value gives a result in the range [0,value - 1] (assuming value is positive), not [0, value].
rand() % 100 returns number between 0 and 99. This is 100 NUMBERs but includes 0 and does not include 100.
A good way to think about this is a random number (1000) % 100 = 0. If I mod a random number with the number N then there is no way to get the number N back.
Along those lines
pos = rand() % baseWord.size();
will never return pos = baseWord.size() so in your case there will not be an indexing issue
I guess you just misunderstood the modulo operator. a % b, with a and b any integer, will return values between 0 and b-1 (inclusive).
As for your HELLO example, it will only return values between 0 and 4, therefore will never encounter out of bound error.

Having trouble understanding a portion of code (bit operation)

I can't understand how to count number of 1's in binary representation.
I have my code, and I hope someone can explain it for me.
Code:
int count (int x)
{
int nr=0;
while(x != 0)
{
nr+=x%2;
x/=2;
}
return nr;
}
Why while ? For example if i have 1011, it wouldn't stop at 0?
Why nr += x%2 ?
Why x/=2 ?!
First:
nr += x % 2;
Imagine x in binary:
...1001101
The Modulo operator returns the remainder from a / b.
Now the last bit of x is either a 0, in which case 2 will always go into x with 0 remainder, or a 1, in which case it returns a 1.
As you can see x % 2 will return (if the last bit is a one) a one, thus incrementing nr by one, or not, in which case nr is unchanged.
x /= 2;
This divides x by two, and because it is a integer, drops the remainder. What this means is is the binary was
....10
It will find out how many times 2 would go into it, in this case 1. It effectively drops the last digit of the binary number because in base 2 (binary) the number of times 2 goes into a number is just the same as 'shifting' everything down a space (This is a poor explanation, please ask if you need elaboration). This effectively 'iterates' through the binary number, allowing the line about to check the next bit.
This will iterate until the binary is just 1 and then half that, drop the remainder and x will equal 0,
while (x != 0)
in which case exit the loop, you have checked every bit.
Also:
'count`is possibly not the most descriptive name for a function, consider naming it something more descriptive of its purpose.
nr will always be a integer greater or equal to zero, so you should probably have the return type unsigned int
int count (int x)
{
int nr=0;
while(x != 0)
{
nr+=x%2;
x/=2;
}
return nr;
}
This program basically gives the numbers of set bits in a given integer.
For instance, lets start with the example integer 11 ( binary representation - 1011).
First flow will enter the while loop and check for the number, if it is equal to zero.
while(11 != 0)
Since 11 is not equal to zero it enter the while loop and nr is assigned the value 1 (11%2 = 1).nr += 11%2;
Then it executes the second line inside the loop (x = x/2). This line of code assigns the value 5 (11/2 = 5 ) to x.
Once done with the body of the while loop, it then again checks if x ie 5 is equal to zero.
while( 5 != 0).
Since it is not the case,the flow goes inside the while loop for the second time and nr is assigned the value 2 ( 1+ 5%2).
After that the value of x is divided by 2 (x/2, 5/2 = 2 )and it assigns 2 to x.
Similarly in the next loop, while (2 != 0 ), nr adds (2 + 2%2), since 2%2 is 0, value of nr remains 2 and value of x is decreased to 1 (2/2) in the next line.
1 is not eqaul to 0 so it enters the while loop for the third time.
In the third execution of the while loop nr value is increased to 3 (2 + 1%2).
After that value of x is reduced to 0 ( x = 1/2 which is 0).
Since it fails the check (while x != 0), the flow comes out of the loop.
At the end the value of nr (Which is the number of bits set in a given integer) is returned to the calling function.
Best way to understand the flow of a program is executing the program through a debugger. I strongly suggest you to execute the program once through a debugger.It will help you to understand the flow completely.

Turn while loop into math equation?

I have two simple while loops in my program that I feel ought to be math equations, but I'm struggling to convert them:
float a = someValue;
int b = someOtherValue;
int c = 0;
while (a <= -b / 2) {
c--;
a += b;
}
while (a >= b / 2) {
c++;
a -= b;
}
This code works as-is, but I feel it could be simplified into math equations. The idea here being that this code is taking an offset (someValue) and adjusting a coordinate (c) to minimize the distance from the center of a tile (of size someOtherValue). Any help would be appreciated.
It can be proved that the following is correct:
c = floor((a+b/2)/b)
a = a - c*b
Note that floor means round down, towards negative infinity: not towards 0. (E.g. floor(-3.1)=-4. The floor() library functions will do this; just be sure not to just cast to int, which will usually round towards 0 instead.)
Presumably b is strictly positive, because otherwise neither loop will never terminate: adding b will not make a larger and subtracting b will not make a smaller. With that assumption, we can prove that the above code works. (And paranoidgeek's code is also almost correct, except that it uses a cast to int instead of floor.)
Clever way of proving it:
The code adds or subtracts multiples of b from a until a is in [-b/2,b/2), which you can view as adding or subtracting integers from a/b until a/b is in [-1/2,1/2), i.e. until (a/b+1/2) (call it x) is in [0,1). As you are only changing it by integers, the value of x does not change mod 1, i.e. it goes to its remainder mod 1, which is x-floor(x). So the effective number of subtractions you make (which is c) is floor(x).
Tedious way of proving it:
At the end of the first loop, the value of c is the negative of the number of times the loop runs, i.e.:
0 if: a > -b/2 <=> a+b/2 > 0
-1 if: -b/2 ≥ a > -3b/2 <=> 0 ≥ a+b/2 > -b <=> 0 ≥ x > -1
-2 if: -3b/2 ≥ a > -5b/2 <=> -b ≥ a+b/2 > -2b <=> -1 ≥ x > -2 etc.,
where x = (a+b/2)/b, so c is: 0 if x>0 and "ceiling(x)-1" otherwise. If the first loop ran at all, then it was ≤ -b/2 just before the last time the loop was executed, so it is ≤ -b/2+b now, i.e. ≤ b/2. According as whether it is exactly b/2 or not (i.e., whether x when you started was exactly a non-positive integer or not), the second loop runs exactly 1 time or 0, and c is either ceiling(x) or ceiling(x)-1. So that solves it for the case when the first loop did run.
If the first loop didn't run, then the value of c at the end of the second loop is:
0 if: a < b/2 <=> a-b/2 < 0
1 if: b/2 ≤ a < 3b/2 <=> 0 ≤ a-b/2 < b <=> 0 ≤ y < 1
2 if: 3b/2 ≤ a < 5b/2 <=> b ≤ a-b/2 < 2b <=> 1 ≤ y < 2, etc.,
where y = (a-b/2)/b, so c is: 0 if y<0 and 1+floor(y) otherwise. [And a now is certainly < b/2 and ≥ -b/2.]
So you can write an expression for c as:
x = (a+b/2)/b
y = (a-b/2)/b
c = (x≤0)*(ceiling(x) - 1 + (x is integer))
+(y≥0)*(1 + floor(y))
Of course, next you notice that (ceiling(x)-1+(x is integer)) is same as floor(x+1)-1 which is floor(x), and that y is actually x-1, so (1+floor(y))=floor(x), and as for the conditionals:
when x≤0, it cannot be that (y≥0), so c is just the first term which is floor(x),
when 0 < x < 1, neither of the conditions holds, so c is 0,
when 1 ≤ x, then only 0≤y, so c is just the second term which is floor(x) again.
So c = floor(x) in all cases.
c = (int)((a - (b / 2)) / b + 1);
a -= c * b;
Test case at http://pastebin.com/m1034e639
I think you want something like this:
c = ((int) a + b / 2 * sign(a)) / b
That should match your loops except for certain cases where b is odd because the range from -b/2 to b/2 is smaller than b when b is odd.
Assuming b is positive, abs(c) = floor((abs(a) - b/2) / b). Then, apply sign of a to c.