C++ Running Time of Algorithms [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I've made Naive Approach/Finite Automata search algorithms as homework. Professor also asked for us to print run time of each algorithm. I tried;
int start_s=clock();
// the code you wish to time goes here
int stop_s=clock();
cout << "time: " << (stop_s-start_s)/double(CLOCKS_PER_SEC)*1000 << endl;
this stuff but it can't compute outside of main... I think.
Here is my code;
#include <iostream>
#include <sstream>
#include <fstream>
#include<stdio.h>
#include<string.h>
#include <ctime>
#define NO_OF_CHARS 256
using namespace std;
//Naive Approach search starts here:
void naive_search(string pat, string txt)
{
int M = pat.length();
int N = txt.length();
/* A loop to slide pat[] one by one */
for (int i = 0; i <= N - M; i++)
{
int j;
/* For current index i, check for pattern match */
for (j = 0; j < M; j++)
{
if (txt[i + j] != pat[j])
break;
}
if (j == M) // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
{
printf("Found pattern at index: %d \n", i);
}
}
}
//Finite Autoama starts here:
int goNextState(string pattern, int num_total_state, int state, int given_character) {
// If our character match with the pattern
if (state < num_total_state && given_character == pattern[state])
return state + 1;
int nextstate, index;
//If dont match, search the maximum legth of matched pattern
// For example pattern is = aabb and our index is aabc , start to match first character of pattern and last character of given index increasingly and decreasingly..
for (nextstate = state; nextstate > 0; nextstate--)
{
if (pattern[nextstate - 1] == given_character) // start to find longest matched substring
{
for (index = 0; index < nextstate - 1; index++) {
if (pattern[index] != pattern[state - nextstate + 1 + index])
break;
}
if (index == nextstate - 1)
return nextstate;
}
}
return 0;
}
void Transition_Table(string pattern, int lengt_of_pattern, int Table_Array[][NO_OF_CHARS])
{
int given_character;
int state;
for (state = 0; state <= lengt_of_pattern; state++)
for (given_character = 0; given_character<NO_OF_CHARS; ++given_character)
Table_Array[state][given_character] = goNextState(pattern, lengt_of_pattern, state, given_character);
}
void Automata_Compute(string pattern, string given_text) {
int numberOfLine = 0;
int count = 0;
int A = pattern.length();
int B = given_text.length();
int Table_Array[1000][NO_OF_CHARS];
Transition_Table(pattern, A, Table_Array);
int i, state = 0;
for (i = 0; i<B; i++) {
// get input ...
state = Table_Array[state][given_text[i]];
if (state == A) {
count++;
printf("Found pattern at index: %d \n",i - A + 1);
}
}
}
// Driver program to test above function
int main()
{
ifstream ifile("Text.txt"); // open
string text(istreambuf_iterator<char>(ifile), {});
string pat = ("AABA");
//string text = ("AABABBABABAAABABBABAAABABBBBBBBAAAAAAABBAABA\nABABABAAABAAAABBBBBAABA\nABABABAABABBBBAAAAABA");
cout << "Naive Approach:" << endl;
naive_search(pat, text);
cout << "\nFinite Automata:" << endl;
Automata_Compute(pat, text);
return 0;
}
Edit: I need help about how to compute time of Naive Approach Search Algorithm and Finite Autoamata Search Algorithm.

The question is not entirely clear but what is stopping you from just doing:
std::clock_t start = std::clock();
method_to_time();
std::clock_t end = std::clock();
std::cout << "Time taken to compute method_to_time() = "
<< static_cast<double)((end-start))/CLOCKS_PER_SEC << " seconds.";
Note that using <ctime> as above is not the best way to accurately time algorithms as the clock runs based on the processor cycle so can give different results based on whether it is at high or low loads. However, if accuracy is not a big issue then the above is "fine".
For a better timing facility look into the <chrono> header.

#ArchbishopOfBanterbury thanks for your help! I did it like you suggested and it worked;
int main()
{
ifstream ifile("Example.txt"); // open
string text(istreambuf_iterator<char>(ifile), {});
string pat = ("nut");
//string text = ("AABABBABABAAABABBABAAABABBBBBBBAAAAAAABBAABA\nABABABAAABAAAABBBBBAABA\nABABABAABABBBBAAAAABA");
cout << "Naive Approach:" << endl;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
naive_search(pat, text);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto nduration = duration_cast<microseconds>(t2 - t1).count();
cout << "\nFinite Automata:" << endl;
high_resolution_clock::time_point t3 = high_resolution_clock::now();
Automata_Compute(pat, text);
high_resolution_clock::time_point t4 = high_resolution_clock::now();
auto fduration = duration_cast<microseconds>(t4 - t3).count();
cout << "\nNaive Approach Duration: ";
cout << nduration;
cout << "\nFinite Automata Duration: ";
cout << fduration << endl;
cout << "\n";
return 0;
}

Related

C++ terminate called after throwing an instance of 'std::invalid_argument'

I just wrote this program. The test case I am using is 541. It is supposed to reverse the 541 into 154, then subtract 541 and 154, to get 396 then reverse that into 693. After that it is supposed to add 396 and 693 to get 1089. In the last three lines of code, I am trying to convert the strings into ints so I can add the last two numbers but I am getting this error. The code has to be done in this specific way for my class.
#include <iostream>
#include <string>
#include <algorithm>
/**
* main application starting point
* #return integer (0=SUCCESS)
*/
int main() {
//prompts user to input a three-digit number
std::string threeDigitNum;
std::cout << "Enter a 3-digit number, where the first and last digit differ by at least one" ;
std::cin >> threeDigitNum;
//uses a for loop to output the reverse of the first number
std::string threeReversed;
int control = 0;
for(int i = 2; i >= 0; i--){
threeReversed[control] = threeDigitNum[i];
control++;
}
std::cout << threeDigitNum[2]+ threeDigitNum[1]+ threeDigitNum[0] << std::endl;
//converts the numbers in the strings to integers
//displays the differnce of the first and second number
int firstNum = std::stoi(threeDigitNum);
int secondNum = std::stoi(threeReversed);
std::cout << firstNum - secondNum << std::endl;
std::string thirdNum;
thirdNum = std::to_string(firstNum - secondNum);
std::string thirdNumReverse;
for(int i = thirdNum.length(); i >= 0; i--){
thirdNumReverse = thirdNumReverse + thirdNum[i];
}
std::cout << thirdNumReverse << std::endl;
int fourthNum = std::stoi(thirdNum);
int fifthNum = std::stoi(thirdNumReverse);
std::cout<< fourthNum + fifthNum;
return 0;
}
Here's a hint:
std::string thirdNumReverse;
for(int i = thirdNum.length(); i >= 0; i--){
thirdNumReverse = thirdNumReverse + thirdNum[i];
}
If the length of thirdNum is 3, then the valid indices are from [2..0]. But yor code enumerates a different range of indices.
You are creating an empty string
std::string threeReversed;
and then you try to write into that empty (!) string using the subscript operator (using positions which don't exist in that string).
threeReversed[control] = threeDigitNum[i];
If you want to reverse a string, you can use a C++ Standard Library algorithm:
std::string threeReversed{ threeDigitNum };
std::reverse(threeReversed.begin(), threeReversed.end());
Later in the code, you have the same issue again for thirdNumReverse.
You are at a point where you want to learn how to debug small programs.
You may also want to use smaller methods which you can test on their own. See how short your code can become when you use a method that does the number reversing process for you:
#include <iostream>
#include <string>
#include <algorithm>
#include <cassert>
int reverse(int i)
{
std::string s = std::to_string(i);
std::reverse(s.begin(), s.end());
return std::stoi(s);
}
int main() {
assert(reverse(541) == 145);
int threeDigitNum{541};
int threeReversed = reverse(threeDigitNum);
std::cout << threeReversed << std::endl;
std::cout << threeDigitNum - threeReversed << std::endl;
int thirdNum = threeDigitNum - threeReversed;
int thirdNumReverse = reverse(thirdNum);
std::cout << thirdNumReverse << std::endl;
std::cout << thirdNum + thirdNumReverse;
return 0;
}
There are 2 errors in your code :
Error 1 : Creating empty string, but accessing other indices.
std::string threeReversed;
int control = 0;
for(int i = 2; i >= 0; i--){
threeReversed[control] = threeDigitNum[i];
control++;
}
change above code as you already did while calculating thirdNumReverse :
std::string threeReversed;
for(int i = 2; i >= 0; i--){
threeReversed = threeReversed + threeDigitNum[i];
}
Error 2 : indices are 0 based in c++, so start from thirdNum.length() - 1 instead of thirdNum.length()
for(int i = thirdNum.length(); i >= 0; i--){
thirdNumReverse = thirdNumReverse + thirdNum[i];
}
change above code as below :
for(int i = thirdNum.length() - 1; i >= 0; i--){
thirdNumReverse = thirdNumReverse + thirdNum[i];
}
Note : This code can be improved but I am just pointing out the errors in your existing code. Not improving it.

What are various methods to store very large integer value in a variable with less compilation time in C++ when doing operation on that variable

What should I do with this variable to make it store following large number without downloading any new libraries.I am talking about using some manipulation like hashing or arrays or something I don't know.
For fun I've written something that works only on strings. By the way, that number you gave is awfully large number, it's something like a quintillion times the mass of our solar system in kg.
There are two methods. The first one adds one to the number and checks if it's a palindrome. This is a slow version, but can still works for numbers up to like about 16 digits in a reasonable time.
The second method is the method better way, it basically copies the left side of the number to the right side, it's pretty much instant. As the code is now you can run it through both to cross-reference the results.
I can't say it's fool-proof and I'm sure there's errors in it, but it seems to work, and I did have fun writing it. Also, if you're not allowed to use ANY libraries whatsoever, it's rather easy to refactor, just use raw strings and pass the size in the function.
#include <iostream>
#include <string>
#include <chrono>
#include <stdexcept>
#include <cstring>
using namespace std::chrono;
using namespace std;
auto startT = high_resolution_clock::now();
auto endT = high_resolution_clock::now();
double timeTaken;
#define STARTCLOCK startT = high_resolution_clock::now();
#define STOPCLOCK endT = high_resolution_clock::now();
#define PRINT_ELAPSED_TIME timeTaken = duration_cast<milliseconds>(endT - startT).count() / 1000.0; \
cout << "Process took " << timeTaken << " seconds\n\n";
void addOneTo(std::string& value)
{
int64_t idx = value.size();
do
{
--idx;
if (idx < 0) {
memset(&value[0], '0', value.size());
value.insert(value.begin(), '1');
return;
}
value[idx] += char(1);
if (value[idx] > '9') { value[idx] = '0'; }
} while (value[idx] == '0');
}
bool isPalindrome(const std::string& number)
{
const char* start = &number[0];
const char* end = &number[number.size() - 1];
while (start <= end)
{
if (*start != *end) return false;
++start;
--end;
}
return true;
}
std::string getSmallestPalindromeByBruteForceBiggerThan(std::string num)
{
if (num.empty()) throw std::runtime_error("Empty string");
while (true)
{
addOneTo(num);
if (isPalindrome(num)) return num;
}
}
std::string getSmallestPalindromeOptimisedWayBiggerThan(std::string num)
{
if (num.empty()) throw std::runtime_error("Empty string");
addOneTo(num);
if (num.size() == 1) return num;
int64_t left;
int64_t right;
left = num.size() / 2 - 1;
if (num.size() % 2 == 0) right = num.size() / 2;
else right = num.size() / 2 + 1;
if (num[left] < num[right])
{
++num[left];
num[right] = num[left];
}
for (; left >= 0 && right < num.size(); --left, ++right)
{
num[right] = num[left];
}
return num;
}
int main()
{
string number = "60819750046451377";
STARTCLOCK
string palindrome = getSmallestPalindromeByBruteForceBiggerThan(number);
cout << "____BRUTE FORCE____\n";
cout << "Smallest palindrome = \n" << palindrome << '\n';
STOPCLOCK
PRINT_ELAPSED_TIME
STARTCLOCK
palindrome = getSmallestPalindromeOptimisedWayBiggerThan(number);
cout << "____OPTIMISED____\n";
cout << "Smallest palindrome = \n" << palindrome << '\n';
STOPCLOCK
PRINT_ELAPSED_TIME
cin.ignore();
}
If you don't need to perform any operations on that variable and can't use any libraries, including the C++ standard library, then use
const char* x = "1119191991900234245239919234772376189636415308431";
else the next best thing to use is a
std::string x = "1119191991900234245239919234772376189636415308431";
Even elementary arithmetic can be performed on such an encoding, the digit value at position n in the string is x[n] - '0'.
But all this is really rather silly. Suggest you look at the big number library that's part of the Boost distribution. See www.boost.org.

What's wrong with my dynamic programming algorithm with memoization?

*Sorry about my poor English. If there is anything that you don't understand, please tell me so that I can give you more information that 'make sence'.
**This is first time asking question in Stackoverflow. I've searched some rules for asking questions correctly here, but there should be something I missed. I welcome all feedback.
I'm currently solving algorithm problems to improve my skill, and I'm struggling with one question for three days. This question is from https://algospot.com/judge/problem/read/RESTORE , but since this page is in KOREAN, I tried to translate it in English.
Question
If there are 'k' pieces of partial strings given, calculate shortest string that includes all partial strings.
All strings consist only lowercase alphabets.
If there are more than 1 result strings that satisfy all conditions with same length, choose any string.
Input
In the first line of input, number of test case 'C'(C<=50) is given.
For each test case, number of partial string 'k'(1<=k<=15) is given in the first line, and in next k lines partial strings are given.
Length of partial string is between 1 to 40.
Output
For each testcase, print shortest string that includes all partial strings.
Sample Input
3
3
geo
oji
jing
2
world
hello
3
abrac
cadabra
dabr
Sample Output
geojing
helloworld
cadabrac
And here is my code. My code seems to work perfect with Sample Inputs, and when I made test inputs for my own and tested, everything worked fine. But when I submit this code, they say my code is 'wrong'.
Please tell me what is wrong with my code. You don't need to tell me whole fixed code, I just need sample inputs that causes error with my code. Added code description to make my code easier to understand.
Code Description
Saved all input partial strings in vector 'stringParts'.
Saved current shortest string result in global variable 'answer'.
Used 'cache' array for memoization - to skip repeated function call.
Algorithm I designed to solve this problem is divided into two function -
restore() & eraseOverlapped().
restore() function calculates shortest string that includes all partial strings in 'stringParts'.
Result of resotre() is saved in 'answer'.
For restore(), there are three parameters - 'curString', 'selected' and 'last'.
'curString' stands for currently selected and overlapped string result.
'selected' stands for currently selected elements of 'stringParts'. Used bitmask to make my algorithm concise.
'last' stands for last selected element of 'stringParts' for making 'curString'.
eraseOverlapped() function does preprocessing - it deletes elements of 'stringParts' that can be completly included to other elements before executing restore().
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
string answer; // save shortest result string
vector<string> stringParts;
bool cache[MAX + 1][(1 << MAX) + 1]; //[last selected string][set of selected strings in Bitmask]
void restore(string curString, int selected=0, int last=0) {
//base case 1
if (selected == (1 << k) - 1) {
if (answer.empty() || curString.length() < answer.length())
answer = curString;
return;
}
//base case 2 - memoization
bool& ret = cache[last][selected];
if (ret != false) return;
for (int next = 0; next < k; next++) {
string checkStr = stringParts[next];
if (selected & (1 << next)) continue;
if (curString.empty())
restore(checkStr, selected + (1 << next), next + 1);
else {
int check = false;
//count max overlapping area of two strings and overlap two strings.
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size()-i, i) == checkStr.substr(0, i)) {
restore(curString + checkStr.substr(i, checkStr.length()-i), selected + (1 << next), next + 1);
check = true;
break;
}
}
if (!check) { // if there aren't any overlapping area
restore(curString + checkStr, selected + (1 << next), next + 1);
}
}
}
ret = true;
}
//check if there are strings that can be completely included by other strings, and delete that string.
void eraseOverlapped() {
//arranging string vector in ascending order of string length
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
//deleting included strings
vector<string>::iterator iter;
for (int i = 0; i < vectorLen-1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C; // testcase
for (int testCase = 0; testCase < C; testCase++) {
cin >> k; // number of partial strings
memset(cache, false, sizeof(cache)); // initializing cache to false
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
eraseOverlapped();
k = stringParts.size();
restore("");
cout << answer << endl;
answer.clear();
stringParts.clear();
}
}
After determining which string-parts can be removed from the list since they are contained in other string-parts, one way to model this problem might be as the "taxicab ripoff problem" problem (or Max TSP), where each potential length reduction by overlap is given a positive weight. Considering that the input size in the question is very small, it seems likely that they expect a near brute-force solution, with possibly some heuristic and backtracking or other form of memoization.
Thanks Everyone who tried to help me solve this problem. I actually solved this problem with few changes on my previous algorithm. These are main changes.
In my previous algorithm I saved result of restore() in global variable 'answer' since restore() didn't return anything, but in new algorithm since restore() returns mid-process answer string I no longer need to use 'answer'.
Used string type cache instead of bool type cache. I found out using bool cache for memoization in this algorithm was useless.
Deleted 'curString' parameter from restore(). Since what we only need during recursive call is one previously selected partial string, 'last' can replace role of 'curString'.
CODE
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#define MAX 15
using namespace std;
int k;
vector<string> stringParts;
string cache[MAX + 1][(1 << MAX) + 1];
string restore(int selected = 0, int last = -1) {
if (selected == (1 << k) - 1) {
return stringParts[last];
}
if (last == -1) {
string ret = "";
for (int next = 0; next < k; next++) {
string resultStr = restore(selected + (1 << next), next);
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
string& ret = cache[last][selected];
if (!ret.empty()) {
cout << "cache used in [" << last << "][" << selected << "]" << endl;
return ret;
}
string curString = stringParts[last];
for (int next = 0; next < k; next++) {
if (selected & (1 << next)) continue;
string checkStr = restore(selected + (1 << next), next);
int check = false;
string resultStr;
for (int i = (checkStr.length() > curString.length() ? curString.length() : checkStr.length())
; i > 0; i--) {
if (curString.substr(curString.size() - i, i) == checkStr.substr(0, i)) {
resultStr = curString + checkStr.substr(i, checkStr.length() - i);
check = true;
break;
}
}
if (!check)
resultStr = curString + checkStr;
if (ret.empty() || ret.length() > resultStr.length())
ret = resultStr;
}
return ret;
}
void EraseOverlapped() {
int vectorLen = stringParts.size();
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].length() < stringParts[j].length()) {
string temp = stringParts[i];
stringParts[i] = stringParts[j];
stringParts[j] = temp;
}
}
}
vector<string>::iterator iter;
for (int i = 0; i < vectorLen - 1; i++) {
for (int j = i + 1; j < vectorLen; j++) {
if (stringParts[i].find(stringParts[j]) != string::npos) {
iter = stringParts.begin() + j;
stringParts.erase(iter);
j--;
vectorLen--;
}
}
}
}
int main(void) {
int C;
cin >> C;
for (int testCase = 0; testCase < C; testCase++) {
cin >> k;
for (int i = 0; i < MAX + 1; i++) {
for (int j = 0; j < (1 << MAX) + 1; j++)
cache[i][j] = "";
}
string inputStr;
for (int i = 0; i < k; i++) {
cin >> inputStr;
stringParts.push_back(inputStr);
}
EraseOverlapped();
k = stringParts.size();
string resultStr = restore();
cout << resultStr << endl;
stringParts.clear();
}
}
This algorithm is much slower than the 'ideal' algorithm that the book I'm studying suggests, but it was fast enough to pass this question's time limit.

Why my Shell sorting is so slow

I am trying to implement shell sorting algorithm myself. I wrote my own code and didn't watch to any code samples only watch the video of algorithm description
My sort works but very slow (bubble sort 100 items - 0.007 s; shell sort 100 items - 4.83 s), how is it possible to improve it?
void print(vector<float>vec)
{
for (float i : vec)
cout << i << " ";
cout << "\n\n";
}
void Shell_sorting(vector<float>&values)
{
int swapping = 0;
int step = values.size();
clock_t start;
double duration;
start = clock();
while (step/2 >= 1)
{
step /= 2;
for (int i = 0; i < values.size()-step; i++)
{
if ((i + step < values.size()))
{
if ((values[i + step] < values[i]))
{
swap(values[i], values[i + step]);
print(values);
++swapping;
int c = i;
while (c - step > 0)
{
if (values[c] < values[c - step])
{
swap(values[c], values[c - step]);
print(values);
++swapping;
c -= step;
}
else
break;
}
}
}
else
break;
}
}
duration = (clock() - start) / (double)CLOCKS_PER_SEC;
print(values);
cout << swapping << " " << duration;
print(values);
}
A better implementation could be:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec = {
726,621,81,719,167,958,607,130,263,108,
134,235,508,407,153,162,849,923,996,975,
250,78,460,667,654,62,865,973,477,912,
580,996,156,615,542,655,240,847,613,497,
274,241,398,84,436,803,138,677,470,606,
226,593,620,396,460,448,198,958,566,599,
762,248,461,191,933,805,288,185,21,340,
458,592,703,303,509,55,190,318,310,189,
780,923,933,546,816,627,47,377,253,709,
992,421,587,768,908,261,946,75,682,948,
};
std::vector<int> gaps = {5, 2, 1};
int j;
for (int gap : gaps) {
for (int i = gap; i < vec.size(); i++)
{
j = i-gap;
while (j >= 0) {
if (vec[j+gap] < vec[j])
{
int temp = vec[j+gap];
vec[j+gap] = vec[j];
vec[j] = temp;
j = j-gap;
}
else break;
}
}
}
for (int item : vec) std::cout << item << " " << std::endl;
return 0;
}
I prefer to use a vector to store gap data so that you do not need to compute the division (which is an expansive operation). Besides, this choice, gives your code more flexibility.
the extern loop cycles on gap values. Once choosen the gap, you iterate over your vector, starting from vec[gap] and explore if there are elements smaller then it according to the logic of the Shell Sort.
So, you start setting j=i-gap and test the if condition. If it is true, swap items and then repeat the while loop decrementing j. Note: vec[j+gap]is the element that in the last loop cycle was swapped. If the condition is true, there's no reason to continue in the loop, so you can exit from it with a break.
On my machine, it took 0.002s calculated using the time shell command (the time includes the process of printing numbers).
p.s. to generate all that numbers and write them in the array, since i'm too lazy to write a random function, i used this link and then i edited the output in the shell with:
sed -e 's/[[:space:]]/,/g' num | sed -e 's/$/,/'

Unexpected Output While Using Threads

I am working on a proof of concept test program for a game where certain actions are threaded and information is output to the command window for each thread. So far I have gotten the basic threading process to work but it seems that the couting in my called function is not being written for each thread and instead each thread is overwriting the others output.
The desired or expected output is that each thread will output the information couted within the mCycle function of mLaser. Essentially this is meant to be a timer of sorts for each object counting down the time until that object has completed its task. There should be an output for each thread, so if five threads are running there should be five counters counting down independently.
The current output is such that each thread is outputting its own information with in the same space which then overwrites what another thread is attempting to output.
Here is an example of the current output of the program:
Time until cycle Time until cycle 74 is complete: 36 is complete:
92 seconds 2 seconds ress any key to continue . . .
You can see the aberrations where numbers and other text are in places they should not be if you examine how the information is couted from mCycle.
What should be displayed is more long these lines:
Time until cycle 1 is complete:
92 seconds
Time until cycle 2 is complete:
112 seconds
Time until cycle 3 is complete:
34 seconds
Cycle 4 has completed!
I am not sure if this is due to some kind of thread locking going on due to how my code is structured or just an oversight in my coding for the output. If I could get a fresh pair of eyes to look over the code and point anything out that could be the fault I would appreciate it.
Here is my code, it should be compilable in any MSVS 2013 install (no custom libraries used)
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>
using namespace std;
class mLaser
{
public:
mLaser(int clen, float mamt)
{
mlCLen = clen;
mlMAmt = mamt;
}
int getCLen()
{
return mlCLen;
}
float getMAmt()
{
return mlMAmt;
}
void mCycle(int i1, int mCLength)
{
bool bMCycle = true;
int mCTime_left = mCLength * 1000;
int mCTime_start = GetTickCount(); //Get cycle start time
int mCTime_old = ((mCTime_start + 500) / 1000);
cout << "Time until cycle " << i1 << " is complete: " << endl;
while (bMCycle)
{
cout << ((mCTime_left + 500) / 1000) << " seconds";
bool bNChange = true;
while (bNChange)
{
//cout << ".";
int mCTime_new = GetTickCount();
if (mCTime_old != ((mCTime_new + 500) / 1000))
{
//cout << mCTime_old << " " << ((mCTime_new+500)/1000) << endl;
mCTime_old = ((mCTime_new + 500) / 1000);
mCTime_left -= 1000;
bNChange = false;
}
}
cout << " \r" << flush;
if (mCTime_left == 0)
{
bMCycle = false;
}
}
cout << "Mining Cycle " << i1 << " finished" << endl;
system("Pause");
return true;
}
private:
int mlCLen;
float mlMAmt;
};
string sMCycle(mLaser ml, int i1, thread& thread);
int main()
{
vector<mLaser> mlasers;
vector<thread> mthreads;
future<string> futr;
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> laser(1, 3);
uniform_int_distribution<> cLRand(30, 90);
uniform_real_distribution<float> mARand(34.0f, 154.3f);
int lasers;
int cycle_time;
float mining_amount;
lasers = laser(gen);
for (int i = 0; i < lasers-1; i++)
{
mlasers.push_back(mLaser(cLRand(gen), mARand(gen)));
mthreads.push_back(thread());
}
for (int i = 0; i < mlasers.size(); i++)
{
futr = async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); });
//mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
}
for (int i = 0; i < mthreads.size(); i++)
{
//mthreads.at(i).join();
}
//string temp = futr.get();
//float out = strtof(temp.c_str(),NULL);
//cout << out << endl;
system("Pause");
return 0;
}
string sMCycle(mLaser ml, int i1, thread& t1)
{
t1 = thread(bind(&mLaser::mCycle, ref(ml), ml.getCLen(), ml.getMAmt()));
//t1.join();
return "122.0";
}
Although writing from multiple threads concurrently to std::cout has to be data race free, there is no guarantee that concurrent writes won't be interleaved. I'm not sure if one write operation of one thread can be interleaved with one write operation from another thread but they can certainly be interleaved between write operations (I think individual outputs from different threads can be interleaved).
What the standard has to say about concurrent access to the standard stream objects (i.e. std::cout, std::cin, etc.) is in 27.4.1 [iostream.objects.overview] paragraph 4:
Concurrent access to a synchronized (27.5.3.4) standard iostream object’s formatted and unformatted input (27.7.2.1) and output (27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (1.10). [ Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. —end note ]
If you want to have output appear in some sort of unit, you will need to synchronize access to std::cout, e.g., by using a mutex.
While Dietmar's answer is sufficient I decided to go a different, much more simple, route. Since I am creating instances of a class and I am accessing those instances in the threads, I chose to update those class' data during the threading and then called the updated data once the thread have finished executing.
This way I do not have to deal with annoying problems like data races nor grabbing output from async in a vector of shared_future. Here is my revised code in case anyone else would like to implement something similar:
#include <iostream>
#include <Windows.h>
#include <string>
#include <vector>
#include <random>
#include <thread>
#include <future>
using namespace std; //Tacky, but good enough fo a poc D:
class mLaser
{
public:
mLaser(int clen, float mamt, int time_left)
{
mlCLen = clen;
mlMAmt = mamt;
mCTime_left = time_left;
bIsCompleted = false;
}
int getCLen()
{
return mlCLen;
}
float getMAmt()
{
return mlMAmt;
}
void setMCOld(int old)
{
mCTime_old = old;
}
void mCycle()
{
if (!bIsCompleted)
{
int mCTime_new = GetTickCount(); //Get current tick count for comparison to mCOld_time
if (mCTime_old != ((mCTime_new + 500) / 1000)) //Do calculations to see if time has passed since mCTime_old was set
{
//If it has then update mCTime_old and remove one second from mCTime_left.
mCTime_old = ((mCTime_new + 500) / 1000);
mCTime_left -= 1000;
}
cur_time = mCTime_left;
}
else
{
mCTime_left = 0;
}
}
int getCTime()
{
return cur_time;
}
int getCTLeft()
{
return mCTime_left;
}
void mCComp()
{
bIsCompleted = true;
}
bool getCompleted()
{
return bIsCompleted;
}
private:
int mlCLen; //Time of a complete mining cycle
float mlMAmt; //Amoung of ore produced by one mining cycle (not used yet)
int cur_time; //The current time remaining in the current mining cycle; will be removing this as it is just a copy of mCTime_left that I was going to use for another possiblity to make this code work
int mCTime_left; //The current time remaining in the current mining cycle
int mCTime_old; //The last time that mCycle was called
bool bIsCompleted; //Flag to check if a mining cycle has already been accounted for as completed
};
void sMCycle(mLaser& ml, int i1, thread& _thread); //Start a mining cycle thread
//Some global defines
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> laser(1, 10); //A random range for the number of mlaser entities to use
uniform_int_distribution<> cLRand(30, 90); //A random time range in seconds of mining cycle lengths
uniform_real_distribution<float> mARand(34.0f, 154.3f); //A random float range of the amount of ore produced by one mining cycle (not used yet)
int main()
{
//Init some variables for later use
vector<mLaser> mlasers; //Vector to hold mlaser objects
vector<thread> mthreads; //Vector to hold threads
vector<shared_future<int>> futr; //Vector to hold shared_futures (not used yet, might not be used if I can get the code working like this)
int lasers; //Number of lasers to create
int cycle_time; //Mining cycle time
int active_miners = 0; //Number of active mining cycle threads (one for each laser)
float mining_amount; //Amount of ore produced by one mining cycle (not used yet)
lasers = laser(gen); //Get a random number
active_miners = lasers; //Set this to that random number for the while loop later on
//Create the mlaser objects and push them into the mlasers vector
for (int i = 0; i < lasers; i++)
{
int clength = cLRand(gen);
mlasers.push_back(mLaser(clength, mARand(gen), (clength * 1000)));
//Also push thread obects into mthreads for each laser object
mthreads.push_back(thread());
}
//Setup data for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
int mCTime_start = GetTickCount(); //Get cycle start time
mlasers.at(i).setMCOld(((mCTime_start + 500) / 1000));
}
//Print initial display for mining cycles
for (int i = 0; i < mlasers.size(); i++)
{
cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds..." << endl;
}
while (active_miners > 0)
{
for (int i = 0; i < mlasers.size(); i++)
{
//futr.push_back(async(launch::async, [mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }));
async(launch::async, [&mlasers, i, &mthreads]{return sMCycle(mlasers.at(i), i + 1, mthreads.at(i)); }); //Launch a thread for the current mlaser object
//mthreads.at(i) = thread(bind(&mLaser::mCycle, ref(mlasers.at(i)), mlasers.at(i).getCLen(), mlasers.at(i).getMAmt()));
}
//Output information from loops
//cout << " \r" << flush; //Return cursor to start of line and flush the buffer for the next info
system("CLS");
for (int i = 0; i < mlasers.size(); i++)
{
if (mlasers.at(i).getCTLeft() != 0) //If mining cycle is not completed
{
cout << "Mining Laser " << i + 1 << " cycle will complete in " << (mlasers.at(i).getCTLeft() + 500) / 1000 << " seconds..." << endl;
}
else if (mlasers.at(i).getCTLeft() == 0) //If it is completed
{
if (!mlasers.at(i).getCompleted())
{
mlasers.at(i).mCComp();
active_miners -= 1;
}
cout << "Mining Laser " << i + 1 << " has completed its mining cycle!" << endl;
}
}
}
/*for (int i = 0; i < mthreads.size(); i++)
{
mthreads.at(i).join();
}*/
//string temp = futr.get();
//float out = strtof(temp.c_str(),NULL);
//cout << out << endl;
system("Pause");
return 0;
}
void sMCycle(mLaser& ml, int i1,thread& _thread)
{
//Start thread
_thread = thread(bind(&mLaser::mCycle, ref(ml)));
//Join the thread
_thread.join();
}