I'm working on a markov chain and have created a 2d hashmap that calculates the weighted probabilities. The output of this works fine.
I'm looking to find the best way to output the next value. The way I have it at the moment isn't working properly. Ent1.first is the incoming midiNote. Ent2.first is the potential outgoing value and Ent2.second is the weighted probability.
When midiNotecomes in, I need to look into the table and find the weighted probabilities and using rand() pick the next value. One problem is that I only need this to happen once, not for every time in the for loop. Here is a snippet of my table calculation for simplicity's sake, but if you'd like me to post the entire code let me know.
void getCountTable(int midiNote) {
for(auto const &ent1: cdf) {
midiNote = ent1.first;
for (auto const &ent2: ent1.second) {
//console out all resulting note transition weights
//std::cout << "Note: " << ent1.first << std::endl <<"Next note: " << ent2.first <<std::endl << "Weight: " << ent2.second << std::endl << std::endl;
//TRYING TO FIGURE HOW TO HANDLE THIS. JUST WANT TO HAPPEN ONCE FOR EACH INCOMING VALUE
//psuedo-random values between 0-1
float r = static_cast <float> (rand()) / static_cast<float> (RAND_MAX);
//calculate next value
if (r < ent2.second) {
int output = ent2.first;
std::cout << ent1.first << " " << output << std::endl;
}
}
}
}
Currently you are creating a new random number each time around your inner loop and comparing it with the chance for that possibility. This will mean that sometimes one item will match (good), but sometimes you will get zero or two or more items matching (it is random).
One way to pick the just one possibility out of all the options is to generate one random number, then loop through the possibilities until the sum of all the possibilities so far is greater than the random number that you have generated.
Rearranging your code (untested)
midiNote = ent1.first;
//psuedo-random values between 0-1
float r = static_cast <float> (rand()) / static_cast<float> (RAND_MAX);
float sum = 0;
int output = 0;
for (auto const &ent2: ent1.second){
sum += ent2.second;
if (sum >= r) {
output = ent2.first;
std::cout << ent1.first << " " << output << std::endl;
break;
}
}
This should work, although given the inexactness of floating point additions, it might be worth defaulting output to the last item of ent1.second if nothing is found (e.g. this might happen if sum ends up at 0.999, but r was 0.9999)
I've found there needs to be a comparison between the map and the incoming midi value. Also changed the probabilities to the first entry in the second map and the resulting output as the second entry. Modified some and provided all below.
void nextNote(int midiNote){
float r = static_cast <float> (rand()) / static_cast<float> (RAND_MAX);
int output = 0;
float sum = 0;
for (auto const & ent1: cdf){
if(ent1.first == midiNote){
for (auto const & ent2: ent1.second){
sum+= ent2.first;
std::cout <<sum << std::endl;
if(sum >= r){
output = ent2.second;
std::cout << output <<std::endl;
break;
}
}
}
}
}
Related
I was trying to sort the areas of a circle in an ascending order. First, the user chooses the number of circles, then he should type the coordinates and the area of his circles. In the end the program should output the radius of a circle in an ascending order.But the output of areas is not in an ascending order(It's the same as input). What is my problem?
#include<iostream>
#include <algorithm>
using namespace std;
struct circle {
int 반지름;
int coordinates;
int coordinates2;
};
bool compare(circle a, circle b){
if(a.반지름 < b.반지름)
return 1;
else
return 0;
}
int main()
{
int n = 1;
int* ptr1;
ptr1 = new int;
circle* circle1;
circle1 = new (nothrow) circle[5];
circle1[0].반지름;
circle1[0].coordinates;
circle1[0].coordinates2;
circle1[1].반지름;
circle1[1].coordinates;
circle1[1].coordinates2;
circle1[2].반지름;
circle1[2].coordinates;
circle1[2].coordinates2;
circle1[3].반지름;
circle1[3].coordinates;
circle1[3].coordinates2;
circle1[4].반지름;
circle1[4].coordinates;
circle1[4].coordinates2;
circle1[5].반지름;
circle1[5].coordinates;
circle1[5].coordinates2;
cout << "Enter the number of circles: ";
cin >> *ptr1;
cout << "중심 좌표, 반지름 : " << endl;
for (int i = 0; i < *ptr1; i++) {
cin >> circle1[i].coordinates >> circle1[i].coordinates2 >> circle1[i].반지름;
}
sort(circle1, circle1 + 1, compare);
for (int i = 0; i < *ptr1; i++) {
cout << "The result: " << circle1[i].coordinates << " " << circle1[i].coordinates2 << " " << circle1[i].반지름 << endl;
}
delete[] circle1;
delete ptr1;
return 0;
}
That's not C++, that's a strange and hybrid thing between C and C++... And this is your main problem. You're mixing up things that should not be mixed, not if you don't know PERFECLY what you do - and obviously, it's not the case, otherwise your code should have worked, and it haven't.
Corrected code, in real C++:
#include <iostream> // std::cout & co
#include <algorithm> // std::sort
#include <cstdlib> // std::rand & co
#include <vector> // std::vector
struct circle {
int area ;
int x ;
int y ;
} ;
// For printing a circle easily and not repeat code X times.
// Print as: [area#(x,y)]
std::ostream& operator<<(std::ostream& os, const circle& c) {
os << "[" << c.area << "#(" << c.x << "," << c.y << ")]" ;
return os;
}
int main() {
// Set a constant seed: each run will produce the same result, if needed to debug.
std::srand(1234) ;
// 5 circles declared within a vector, not a C array.
auto circles = std::vector<circle>(5) ;
// Fill the vector.
std::cout << "Original circles:" << std::endl ;
// Use a simpler for syntax.
for ( auto& c: circles ) {
// Random values used. The fixed seed will always give the same values on each run.
c.area = 10 + std::rand() % 50 ;
c.x = std::rand() % 1920 ;
c.y = std::rand() % 1080 ;
// Print the circle.
std::cout << "\t" << c << std::endl ;
}
// Sort the vector, use a lambda expression for the compare operator.
// No need for a "real" function, if it's used only once and only there.
// Compare function returns directly a bool, not an integer.
std::sort(circles.begin(), circles.end(), [](const circle& a, const circle& b) -> bool { return (a.area<b.area) ; });
// Display sorted vector.
std::cout << std::endl << "Sorted circles:" << std::endl ;
for ( const auto& c: circles )
std::cout << "\t" << c << std::endl ;
return 0;
}
Still strange that you use area instead of radius or diameter, but anyway... Area is for a disc, not a circle, but that's mathematical precision at this stage.
First, if you print a structure like circle at least twice, do a stream operator to do it only once. Please note that I send directly the structure to std::cout, after...
Then, I use a C++ container, not a C allocated array. You can still allocate memory for big amount of data, but for this example, that's unneeded.
Then, instead of asking for each values, I use std::rand() to fill them. Easier. Can be used in any language. Refined trick: I initialize the pseudo-random generator to a constant, fixed value, so each time the program is run, it will generate the exact same sequence of pseudo-random numbers - this can vary on each machine / OS / compiler / compiler version but it will be constant on YOUR machine during your tests, and it can be debugged easily.
Please also note that I use a compact form of for that will iterate on the whole circles container, giving me each time a circle& (reference) on each element so that I can modify it - needed for initialization.
Now, the sort itself: from begin() to end() of the container, using a lambda expression to define the compare operator. Please note that I return directly the result of the comparison, which is a bool, and that I don't cast an int to a bool implicitely...
Finally, print the result. Note that this time, I ask for a const auto& reference, to be sure to not modify data by mistake.
Nothing to delete, C++ will take care of that.
An example output, on my machine:
Original circles:
[28#(213,881)]
[18#(16,157)]
[34#(1468,816)]
[14#(745,718)]
[31#(143,818)]
Sorted circles:
[14#(745,718)]
[18#(16,157)]
[28#(213,881)]
[31#(143,818)]
[34#(1468,816)]
I've an array of 2500 steps taken by a robot, each step taken in a random direction (up, down, right, or left). I'm supposed to store the Euclidian distance (a right triangle's hypotenuse) of each step from the robot's origin. No problem there.
I'm also supposed to keep tabs on the max. Euclidian distance the robot reaches, so if the current distance is greater than one of the previous ones, the current one becomes the new greatest distance. Here's my code:
int main(){
int steps[2500];
int randDir[2500];
int coords[2] = {0,0};
int path[2500][2];
double eucliDist[2500];
eucliDist[0] = 1;
double maxEucliDist;
double taxiDist;
for (int i = 0; i < 2500; i++){
randDir[i] = rand() % 4;
steps[i] = i + 1;
switch(randDir[i]){
case 0:
coords[0] = coords[0] + 1;
break;
case 1:
coords[1] = coords[1] + 1;
break;
case 2:
coords[0] = coords[0] - 1;
break;
case 3:
coords[1] = coords[1] - 1;
break;
}
eucliDist[i] = sqrt((pow(coords[0],2)) + (pow(coords[1],2)));
if (eucliDist[i] > eucliDist[i-1]){
maxEucliDist = eucliDist[i]; //need to fix this. Not showing true max Euclid. Dist.
taxiDist = abs(coords[0]) + abs(coords[1]);
}
//cout << "Step " << steps[i] << " Euclidian distance from origin is: " << eucliDist[i] <<endl; //check euclidian dist each step
//cout << steps[i] << "\t Coords (" << coords[0] << ", " << coords[1] << ")" << "\n"; //check coords with each step
}
cout << "Final Coordinates: (" << coords[0] << ", " << coords[1] << ")" << endl;
cout << "Maximum Euclidian distance was: " << maxEucliDist << endl;
cout << "'Taxicab' distance is: " << taxiDist << endl;
cin.get();}
Problem is that my output shows the wrong max, as shown in the snippet of my output below:
Program output showing incorrect maximum Euclidian distance
FYI, "taxicab" distance is the distance a 2nd robot would have to take to get to the 1st robot's position at max distance if it needed to (it's a right triangle's base + height since traveling on a grid).
Not sure what I'm doing wrong. Might have something to do with my if-statement in the bottom half of the code.
Any thoughts?
Your problem is indeed your if-statement:
if (eucliDist[i] > eucliDist[i-1]){ // THIS IS WRONG
maxEucliDist = eucliDist[i]; // THIS IS ACTUALLY OK
taxiDist = abs(coords[0]) + abs(coords[1]);
}
You're comparing your current distance to the distance in the PREVIOUS frame, not your maximum. You also need to initialize your maximum to zero, since it needs something to start with too, or else your comparison will be "current" versus "garbage". C++ does not initialize local variables to zero.
Your new if-statement should be this:
if (eucliDist[i] > maxEucliDist){
maxEucliDist = eucliDist[i];
taxiDist = abs(coords[0]) + abs(coords[1]);
}
Your first job is to recognise that the square of a positive number is a monotonic function of the number. So stop taking those square roots all over the place (which are difficult for a computer to evaluate), and work in distance squared, until you come to display the final result.
Then you can replace the nasty pow(x, 2) functions with x * x and work in integer arithmetic. (Take steps to avoid overflowing an int though.). This will be at least an order of magnitude faster.
Your specific issue is a logic error in that you are only comparing your new distance with the previous one, not the minimum found thus far.
I have 3 vectors, category description and price I have written this piece of code to put the vectors organised by category into a file called menuFile:
for(int x = 0; x < _category.size(); x++){
if(_category[x].compare("Starter") == 0){
menuFile << _category[x] << ":" << _description[x] << ":" << _price[x] << endl;
}
}
for(int x = 0; x < _category.size(); x++){
if(_category[x].compare("Main") == 0){
menuFile << _category[x] << ":" << _description[x] << ":" << _price[x] << endl;
}
}
for(int x = 0; x < _category.size(); x++){
if(_category[x].compare("Pudding") == 0){
menuFile << _category[x] << ":" << _description[x] << ":" << _price[x] << endl;
}
}
for(int x = 0; x < _category.size(); x++){
if(_category[x].compare("Drink") == 0){
menuFile << _category[x] << ":" << _description[x] << ":" << _price[x] << endl;
}
}
But this does not seem like a very efficient method. Is the a better way to do this?
I believe you should create a struct to handle the three types of data and then make a vector for it.
for example:
struct Menu {
string category;
string description;
int price;
};
then i would recommend you to implement a comparator to decide on how to sort the data. Let's say sort by the price (You can decide on how to implement the overloaded operator of course).
struct Menu {
string category;
string description;
int price;
bool operator < (const Menu& rhs) const {
return (this->price < rhs.price);
}
};
then just make a vector for this struct and sort it.
vector<Menu> menu;
// do something, insert data
sort(menu.begin(),menu.end());
Then output accordingly.
for(int x = 0; x < menu.size(); x++){
menuFile << menu[x].category << ":" << menu[x].description << ":" << menu[x].price << endl;
}
I don't know what your container types are, so I'm going to assume std::string. The simplest thing might be to just make a separate vector of tuples:
using StrTuple = std::tuple<std::string*, std::string*, std::string*>;
std::vector<StrTuple> combined;
for (size_t i = 0; i < _category.size(); ++i) {
combined.emplace_back(&_category[i], &_description[i], &_price[i]);
}
And then sort that one by category:
std::sort(std::begin(combined), std::end(combined),
[](const StrTuple& lhs, const StruTuple& rhs) {
return *std::get<0>(lhs) < *std::get<0>(rhs);
});
And then just stream it in order:
for (auto& t : combined) {
menuFile << *std::get<0>(t) << ":" << *std::get<1>(t) << ":" << *std::get<2>(t) << std::endl;
}
The same could be achieved with a separate type instead, something like:
struct CombinedValues {
std::string *category, *description, *price;
};
I do not think there is a much more efficient algorithm to do that. You may think so because you do 4 loop with the same thing. But you are still doing O(n) efficiency. Adding a sort operation like some proposition above would add a step running at O(n*log(n)) efficiency, which is way worse.
You still need the 4 loops, so the only thing we can try to optimize is the testing, that is replacing the string compare() operation in each loop by something faster. Something possible would be to replace the string test by an integer test, meaning pre-computing a category number in a new vector (i.e. a value 0 if category=="Starter", 1 if "Main", etc and a value different from 0..3 if not any of the interesting category (if that is possible)
That would mean an initial loop to compute this category, which can be made more efficient (using an average of 2 string comparison). Or even less using a hash map of the category string.
So in the loops, we just do an integer comparison instead of a string comparison for each element. However, we add the time to compute the category number in the first loop. It is not obvious at first glance which will be faster: 4 loops and 4*n string comparisons or 4 loops, 2*n string comparisons and 4*n integer comparisons. That may be faster, if comparing strings are much more costly than comparing integers.
For this kind of stuff, only way to know is to measure actual execution time. Obviously, all this is time consuming, so only to be done if this is really necessary (i.e. your profiler tells you that this part needs to be optimized)
I want to increment a double value from the smallest possible (negative) value it can take to the largest possible value it can take.
I've started off with this:
int main()
{
double min(numeric_limits<double>::min());
double i(min);
while(i < 0);
{
cout << i << endl;
i += min ;
}
}
Unfortunately, this doesn't produce the desired result - the while loop is skipped after one iteration.
Is there a better way to accomplish my goal?
I'm guessing at what you want from your code: You want to start with largest possible negative value and increment it toward positive infinity in the smallest possible steps until the value is no longer negative.
I think the function you want is nextafter().
int main() {
double value(-std::numeric_limits<double>::max());
while(value < 0) {
std::cout << value << '\n';
value = std::nextafter(value,std::numeric_limits<double>::infinity());
}
}
Firstly,
while(i < 0); // <--- remove this semicolon
{
cout << i << endl;
i += min ;
}
Then, std::numeric_limits<double>::min() is a positive value, so i < 0 will never be true. If you need the most negative value, you'll need
double min = -std::numeric_limits<double>::max();
but I don't know what your i += min line is supposed to do. Adding two most negative number will just yield −∞, and the loop will never finish. If you want to add a number, you'll need another variable, like
double most_negative = -std::numeric_limits<double>::max();
double most_positive = std::numeric_limits<double>::max();
double i = most_negative;
while (i < 0)
{
std::cout << i << std::endl;
i += most_positive;
}
Of course this will just print the most negative number (-1.8e+308), and then i becomes 0 and the loop will exit.
The following runs through all float-values 'in order'. The steps between successive values become smaller as u.mind increases.
No guarantee this is correct and it will take a long time to complete and this isn't portable and it will take even longer for doubles and... etc. etc.
#include <cassert>
#include <iostream>
#include <limits>
union umin {
float mind;
int mini;
} u;
int main()
{
u.mind = std::numeric_limits<float>::max();
std::cout << -u.mind << " " << u.mini << std::endl;
while ( u.mind > 0 ) {
float previous = u.mind;
u.mini -= 1;
std::cout << -u.mind << " " << u.mini << " " << previous - u.mind << std::endl;
assert( previous > u.mind );
}
}
I have a homework problem for my C++ class and the problem wants us to have the user input a wavelength and then output the correct type of radiation. The point to notice is that there are more Wave Name values than there are Wave Lengths.
My solution is listed below:
const double WAVE_LENGTH[] = { 1e-11, 1e-8, 4e-7, 7e-7, 1e-3, 1e-2 };
const char* WAVE_NAME[] = { "Gamma Rays", "X Rays", "Ultraviolet", "Visible Light", "Infrared", "Microwaves", "Radio Waves" };
double waveLength;
std::cout << "Enter a wavelength in decimal or scientific notation\nWavelength: ";
std::cin >> waveLength;
for (unsigned short i = 0U; i < 6U; ++i)
{
if (waveLength < WAVE_LENGTH[i])
{
std::cout << "The type of radiation is " << WAVE_NAME[i] << std::endl;
break;
}
if (i == 5U) // Last iteration
std::cout << "The type of radiation is " << WAVE_NAME[i + 1] << std::endl;
}
My question is regarding my approach at solving the problem, specifically within the loop. I can't seem to find a way to handle all the situations without creating two conditions inside the loop which seems like it is a poor design. I realize I could use a series of if/else if statements, but I figured a loop is cleaner. Is my approach the best way or is there a cleaner way of coding this?
Thanks!
I think you can simplify your loop to this:
unsigned short i;
for (i = 0U; i < 6U; ++i)
{
if (waveLength < WAVE_LENGTH[i])
{
break;
}
}
std::cout << "The type of radiation is " << WAVE_NAME[i] << std::endl;
In my view a somewhat cleaner design is to add positive infinity as the last element of WAVE_LENGTH. This way your corner case will require no special handling:
#include <iostream>
#include <limits>
...
const double WAVE_LENGTH[] = { 1e-11, 1e-8, 4e-7, 7e-7, 1e-3, 1e-2,
std::numeric_limits<double>::infinity() };
const char* WAVE_NAME[] = { "Gamma Rays", "X Rays", "Ultraviolet", "Visible Light",
"Infrared", "Microwaves", "Radio Waves" };
double waveLength;
std::cout << "Enter a wavelength in decimal or scientific notation\nWavelength: ";
std::cin >> waveLength;
for (int i = 0; i < sizeof(WAVE_LENGTH) / sizeof(WAVE_LENGTH[0]); ++i)
{
if (waveLength < WAVE_LENGTH[i])
{
std::cout << "The type of radiation is " << WAVE_NAME[i] << std::endl;
break;
}
}
Also note how I've avoided having to hard-code the length of the array (6U in your code) in the loop's terminal condition.
You can test the last iteration in the same if. Notice there is no test anymore itn for.
for (unsigned short i = 0U; ; ++i)
{
if (i == 6 || waveLength < WAVE_LENGTH[i])
{
std::cout << "The type of radiation is " << WAVE_NAME[i] << std::endl;
break;
}
}
Alternatively, you can add a extra wavelength set to MAX_FLOAT (or whatever is called in C++) or set the last one to zero and exit if wave_length[i] == 0.0. That way you don't need to "know" the number of wave lengths.