Do... while loop unexpected behavior - c++

Quick explanation:
I want to assign random numbers to words, in a way so every letter has different number. for convenience purposes I have used arrays instead of separate one letter variables; this way I know that "abc[1]" is letter 'b' from word "abc". The first number of a word is using different range to avoid having numbers like "075"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int abc[2];
int def[2];
void setRandom()
{
abc[0] = rand() %9+1;
do {abc[1] = rand() %10;} while (abc[1] == abc[0]);
do {abc[2] = rand() %10;} while (abc[2] == abc[1] || abc[2] == abc[0]);
printf("RANDOM abc %d %d %d", abc[0], abc[1], abc[2]); //printed just fine.
do {def[0] = rand() % 9 +1; } while (def[0] == abc[2] || def[0] == abc[1] || def[0] == abc[0]); //code seems to be stuck here
do {def[1] = rand() %10;} while (def[1] == def[0] || def[1] == abc[2] || def[1] == abc[1] || def[1] == abc[0]);
do {def[2] = rand() %10;} while (def[2] == def[1] || def[2] == def[0] || def[2] == abc[2] || def[2] == abc[1] || def[2] == abc[0]);
printf("RANDOM def %d %d %d", def[0], def[1], def[2]); //THIS CODE IS NEVER REACHED. WHY?
}
int main ()
{
setRandom();
printf("RANDOM SET");
}
I am aware that the numbers are not truly random. I am aware that the code is messy. I am aware it's innefficient to brute-force numbers. I am aware that this way of setting numbers is bad, but I couldn't think of anything better. This code will do the job for my purposes.
The problem is that the above code gets stuck while generating number for def[0]; it will infinitely generate new random numbers, it seems to be completely ignoring 'while' part of the loop.
You may either suggest a better method of doing what I'm trying to do, or simply a solution to the problem, either will do just fine since the project isn't anything big, it's just used as puzzle solver.

The problem is that you've chosen the wrong size for your arrays. def[0] and abc[2] most likely point to the same location.
Specifically, you're creating arrays of size 2, and then accessing 3 elements of them. Change:
int abc[2];
int def[2];
to:
int abc[3];
int def[3];
See also this answer as to a better way to do what you're trying to do.

Arrays in C/C++ are zero-based. creating abc[2] give you only 0 and 1 to legitimately access. Anything beyond the end of the array is undefined behaviour - in this case it's probable that abc[2] (the third, not second element) points to def[0].
Fix your code so that both declarations allocate 3 elements instead of 2.

Related

How do i find GCD with while loop? How does modulus operator work?

#include <iostream>
int GCD()
{
int a,b,k;
cout<<"Enter a and b"<<endl;
cin>>a>>b;
cout<<endl;
if (a>b)
{
k=a;
}
else
{
k=b;
}
cout<<k<<endl;
do
{
k=k-1;
} while(a%k !=0 && b%k !=0);
cout<<k<<endl;
return 0;
}
Why programm like this doesnt work correctly? For example when i enter 125 and 5 answer is 25, but supposed to be 5? Am wrong with logic in while loop? As i understood problem is in modulus operator. When k hits 25 it says that 125%25=0 and 5%=25=0. How can i fix this?
You have some mistakes here:
The GCD is lower or equal to the lower number. Currently, you start checking with the larger number. You need to flip the if block to if (a<b). (not exactly an error, but you check much more numbers than needed)
You need to check if the inital k is the GCD. When using a do {} while() the first number you check is k-1. Use a simple while instead. Also the loop condition has a logic flaw.
while (!((a % k == 0) && (b % k == 0)))
{
k--;
}
Note that the brackets around the modulo are not neccessary, but improve readability a bit.
Your code will not compile under all compilers and you should not omit the namespace std::.
Your while statement has logic error. It needs to be
while(!(a%k == 0 && b%k == 0));
When k is equal to 25, 125%25==0 so in your while statement a%k !=0 part is equals to false so it exit your do-while but it needs to test if b%k is equal to 0 or not!
Also your implementation tends to execute slow when a and b is big. You can take a look efficent solutions.

Using getchar_unlocked()

I recently learnt that using getchar_unlocked() is a faster way of reading input.
I searched on the internet and found the code snippet below:
But I am unable to understand it.
void fast_scanf(int &number)
{
register int ch = getchar_unlocked();
number= 0;
while (ch > 47 && ch < 58) {
number = number * 10 + ch - 48;
ch = getchar_unlocked();
}
}
int main(void)
{
int test_cases;fast_scanf(test_cases);
while (test_cases--)
{
int n;
fast_scanf(n);
int array[n];
for (int i = 0; i < n; i++)
fast_scanf(array[i]);
}
return 0;
}
So, this code takes input for an integer array of size n for a given number of test_cases . I didn't understand anything in the function fast_scanf, like why this line:
while (ch > 47 && ch < 58)
{ number = number * 10 + ch - 48;
why the register is used while declaring ch?
why the getchar_unlocked() is used twice in the function? and so on..
It would be great help if someone elaborates this for me. Thanks in advance!
Okay, since what you are asking needs to be explained clearly, I am writing it here... so I don't jumble it all up inside the comments...
The function: (Edited it a bit to make it look like more C++-standard)
void fast_scanf(int &number)
{
auto ch = getchar_unlocked();
number= 0;
while (ch >= '0' && ch <= '9')
{
number = number * 10 + ch - '0';
ch = getchar_unlocked();
}
}
Here, take up consideration by looking at the ASCII Table first, since you won't understand how the results are coming up if you don't...
1) Here, you have a character ch takes up the input character from the user using getchar_unlocked() (The auto keyword does that automatically for you and is only usable in C++, not C)...
2) You assign the variable number to zero so that the variable can be re-used, note that the variable is a reference so it changes inside your program as well...
3) while (ch >= '0' && ch <= '9')... As pointed out, checks whether the characters is within the numerical ASCII limit, similar to saying that the character has to be greater than or equal to 48 but less than or equal to 57...
4) Here, things are a little bit tricky, Variable number is multiplied with the product of itself and 10 and the real integer value of the character you stored)...
5) In the next line, ch is reassigned so that you don't have to stay in the loop forever, since ch will remain that number forever if the user doesn't type anything... remember a loop goes back to where it was declared after reaching the end, checks if the condition is true, continues if it is true else breaks)...
For example: 456764
Here, ch will first take 4 then the others follow so we go with 4 first...
1) Number will be assigned to zero. While loop checks if the given character is a number or not, if it is continues the loop else breaks it...
2) Multiplication of 0 with 10 will be zero... and adding it with difference 52 (that is '4') with 48 (that is '0') gives you 4 (the real numerical value, not the char '4')...
So the variable number now is 4...
And the same continues with the others as well... See...
number = number * 10 + '5' - '0'
number = 4 * 10 + 53 - 48
number = 40 + 5
number = 45... etc, etc. for other numbers...

I just created an extremely fast way to sort primes. How do I improve it?

Basically, how it works is it converts a number into a string, and if it finds any even in the string then it gives foundEven variable a positive value. The same goes for odd numbers.
(One thing I don't get is why if I switch the '>' sign with an '<' in if (FoundEvenSignedInt < FoundOddSignedInt) it gives you the correct result of an odd number.)
Are there any ways I could improve the code? Are there any bugs in it? I'm fairly new at C++ programing.
#include <string>
#include <cstddef>
int IsPrime(long double a)
{
int var;
long double AVar = a;
signed int FoundEvenSignedInt, FoundOddSignedInt;
std::string str = std::to_string(a);
std::size_t foundEven = str.find_last_of("2468");
std::size_t foundOdd = str.find_last_of("3579");
FoundEvenSignedInt = foundEven;
FoundOddSignedInt = foundOdd;
if (FoundEvenSignedInt < FoundOddSignedInt)
{
var = 1;
goto EndOfIsPrimeFunction;
}
if (FoundEvenSignedInt > FoundOddSignedInt)
{
var = 2;
goto EndOfIsPrimeFunction;
}
// This if statement kept giving me this weird warning so I made it like this
if (FoundEvenSignedInt == -1)
{
if (FoundOddSignedInt == -1)
{
if (AVar == 10 || 100 || 1000 || 10000 || 100000 || 1000000)
{
var = 2;
goto EndOfIsPrimeFunction;
}
}
}
EndOfIsPrimeFunction:
return var;
}
Here are some ways to improve the code.
The Collatz conjecture is about integers. long double is a data type of floating point numbers. It is unsuitable for checking the conjecture. You need to work with an integral data type such as unsigned long long. If this doesn't have enough range for you, you need to work with some kind of Bignum dat atype. There isn't any in the standard C library, you need to find a third party one.
The Collatz conjecture has nothing to do with being prime. It is about even and odd integers. It is true that all prime numbers except 2 are odd, but this fact doesn't help you.
The data type to answer yes/no questions in C++ is bool. By convention. for any other numeric data type zero means "no" and all other values mean "yes" (technically, when converted to bool, zero is converted to false and other values to true, so you can do things like if (a % 2). A function that returns 1 and 2 for yes and no is highly unconventional.
A natural method of checking whether a number is odd is this:
bool isOdd (unsigned long long a)
{
return a % 2;
}
It is somewhat faster than your code (by a factor of about 400 on my computer), gives correct results every time, is readable, and has zero goto statements.
Instead of the if(AVar == 10 || 100 || ..., you can say if(!(AVar % 10)).

Getting a wrong answer for SPOJ PLD

I am trying to solve problem PLD on SPOJ, but I'm getting a WA on the 9th testcase.
My Approach:
I am implementing Manacher's Algorithm and I believe that if something wrong is there, then it can be wrong in this code.
if((k%2==0)&&(p[i]>=k)&&(temp[i]=='#'))
count++;
if((k%2==1)&&(p[i]>=k)&&(temp[i]!='#'))
count++;
But according to my approach if character is #, then the maximum length of palindromic string centered at it can be even only, so if p[i] >= k, then I am increasing count if we are finding a palindromic string of even length.
Similarly for characters [considering input character i.e other than #] centered at i-th location but for odd length strings.
#include<stdio.h>
#include<string.h>
char a[30002],temp[60010];
int p[60010];
int min(int a,int b)
{
if(a<b)
return a;
return b;
}
int main()
{
//freopen("input.txt","r+",stdin);
//freopen("a.txt","w+",stdout);
int k,len,z;
scanf("%d",&k);
getchar();
gets(a);
len=strlen(a);
//Coverting String
temp[0]='$';
temp[1]='#';
z=2;
for(int i=1;i<=len;i++)
{
temp[z++]=a[i-1];
temp[z++]='#';
}
len=z;
int r=0,c=0,check=0,idash,t,count=0;
for(int i=1;i<len;i++)
{
check=0;
idash=c-(i-c);
p[i]=r>i?min(r-i,p[idash]):0;
t=p[i];
while(temp[i+p[i]+1]==temp[i-1-p[i]])
p[i]++;
if(r<i+p[i])
{
c=i;
r=i+p[i];
}
if((k%2==0)&&(p[i]>=k)&&(temp[i]=='#'))
count++;
if((k%2==1)&&(p[i]>=k)&&(temp[i]!='#'))
count++;
}
printf("%d",count);
//getchar();
//getchar();
return 0;
}
You may want to take advantage of C++ short-circuit evaluation of logical expressions.
For example, rearrange the order so you check for '#' first:
if ((temp[i] == '#') && (k % 2 == 0) && (p[i] >= k))
In the above rearrangement, if the character is not '#', none of the other expressions are evaluated.
You may want to extract (p[i] >= k) to an outside if statement since it is common to both:
if (p[i] >= k)
{
if ((temp[i] == '#') && (k % 2 == 0)) ++count;
if ((temp[i] != '#') && (k % 2 == 1)) ++count;
}
The above modification will result in only one evaluation of the expression (p[i] >= k).
Also examine your for loop to see if there are statements or expressions that don't change or are repeated. If a statement or expression doesn't change inside the loop, it is called an invariant, and can be moved before or after the loop.
Statements or expressions that are duplicated (such as array index calculations) can be evaluated and stored in a temporary variable. Although good compilers may do this (depending on the optimization level), in your performance requirements, you may want to help out the compiler.
Another suggestion is to replace p[i] with a pointer to the location or a reference to the location. Again, this is to help out the compiler when the optimization is not set optimally:
int& p_slot_i = p[i]; // This syntax needs checking
// or
int * p_slot_i = &p[i];
//...
t = *p_slot_i;
while(temp[i + *p_slot_i + 1] == temp[i - 1 - *p_slot_i)
{
*p_slot_i++;
}
Lastly, Elimination of spaces, blank lines and curly braces DOES NOT AFFECT PROGRAM PERFORMANCE. A program that is one line or spaced across multiply lines will have the exact assembly translation and the exact performance. So please, add spaces, blank lines and curly braces to improve readability.
Edit 1: performance of min()
You may want to declare you min() function as inline to suggest to the compiler you want the function pasted where it is called, rather than calling the function. Function calls slow down a programs execution.

C++ random numbers logical operator wierd outcome

I am trying to make a program generating random numbers until it finds a predefined set of numbers (eg. if I had a set of my 5 favourite numbers, how many times would I need to play for the computer to randomly find the same numbers). I have written a simple program but don't understand the outcome which seems to be slightly unrelated to what I expected, for example the outcome does not necessarily contain all of the predefined numbers sometimes it does (and even that doesn't stop the loop from running). I think that the problem lies in the logical operator '&&' but am not sure. Here is the code:
const int one = 1;
const int two = 2;
const int three = 3;
using namespace std;
int main()
{
int first, second, third;
int i = 0;
time_t seconds;
time(&seconds);
srand ((unsigned int) seconds);
do
{
first = rand() % 10 + 1;
second = rand() % 10 + 1;
third = rand() % 10 + 1;
i++;
cout << first<<","<<second<<","<<third<< endl;
cout <<i<<endl;
} while (first != one && second != two && third != three);
return 0;
}
and here is out of the possible outcomes:
3,10,4
1 // itineration variable
7,10,4
2
4,4,6
3
3,5,6
4
7,1,8
5
5,4,2
6
2,5,7
7
2,4,7
8
8,4,9
9
7,4,4
10
8,6,5
11
3,2,7
12
I have also noticed that If I use the || operator instead of && the loop will execute until it finds the exact numbers respecting the order in which the variables were set (here: 1,2,3). This is better however what shall I do make the loop stop even if the order is not the same, only the numbers? Thanks for your answers and help.
The issue is here in your condition:
} while (first != one && second != two && third != three);
You continue while none of them is equal. But once at least one of them is equal, you stop/leave the loop.
To fix this, use logical or (||) rather than a logical and (&&) to link the tests:
} while (first != one || second != two || third != three);
Now it will continue as long as any of them doesn't match.
Edit - for a more advanced comparison:
I'll be using a simple macro to make it easier to read:
#define isoneof(x,a,b,c) ((x) == (a) || (x) == (b) || (x) == (c))
Note that there are different approaches you could use.
} while(!isoneof(first, one, two, three) || !isoneof(second, one, two, three) || !isoneof(third, one, two, three))
You have a mistake in your logical condition: it means "while all numbers are not equal". To break this condition, it is enough for one pair to become equal.
You needed to construct a different condition - either put "not" in front of it
!(first==one && second==two && third==three)
or convert using De Morgan's law:
first!=one || second!=two || third!=three