CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    Jun 2012
    Posts
    15

    Glass Rod Problem

    I'm working on a project, and can't seem to get the project to get the triangle variable to increase when the conditions are met. I need this number to be accurate so I can work out the probability. Below you'll find the project, and my amateurish code. Any help is appreciated.


    Problem
    Experiments that are either too expensive or too dangerous to perform are often simulated on a computer when the computer is able to provide a good representation of the experiment. Find out how to call the random-number generator (usually a function returning a floating point value in the range 0 to 1) for your C++ system. (Look up the functions rand and srand in the library cstdlib on the website cplusplus.com). Write a program that uses the random-number generator to simulate the dropping of glass rods that break into three pieces. The purpose of the experiment is to estimate the probability that the lengths of the three pieces are such that they might form the sides of a triangle.
    For the purposes of this experiment, you may assume that the glass rod always breaks into three pieces. If you use the line segment 0 to 1 (on the real number line) as a mathematical model of the glass rod, a random-number generator (function) can be used to generate two numbers between 0 and 1 representing the coordinates of the breaks. The triangle inequality (the sum of the lengths of two sides of a triangle are always greater than the length of the third side) may be used to test the length of each piece against the lengths of the other two pieces.
    To estimate the probability that the pieces of the rod form a triangle, you’ll need to repeat the experiment many times and count the number of times a triangle can be formed from the pieces. The probability estimate is the number of successes divided by the total number of rods dropped. Your program should prompt the user for the number of rods to drop and allow the experiment to be repeated. Use a sentinel value of 21 to hale execution of the program.

    Code:
    Code:
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <cfloat>
    #include <iomanip>
    #include <stdlib.h>
    #include <time.h>
    
    using namespace std;
    
    float doBreak (float, float);
    float doProbability (float, float);
    
    const int SENTINEL = 21;		//sentinal value
    
    int main()
    {
    	float break1;
    	float break2;
    	float side1;
    	float side2;
    	float side3;
    	float count;
    	float tests;
    	float triangle;
    	float probability;
    
    	const int SENTINEL = 21;
    	count = 1;
    	srand (time (NULL));
    
    	cout << "Enter number of glassrods to demolish (Enter 21 to end program): ";
    	cin >> tests;
    
    	if 
    	(tests != SENTINEL)
    	{
    		do
    		{
    			doBreak(break1, break2);
    			count++;
    		}while (count <= tests);
    
    	doProbability(triangle, tests);
    	cout << "The probability that the broken glass rods will form a triangle is: " << probability << "%" << endl;
    	}
    	else
    	{
    			cout << "Aww, I was hoping to break stuff..." << endl;
    	}
    	return 0;
    }
    
    float doBreak
    	(float break1, 
    	float break2)
    {
    	float side1;
    	float side2;
    	float side3;
    	float triangle;
    	triangle = 0;
    		
    	break1 = (float)rand()/RAND_MAX;
    	break2 = (float)rand()/RAND_MAX;
    	
    	if (break1 < break2)
    	{
    		side1 = break1;
    		side2 = (break2 - break1);
    		side3 = 1 - break2;
    	}
    	else if (break2 < break1)
    	{	
    		side1 = break2;
    		side2 = (break1 - break2);
    		side3 = 1 - break1;
    	}
    	else
    	{
    		side1 = break1;
    		side2 = break1;
    		side3 = break1;
    	}
    	if
    	((side1 + side2) > side3 &&
    	(side1 + side3) > side2 &&
    	(side2 + side3) > side1)
    	{
    		triangle += 1;
    		cout << triangle << endl;
    	}
    	return side1;
    	return side2;
    	return side3;
    	return triangle;
    }
    	
    float doProbability 
    	(float triangle,
    	float tests)
    {
    	float probability;
    
    	probability = (triangle / tests) * 100;
    	return probability;
    }

  2. #2
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Glass Rod Problem

    The variable "triangle" is local to your doBreak function. You need to have declare it in main and increment it depending on what doBreak returns.

  3. #3
    Join Date
    Jun 2009
    Location
    France
    Posts
    2,513

    Re: Glass Rod Problem

    Quote Originally Posted by CoryMore View Post
    Code:
    float doBreak (float, float);
    float doProbability (float, float);
    
    const int SENTINEL = 21;		//sentinal value
    
    int main()
    {
    	float break1;
    	float break2;
    	float side1;
    	float side2;
    	float side3;
    	float count;
    	float tests;
    	float triangle;
    	float probability;
    
    	const int SENTINEL = 21;
    	count = 1;
    	srand (time (NULL));
    
    	cout << "Enter number of glassrods to demolish (Enter 21 to end program): ";
    	cin >> tests;
    
    	if 
    	(tests != SENTINEL)
    	{
    		do
    		{
    			doBreak(break1, break2);
    			count++;
    		}while (count <= tests);
    
    	doProbability(triangle, tests);
    	cout << "The probability that the broken glass rods will form a triangle is: " << probability << "%" << endl;
    	}
    	else
    	{
    			cout << "Aww, I was hoping to break stuff..." << endl;
    	}
    	return 0;
    }
    
    float doBreak
    	(float break1, 
    	float break2)
    {
    	float side1;
    	float side2;
    	float side3;
    	float triangle;
    	triangle = 0;
    		
    	break1 = (float)rand()/RAND_MAX;
    	break2 = (float)rand()/RAND_MAX;
    	
    	if (break1 < break2)
    	{
    		side1 = break1;
    		side2 = (break2 - break1);
    		side3 = 1 - break2;
    	}
    	else if (break2 < break1)
    	{	
    		side1 = break2;
    		side2 = (break1 - break2);
    		side3 = 1 - break1;
    	}
    	else
    	{
    		side1 = break1;
    		side2 = break1;
    		side3 = break1;
    	}
    	if
    	((side1 + side2) > side3 &&
    	(side1 + side3) > side2 &&
    	(side2 + side3) > side1)
    	{
    		triangle += 1;
    		cout << triangle << endl;
    	}
    	return side1;
    	return side2;
    	return side3;
    	return triangle;
    }
    	
    float doProbability 
    	(float triangle,
    	float tests)
    {
    	float probability;
    
    	probability = (triangle / tests) * 100;
    	return probability;
    }
    Two quick things:

    1) Don't use floating point counters: Floating points are inexact by design. Your loops may end up doing funky things.
    2) What's with the multiple returns? This isn't doing what you think it is.
    3) Your whole "if-do-while" could be replaced by a single much simpler for loop
    4) Are you sure about that last else? Sounds like the sum of the pieces might be != from 1

    I'll give you some design help later.
    Is your question related to IO?
    Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
    It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.

  4. #4
    Join Date
    May 2009
    Posts
    2,413

    Re: Glass Rod Problem

    Quote Originally Posted by CoryMore View Post
    Experiments that are either too expensive or too dangerous to perform are often simulated on a computer when the computer is able to provide a good representation of the experiment.
    I became interested in the Glass Rod problem and I calculated the theoretical probability to 1/4. That is in 25 percent of the cases the rod breaks to form a triangle. I think you got the logic of the doBreak function right so I just modified it a little.

    In my version doBreak generates two random numbers and then returns true if it became a triangle, otherwise false. Here's the code (and the triangle fraction is around 0.25 indeed),

    Code:
    bool doBreak() {
       float break1 = (float)rand()/RAND_MAX;
       float break2 = (float)rand()/RAND_MAX;
    
       float side1, side2, side3;	
       if (break1 < break2) {
          side1 = break1;
          side2 = (break2 - break1);
          side3 = 1 - break2;
       } else if (break1 > break2) {
          side1 = break2;
          side2 = (break1 - break2);
          side3 = 1 - break1;
       } else return false;
    
       return ((side1 + side2) > side3 && (side1 + side3) > side2 && (side2 + side3) > side1);
    }
    //
    void test() {
       srand (time (NULL));
       int N = 10000; // number of trials
       int c = 0; // counter
       for (int i=0; i<N; ++i) {
          if (doBreak()) ++c; // increment counter if it's a triangle
       }
       std::cout << float(c) / float(N) << std::endl; // triangle fraction
    }

  5. #5
    Join Date
    Jun 2012
    Posts
    15

    Re: Glass Rod Problem

    I appreciate all the feedback. Below is what I ended up with, thanks to the help here, and on another board.

    Code:
    #include <iostream>
    #include <cmath>
    #include <cstdlib>
    #include <cfloat>
    #include <iomanip>
    #include <stdlib.h>
    #include <time.h>
    
    using namespace std;
    
    float doBreak ();
    float doProbability (float, float);
    
    const int SENTINEL = 21;		//sentinal value
    
    
    int main()
    {
    	float count;
    	float tests;
    	float probability;
    	float triangle = 0;
    	
    
    	count = 1;
    	srand (time (NULL));
    
    	cout << "Enter number of glassrods to demolish (Enter " << SENTINEL << " to end program): ";
    	cin >> tests;
    
    	if 
    	(tests != SENTINEL)
    	{
    		do
    		{
    			triangle = triangle + doBreak();
    			count++;
    		}while (count <= tests);
    
    	probability = doProbability(triangle, tests);
    	
    	cout << "The probability that the broken glass rods will form a triangle is: " << probability << "%" << endl;
    	}
    	else
    	{
    			cout << "Aww, I was hoping to break stuff..." << endl;
    	}
    	return 0;
    }
    
    float doBreak()
    {
    	float break1;
    	float break2;	
    	float side1;
    	float side2;
    	float side3;
    	
    	
    	
    	
    		
    	break1 = (float)rand()/RAND_MAX;
    	break2 = (float)rand()/RAND_MAX;
    	
    	if (break1 < break2)
    	{
    		side1 = break1;
    		side2 = (break2 - break1);
    		side3 = 1 - break2;
    	}
    	else
    	{	
    		side1 = break2;
    		side2 = (break1 - break2);
    		side3 = 1 - break1;
    	}
    	if
    	((side1 + side2) > side3 &&
    	(side1 + side3) > side2 &&
    	(side2 + side3) > side1)
    	{
    		return 1;
    	}
    	else
    	{
    		return 0;
    	}
    }
    	
    float doProbability 
    	(float triangle,
    	float tests)
    	
    {
    	float probability;
    	
    	probability = (triangle / tests) * 100;
    	return probability;
    }

  6. #6
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Glass Rod Problem

    I guess you didn't heed the advice to not use floating point variables as counters. Your program will more than likely not run consistently depending on compiler, compiler options chosen, etc. Those loops will run either fewer or more times then you expect.

    Always use integer if you want make sure loops iterate the exact number of times.

    Regards,

    Paul McKenzie

  7. #7
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Glass Rod Problem

    Same with the triangle counter. That should be an int too.

  8. #8
    Join Date
    May 2009
    Posts
    2,413

    Re: Glass Rod Problem

    Quote Originally Posted by nuzzle View Post
    I became interested in the Glass Rod problem and I calculated the theoretical probability to 1/4.
    I've given this some further thought and come up with a quite simple motivation.

    The rod breaks into a left, a right and a middle piece. If one piece is longer than half the rod length no triangle can be formed.

    In 1/4 of the cases both breaks will be in the left half of the rod. This means the right piece will be longer than half the rod and no triangle can be formed.

    And analoguously, in 1/4 of the cases both breaks will be in the right half of the rod. Then the left piece will be too long and no triangle can be formed.

    In the rest, that is in 1/2 of the cases, the two breaks will be in different halves of the rod. In these cases there's still a chance a triangle can be formed. This happens when the middle piece is shorter than half the rod. And this happens in 1/2 of the cases. In the remaining 1/2 the middle piece will be too long and no triangle can be formed.

    So the conclussion is that a triangle can be formed when the breaks are in either half of the rod and the middle piece is shorter than half the rod. The combined probability for this is 1/2 times 1/2 is 1/4.

  9. #9
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Glass Rod Problem

    You can also think in terms of building a rod from three pieces. Pick a first length randomly between 0 and 1. In half the population, the first length will be greater than 1/2, so no triangles can be formed with this half of the population. In the other half of the population, where the first piece is less than half, a triangle can be formed only if the length of the second piece is also less than half, which gives an overall yield of 1/4.

  10. #10
    Join Date
    Jun 2012
    Posts
    15

    Re: Glass Rod Problem

    Sorry, I didn't mean to ignore that advice, it is accurate and really good advice. Honestly, I was just so burned out and happy the thing was mostly done and working that it slipped my mind. I will remember for further programs though.

    Quote Originally Posted by Paul McKenzie View Post
    I guess you didn't heed the advice to not use floating point variables as counters. Your program will more than likely not run consistently depending on compiler, compiler options chosen, etc. Those loops will run either fewer or more times then you expect.

    Always use integer if you want make sure loops iterate the exact number of times.

    Regards,

    Paul McKenzie

  11. #11
    Join Date
    Nov 2002
    Location
    California
    Posts
    4,556

    Re: Glass Rod Problem

    Quote Originally Posted by Paul McKenzie View Post
    I guess you didn't heed the advice to not use floating point variables as counters. Your program will more than likely not run consistently depending on compiler, compiler options chosen, etc. Those loops will run either fewer or more times then you expect.

    Always use integer if you want make sure loops iterate the exact number of times.
    Paul's advice is exactly correct.

    Nevertheless, you might have "lucked out" with your program because of one of the design goals of IEEE-753/754 on the format of floating point numbers. According to this goal, any integer between +/- 2-to-the-number-of-bits-in-the-significand has an exact representation in floating point. For example, for single precision floats, where there are 24 bits in the significand (including the implied leading bit of "1"), all integers between +/- 16,777,216 have an exact representation.

    Your code increments the "count" variable by 1, and I doubt that you have more than 16,777,216 trials, so you probably have "lucked out" even though you have incorrectly and dangerously used a float, and not an integer, as your loop counter.

    Mike

  12. #12
    Join Date
    May 2009
    Posts
    2,413

    Re: Glass Rod Problem

    Quote Originally Posted by MikeAThon View Post
    You can also think in terms of building a rod from three pieces.
    With this approach you still need to consider all possible outcomes and I don't think you have.

    Two randomly generated pieces will be shorter than 0.5 in 1/4 of the cases that's true but that doesn't determine whether a triangle can be formed or not. The third randomly generated piece will decide that. It will be a triangle only if the third piece is shorter than the sum of the first two.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured