I would like to do this
I have two numbers, A and B, where it can be A greater or smaller than B. What I want to do:
Compare B with A
If their ratio is "ouside" of a range, then take a random number and add it to "A" - Now check if their new ratio meets the condition
0.95 < ratio < 1.05
if not, try with another random.
My problem is that I ran into infinite loops... this is what I do:
float ratio = A/B;
if (ratio < 0.95 || ratio > 1.05) {
do {
// randomly take a negative or positive number
float random_n = ((float)rand())/RAND_MAX - 0.50;
// get an even smaller step
random_n *= 0.1;
// add or subtract the random number (depending on its sign)
A += random_n;
// form the ratio again
ratio = A / B;
cout << "lets see " << A << " " << B << " " << ratio << endl;
}
while (ratio > 0.95 || ratio < 1.05);
}
The condition should be:
while (ratio <= 0.95 || ratio >= 1.05);
You got the "<" and ">" mixed up. ratio is not between 0.95 and 1.05 if it's less or equal than 0.95 or greater or equal than 1.05.
It's easy to avoid such mistakes if you remember how you negate a conjunction:
NOT (0.95 < ratio < 1.05) === NOT (0.95 < ratio AND ratio < 1.05) ====
[...]
The rule is: change every AND to OR and negate all sub-expressions:
[...] === (NOT (0.95 < ratio) OR NOT (ratio < 1.05)) ====
(0.95 >= ratio OR ratio >= 1.05) === (ratio <= 0.95 OR ratio >= 1.05)
Your do..while loop condition should be
while(ratio <= 0.95 || ratio =>1.05)
Well the problem is you're increasing A and never changing B
and still expect ratio to be in (0.95,1.05) . This depends on initial value of A and B to break the loop.
Try:
B=rand()%RAND_MAX;
do {
A=rand()%RAND_MAX;
ratio = A/B;
cout<<"lets see "<< A <<" "<< B <<" "<<ratio<<endl;
}while(ratio <0.95 || ratio>1.05);
Then can divide A and B by power of ten as per your needs.
Also use srand(time(0)) for different random values on successive runs
Related
I would like to make a table which can show sin,cos,tan,cot values of chosen degrees. As i said, i couldn't take the right answer of tan90 . I don't know how to change it to 'INFINITY'. I am waiting for your help ! :)
#include<math.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
main()
{
double table[10][4];
int i=0,j=0;
double val=0,PI=3.14159;
val = PI / 180.0;
printf("\tİstenen Tablo\n\t-------------\n");
printf("\t ACI\t\t\t SIN\t\t\t COS\t\t\t TAN\t\t\t COT\n\t------\t\t\t------\t\t\t------\t\t\t---
---\t\t\t------");
for(i=0;i<=90;i+=10)
{
for(j=0;j<5;j++)
{
switch (j)
{
case 0:table[i/10][j] = i; break;
case 1:table[i/10][j] = sin(i*val);break;
case 2:table[i/10][j] = cos(i*val);break;
case 3:table[i/10][j] = tan(i*val);break;
case 4:table[i/10][j] = 1/tan(i*val);break;
}
}
printf("\n\t %lf \t\t %lf\t\t %lf\t\t %lf\t\t %lf\n",table[i/10][0],table[i/10]
[1],table[i/10][2],table[i/10][3],table[i/10][4]);
}
return 0;
}
The reason you're getting incorrect values is that π is not 3.14159, that's just an approximation to its real value. In fact, any non-infinite series of decimal digits will be an approximation but, the more digits you have, the closer i * val will be to the correct value you should be passing to your trigonometric calls.
A far better value would be M_PI from math.h, which has far more precision than what you currently have.
You still may not get your expected values due to the limited precision of even the double type. If that happens, you will need to adjust what you get before working things out in floating point.
For example, the following functions could be used to get more acceptable values, forcing very specific values on quadrant boundaries so as to avoid even the smallest possibility of imprecision in those results:
double mySin(int degrees) {
int mod360 = degrees % 360;
if (mod360 == 0) return 0.0;
if (mod360 == 90) return 1.0;
if (mod360 == 180) return 0.0;
if (mod360 == 270) return -1.0;
return sin(degrees % 360 * M_PI / 180.0);
}
double myCos(int degrees) {
return mySin(degrees + 90);
}
double myTan(int degrees) {
int mod360 = degrees % 360;
if (mod360 == 0) return 0.0;
if (mod360 == 90) return 1.0 / 0.0;
if (mod360 == 180) return 0.0;
if (mod360 == 270) return -1.0 / 0.0;
return tan(mod360 * M_PI / 180.0);
}
double myCot(int degrees) {
// Now that tan() works properly for the quadrant
// boundaries, just use normal formula.
return 1.0 / myTan(degrees);
}
These are built from the ground up to use degree inputs rather than radians and, because you trap the infinite value cases before doing any floating point math (which is inherently imprecise when you're dealing with transcendentals), you can give the correct results for those cases.
A complete program, integrating these functions and getting rid of stuff you don't need is shown below. There's no point storing all those values in an array and then printing out the array (with no other use of it) when you can just print the values immediately:
#include <cmath>
#include <cstdio>
using namespace std;
double mySin(int degrees) {
int mod360 = degrees % 360;
if (mod360 == 0) return 0.0;
if (mod360 == 90) return 1.0;
if (mod360 == 180) return 0.0;
if (mod360 == 270) return -1.0;
return sin(mod360 * M_PI / 180.0);
}
double myCos(int degrees) {
return mySin(degrees + 90);
}
double myTan(int degrees) {
int mod360 = degrees % 360;
if (mod360 == 0) return 0.0;
if (mod360 == 90) return 1.0 / 0.0;
if (mod360 == 180) return 0.0;
if (mod360 == 270) return -1.0 / 0.0;
return tan(mod360 * M_PI / 180.0);
}
double myCot(int degrees) {
// Now that tan() works properly for the quadrant
// boundaries, just use normal formula.
return 1.0 / myTan(degrees);
}
int main()
{
printf("İstenen Tablo\n");
printf("-------------\n");
printf("\t ACI \t SIN \t COS \t TAN \t COT\n");
printf("\t------------\t-----------\t-----------\t-----------\t-----------\n");
for (int i = 0; i < 360; i += 10) {
printf("\t%12d\t%9.9lf\t%9.9lf\t%9.9lf\t%9.9lf\n",
i, mySin(i), myCos(i), myTan(i), myCot(i));
}
return 0;
}
The output of that is:
İstenen Tablo
-------------
ACI SIN COS TAN COT
------------ ----------- ----------- ----------- -----------
0 0.000000000 1.000000000 0.000000000 inf
10 0.173648178 0.984807753 0.176326981 5.671281820
20 0.342020143 0.939692621 0.363970234 2.747477419
30 0.500000000 0.866025404 0.577350269 1.732050808
40 0.642787610 0.766044443 0.839099631 1.191753593
50 0.766044443 0.642787610 1.191753593 0.839099631
60 0.866025404 0.500000000 1.732050808 0.577350269
70 0.939692621 0.342020143 2.747477419 0.363970234
80 0.984807753 0.173648178 5.671281820 0.176326981
90 1.000000000 0.000000000 inf 0.000000000
100 0.984807753 -0.173648178 -5.671281820 -0.176326981
110 0.939692621 -0.342020143 -2.747477419 -0.363970234
120 0.866025404 -0.500000000 -1.732050808 -0.577350269
130 0.766044443 -0.642787610 -1.191753593 -0.839099631
140 0.642787610 -0.766044443 -0.839099631 -1.191753593
150 0.500000000 -0.866025404 -0.577350269 -1.732050808
160 0.342020143 -0.939692621 -0.363970234 -2.747477419
170 0.173648178 -0.984807753 -0.176326981 -5.671281820
180 0.000000000 -1.000000000 0.000000000 inf
190 -0.173648178 -0.984807753 0.176326981 5.671281820
200 -0.342020143 -0.939692621 0.363970234 2.747477419
210 -0.500000000 -0.866025404 0.577350269 1.732050808
220 -0.642787610 -0.766044443 0.839099631 1.191753593
230 -0.766044443 -0.642787610 1.191753593 0.839099631
240 -0.866025404 -0.500000000 1.732050808 0.577350269
250 -0.939692621 -0.342020143 2.747477419 0.363970234
260 -0.984807753 -0.173648178 5.671281820 0.176326981
270 -1.000000000 0.000000000 -inf -0.000000000
280 -0.984807753 0.173648178 -5.671281820 -0.176326981
290 -0.939692621 0.342020143 -2.747477419 -0.363970234
300 -0.866025404 0.500000000 -1.732050808 -0.577350269
310 -0.766044443 0.642787610 -1.191753593 -0.839099631
320 -0.642787610 0.766044443 -0.839099631 -1.191753593
330 -0.500000000 0.866025404 -0.577350269 -1.732050808
340 -0.342020143 0.939692621 -0.363970234 -2.747477419
350 -0.173648178 0.984807753 -0.176326981 -5.671281820
Note the disparity between signs on the infinities and forced zeros. While both 0 / 1 and 0 / -1 can be treated as zero (there are no negative zeros despite the fact IEEE754 allows them), the values for 1 / 0 and -1 / 0 are given +inf and -inf respectively.
My more advanced mathematical buddies may disagree but I think I've got that right.
tan(x) is extremely sensitive to even tiny variations in the argument around odd multiples of pi/2 because its derivative 1/cos^2(x) is also unbounded around those points. This, along with the limited precision of the computer floating points, cause significant errors when evaluating tan around odd multiples of pi/2.
The better strategy is to first reduce the angle to the first octant [0, 45) (degrees) then use basic trig identities to derive the target value. This will provide better precision overall, and will also give an actual inf value at 90 degrees since 0 is an exactly representable number, and tan(0) = 0.
An example of such an implementation is below.
#include <math.h>
const double deg2rad = M_PI / 180.0;
double tan_degrees(int n)
{
bool neg = false, inv = false;
if(n < 0) { n = -n; neg = true; } // tan(-x) = -tan(x)
n %= 180; // tan(x + pi) = tan(x)
if(n > 90) { n = 180 - n; neg = !neg; } // tan(pi - x) = -tan(x)
if(n > 45) { n = 90 - n; inv = true; } // tan(pi/2 - x) = 1 / tan(x)
double val = tan(n * deg2rad);
if(neg) val = -val;
if(inv) val = 1. / val;
return val;
}
Common C implementations use the IEEE-754 “double” format (also called binary64) for their double type. The closest value to π/2 representable in this format is 884279719003555 / 562949953421312, which is 1.5707963267948965579989817342720925807952880859375. It differs from π/2 by about 6.12323399573676588613033•10−17. Its tangent is about 1.633123935319536975•1016. (The closest representable value to its tangent is 1.633123935319537•1016.) So the best result you can get by converting 90 degrees to radians and applying tan to the result is 1.633123935319536975•1016.
Because of this, it is not possible to get ∞ from tan(x). All numbers representable in this double format are rational, so none are exactly multiples of π/2, so none have tangents that are infinity.
(There are some numbers representable in the format that are closer to an odd multiple of π/2 than the value above. This is due to the irregularity of the irrational period of π with respect to the representable numbers. However, from memory, none of those numbers are sufficiently close to an odd multiple of π/2 that their tangent is outside the finite range of this double format, which would cause the tan function to overflow to an infinity.)
You might check whether the math library you are using provides a tanpi or tanPi function. This and related functions are recommended by IEEE 754-2008. Apple supplies tanPi with the name __tanPi. __tanPi(x) returns tan(πx), subject to calculation errors. __tanPi(.5) returns ∞.
if (GoalWeight < 0.0) {
int weeks;
cout << "How many weeks do you plan to continue this trend?\n";
cin >> weeks;
double NewWeight = GoalWeight * weeks;
double NegBMI = (weight - NewWeight) * 703 / (pow(HeightConverter, 2));
cout << "If you complete your plan for " << weeks << "weeks you will have a new BMI of: \n" << NegBMI;
}
system("pause");
return 0;
}
Output result:
What is your current weight?: 180
What is your current height in inches?" 71
Your current BMI is: 25.10(Not part of output, but this is correct)
What is your goal weight change?(lbs) -1.5
How many weeks do you plan to continue this trend?: 6
If you complete your plan for 6 weeks you will have a new BMI of: 26.36
As you can tell this is wrong
The calculation for BMI is (weight * 703) /height^2(inches)
What it is doing for negative numbers is:
180 + 9(instead of 180 - 9) giving (191 * 703) / 71^2 yielding 26.36
Instead of:
180 - 9(giving 171 * 703) / 71^2 yielding the correct output of:23.84
I know you're all shaking your heads saying I must be an idiot, and rightfully so, I'm hoping someone can help me with this!
What is your goal weight change?(lbs) -1.5
How many weeks do you plan to continue this trend?: 6
6 * ( -1.5 ) == -9
180 - (-9) == 189
So you either input goal weight change as positive number or add it, not subtract.
Your newWeight is resulting to -9 because of your statement 6 * -1.5.If you want to subtract it just make the (weight + newWeight) rather than the -.
Do you believe that if you do (+NewWeight) the value of NewWeight becomes positive?
this is not the case:
Unary Plus Operator (+): The result of an operation on a numeric type is the value of the operand itself. This operator has been predefined for all numeric types.
As a solution use Reginalds idea and make (weight + newWeight) rather than the -.
I recently created this simple program to find average velocity.
Average velocity = Δx / Δt
I chose x as a function of t as x = t^2
Therefore v = 2t
also, avg v = (x2 - x1) / (t2 - t1)
I chose the interval to be t = 1s to 4s. Implies x goes from 1 to 16
Therefore avg v = (16 - 1) / (4 - 1) = 5
Now the program :
#include <iostream>
using namespace std;
int main() {
float t = 1, v = 0, sum = 0, n = 0; // t = time, v = velocity, sum = Sigma v, n = Sigma 1
float avgv = 0;
while( t <= 4 ) {
v = 2*t;
sum += v;
t += 0.0001;
n++;
}
avgv = sum/n;
cout << "\n----> " << avgv << " <----\n";
return 0;
}
I used very small increments of time to calculate velocity at many moments. Now, if the increment of t is 0.001, The avg v calculated is 4.99998.
Now if i put increment of t as 0.0001, The avg v becomes 5.00007!
Further decreasing increment to 0.00001 yields avg v = 5.00001
Why is that so?
Thank you.
In base 2 0.0001 and 0.001 are periodic numbers, so they don't have an exact representation. One of them is being rounded up, the other one is rounded down, so when you sum lots of them you get different values.
This is the same thing that happens in decimal representation, if you choose the numbers to sum accordingly (assume each variable can hold 3 decimal digits).
Compare:
a = 1 / 3; // a becomes 0.333
b = a * 6; // b becomes 1.998
with:
a = 2 / 3; // a becomes 0.667
b = a * 3; // b becomes 2.001
both should (theoretically) result into 2 but because of rounding error they give different results
In the decimal system, since 10 is factorised into primes 2 and 5 only fractions whose denominator is divisible only by 2 and 5 can be represented with a finite number of decimal digits (all other fractions are periodic), in base 2 only fractions which have as denominator a power of 2 can be represented exactly. Try using 1.0/512.0 and 1.0/1024.0 as steps in your loop. Also, be careful because if you choose a step that is too small, you may not have enough digits to represent that in the float datatype (i.e., use doubles)
I'm trying to speed up my code for calculating the volume of a sphere (see code below).
This volume of the sphere is produced by calculating small volume segments, dv, and summing them into a volume, vol.
In reality this code is just a sanity check before I apply the calculations to other sphere like objects which will have symmetrical properties, hence I should be able to increase the speed of the code by calculating over a small volume and multiplying the end result.
Replace 360 and 180 in while (phid<=(360.0/adstep)) and while (thetad<=(180.0/adstep)) with 180 and 90 respectively and you quarter the calculations required meaning that you can simply multiply the final vol by 4.0.
This works if I set phi to and leave theta at 180, halving the calculations.
But it doesn't like it when I set theta to 90.
Ouput:
Phi 360, Theta 180
Actual Volume Calculated Volume % Difference
4.18879020478639053 4.18878971565348923 0.00001167718922403
Phi 180, Theta 180
4.18879020478639053 4.18878971565618219 0.00001167712493440
Phi 180, Theta 90
4.18879020478639053 4.18586538829648180 0.06987363946500515
You can see in the above that the first two calculations are near identical (I assume the difference is due to precision errors) while the last one gives significantly different results. Could the nested loops cause issues?
Any help would be appreciated as I haven't found anything in my research (google & stack overflow) to describe the problem I'm having.
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
int main()
{
double thetar, phir, maxr, vol, dv, vol2, arstep, adstep, rad, rad3, thetad, phid, ntheta, nphi;
cout << fixed << setprecision(17); // Set output precision to defined number of decimal places. Note Double has up to 15 decimal place accuracy
vol=0.0; // Initialise volume and set at zero
adstep=0.1; // Steps to rotate angles in degrees
arstep=(adstep/180.0)*M_PI; // Angle steps in radians
phid=1.0; // Phi in degrees starting at adstep
maxr = 1.0; // Radius of the sphere
// Loop to calculate volume
while (phid<=(360.0/adstep)) // Loop over Phi divided by adstep. This scales the loop to the desired number of calculations.
{
phir=((phid*adstep)/180.0)*M_PI; // Phi in radians
thetad=1.0; // Theta in degrees, reset to initial adstep value
while (thetad<=(180.0/adstep)) // Loop over Theta divided by adstep. Like Phi loop, this scales the loop to the desired number of calculations
{
thetar=((thetad*adstep)/180.0)*M_PI; // Convert theta degrees to radians
dv = ((maxr*maxr*maxr) * sin(thetar) * arstep * arstep) / 3.0; // Volume of current segment
vol += dv; // Summing all the dv value together to generate a global volume
thetad+=1.0; // Increase theta (degrees) by a single step
}
phid+=1.0; // Increase phi (degrees) by a single step
}
vol = vol*1.0; // Volume compensated for any reduction in phi and theta
rad3 = (3.0*vol)/(4.0*M_PI); // volume equivalent radius^3
rad = pow(rad3,(1.0/3.0)); // volume equivalent radius
vol2 = (4.0/3.0)*M_PI*(maxr*maxr*maxr); // Calculated volume of a sphere given initial maxr
// Diagnostic output
cout << vol2 << " " << vol << " " << ((vol2-vol)/vol)*100.0 << endl;
}
Edit: Corrected starting values of phid and thetad to 1.0
Edit 2:
I just wanted to update, for future viewers, that using the Kahan summation algorithm (https://en.wikipedia.org/wiki/Kahan_summation_algorithm) has virtually negated all my precision errors due to the summation of a small number onto a large number. There are other methods out there but this is one of the simplest and does the job I need it to.
For posterity this is the example psuedocode taken from the wikipedia page on the topic:
function KahanSum(input)
var sum = 0.0
var c = 0.0 // A running compensation for lost low-order bits.
for i = 1 to input.length do
var y = input[i] - c // So far, so good: c is zero.
var t = sum + y // Alas, sum is big, y small, so low-order digits of y are lost.
c = (t - sum) - y // (t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
sum = t // Algebraically, c should always be zero. Beware overly-aggressive optimizing compilers!
// Next time around, the lost low part will be added to y in a fresh attempt.
return sum
As far as speed goes, I suspect (without having profiled it) that a lot of time is wasted converting between radians and degrees, and also computing all those sins. AFAICT, thetar loops through the same values during each iteration of the outer loop, so it would likely be more efficient to pre-compute sin(thetar) once before the main loop, and do a simple lookup in your inner loop.
As for numerical stability, as vol gets larger and larger than dv, you will start losing more and more precision as you go along. You would in principle get better results if you could store all the dvs in an array, then sum it using a divide and conquer approach rather than a linear pass. Then again I count (only) 6 480 000 total iteration, so I think a double accumulator (holding 15-17 significant base-10 digits) can actually handle losing 6-7 digits without much trouble.
Most likely, your problem is: exiting the loop 1 iteration before you want it. You should not compare floating-point numbers for equality. A quick way to fix it is adding a small constant, e.g.
while (thetad<(180.0/adstep)+1e-8)
This isn't a very thorough analysis but might give you some insight into the source of your error. In your code you are accumulating the value of 3240000 floating point numbers. As the value of vol increases, the ratio between dv and vol is increasing you are losing more and more precision in the addition.
A standard way to mitigate the loss of precision in accumulating many values to a single value (known as a reduction sum) is to perform the addition in blocks: for example, you could add together every 8 values and store them to an array, then add together every 8 values of that array, etc. until you are left with a single value. This is likely to get you a better result.
Also, it is worth considering that you are taking linear steps over a spherical surface, so you are not uniformly sampling your sphere. This is likely to affect your final result. One way of sampling the sphere uniformly is to take linear steps in the azimuthal angle phi from 0 to 360 degrees and take the acos of the range from -1 to 1 for your polar angle theta. See this link on sphere point-picking for a more detailed explanation.
First of all, I think, there are couple of errors in your function. I think both phid and thetad should be initialized to either 0 or 1.0.
Second, you can gain quite a bit by reducing the number of floating point multiplications.
In the code below, I moved the contents of your main function to volume1 and created a function volume2 that contains slightly optimized code.
#include <iostream>
#include <iomanip>
#include <cmath>
#include <ctime>
using namespace std;
void volume1(int numSteps)
{
double thetar, phir, maxr, vol, dv, vol2, arstep, adstep, rad, rad3, thetad, phid, ntheta, nphi;
cout << fixed << setprecision(17); // Set output precision to defined number of decimal places. Note Double has up to 15 decimal place accuracy
vol=0.0; // Initialise volume and set at zero
adstep=360.0/numSteps; // Steps to rotate angles in degrees
arstep=(adstep/180.0)*M_PI; // Angle steps in radians
phid=1.0; // Phi in degrees starting at adstep
maxr = 1.0; // Radius of the sphere
// Loop to calculate volume
while (phid<=(360.0/adstep)) // Loop over Phi divided by adstep. This scales the loop to the desired number of calculations.
{
phir=((phid*adstep)/180.0)*M_PI; // Phi in radians
thetad=1.0; // Theta in degrees, reset to initial adstep value
while (thetad<=(180.0/adstep)) // Loop over Theta divided by adstep. Like Phi loop, this scales the loop to the desired number of calculations
{
thetar=((thetad*adstep)/180.0)*M_PI; // Convert theta degrees to radians
dv = ((maxr*maxr*maxr) * sin(thetar) * arstep * arstep) / 3.0; // Volume of current segment
vol += dv; // Summing all the dv value together to generate a global volume
thetad+=1.0; // Increase theta (degrees) by a single step
}
phid+=1.0; // Increase phi (degrees) by a single step
}
vol = vol*1.0; // Volume compensated for any reduction in phi and theta
rad3 = (3.0*vol)/(4.0*M_PI); // volume equivalent radius^3
rad = pow(rad3,(1.0/3.0)); // volume equivalent radius
vol2 = (4.0/3.0)*M_PI*(maxr*maxr*maxr); // Calculated volume of a sphere given initial maxr
// Diagnostic output
cout << vol2 << " " << vol << " " << ((vol2-vol)/vol)*100.0 << endl << endl;
}
void volume2(int numSteps)
{
double thetar, maxr, vol, vol2, arstep, adstep, rad, rad3, thetad, phid, ntheta, nphi;
cout << fixed << setprecision(17); // Set output precision to defined number of decimal places. Note Double has up to 15 decimal place accuracy
vol=0.0; // Initialise volume and set at zero
adstep = 360.0/numSteps;
arstep=(adstep/180.0)*M_PI; // Angle steps in radians
maxr = 1.0; // Radius of the sphere
double maxRCube = maxr*maxr*maxr;
double arStepSquare = arstep*arstep;
double multiplier = maxRCube*arStepSquare/3.0;
// Loop to calculate volume
int step = 1;
for ( ; step <= numSteps; ++step )
{
int numInnerSteps = numSteps/2;
thetad = adstep; // Theta in degrees, reset to initial adstep value
for ( int innerStep = 1; innerStep <= numInnerSteps; ++innerStep )
{
thetar = innerStep*arstep;
vol += multiplier * sin(thetar); // Volume of current segment
}
}
vol = vol*1.0; // Volume compensated for any reduction in phi and theta
rad3 = (3.0*vol)/(4.0*M_PI); // volume equivalent radius^3
rad = pow(rad3,(1.0/3.0)); // volume equivalent radius
vol2 = (4.0/3.0)*M_PI*(maxr*maxr*maxr); // Calculated volume of a sphere given initial maxr
// Diagnostic output
cout << vol2 << " " << vol << " " << ((vol2-vol)/vol)*100.0 << endl << endl;
}
int main()
{
int numSteps = 3600;
clock_t start = clock();
volume1(numSteps);
clock_t end1 = clock();
volume2(numSteps);
clock_t end2 = clock();
std::cout << "CPU time used: " << 1000.0 * (end1-start) / CLOCKS_PER_SEC << " ms\n";
std::cout << "CPU time used: " << 1000.0 * (end2-end1) / CLOCKS_PER_SEC << " ms\n";
}
The output I get, using g++ 4.7.3:
4.18879020478639053 4.18762558892993564 0.02781088785811153
4.18879020478639053 4.18878914146923176 0.00002538483372773
CPU time used: 639.00000000000000000 ms
CPU time used: 359.00000000000000000 ms
That gets you an improvement of about 44%.
Write a program that determines how far and for how long a time a rock will travel when you throw it off a cliff. Click here to copy the file toss.txt to your desktop (right click the file name and choose Save as). The file contains the height of the cliff in meters.
The program will then:
Open the file toss.txt and read the cliff height into a double-precision variable, then echo print the value of the cliff height to the screen with an appropriate label.
Ask the user for the angle at which the rock is thrown (90 degrees is straight up, and 0 degrees is straight forward), and the velocity at which the rock is thrown (in miles per hour).
Check to make sure the angle is greater than or equal to 0 and less than or equal to 90. If it is not, the program terminates and prints an appropriate error message to the screen.
Check to make sure the velocity is less than or equal to 100 mph and greater than or equal to 0 mph. If it is not, the program terminates and prints an appropriate error message to the screen.
If the angle and velocity are valid, the program completes the calculations as follows:
Converts miles per hour to meters per second.
Converts the angle to radians.
Calculates the time traveled using the following equations:
where
Calculates the distance traveled in the horizontal direction using:
Outputs the time and distance traveled in the horizontal direction to the screen with appropriate labels.
Prints an appropriate message telling the user if the distance traveled in the horizontal direction was greater than, less than, or equal to the height of the cliff.
/* This program */
using namespace std;
#include<iostream>
#include<cmath>
#include<iomanip>
#include<fstream>
int readit ();
int calcit (double, double, double);
int main()
{
readit ();
system ("pause");
return 0;
}
int readit ()
{
double hite, angl, v;
ifstream datain ( "toss.txt" );
datain >> hite;
cout << "The cliff height is " << hite << " meters"<< endl;
cout << "Enter the angle in degrees (from horizontal) the rock is thrown: "
<< endl;
cin >> angl;
if (angl>=0 && angl<=90)
{
cout << endl << "The angle you have entered is "<<angl<< endl <<endl;
}
else
{
cout << "The angle you have entered is not acceptable" << endl;
return 0;
}
cout << "Enter the velocity in mph the rock is thrown: " << endl;
cin >> v;
if (v>=0 && v<=100)
{
cout << endl << "The velocity at which the rock is thrown is "<<v<<
" mph" << endl << endl;
}
else
{
cout << "The velocity you have entered is not acceptable" << endl;
return 0;
}
calcit (hite, angl, v);
}
int calcit (double hite, double angl, double v)
{
double tyme, dist;
v = v * (1609.344/3600);
angl = angl*(M_PI/180);
tyme = -v*sin(angl) + (sqrt((v*sin(angl)*v*sin(angl)) + 2*9.8*hite)/9.8) + (2*(v*sin(angl))/9.8);
dist = (tyme * v) * cos(angl);
cout << tyme << " " << dist <<endl;
}
I am trying to get the correct time the rock is traveling before it hits the ground but i keep getting incorrect answers. I am not sure if i am turning the equation to figure out the time the rock will be in the air until impact into c++ language right. any have any ideas??? i really need to finish this damn project.
Starting from the equation for the y (height above 0) for the rock we have
y = h + v*sin(a)*t - g/2*t^2
which transforms into
g/2 T^2 - v*sin(a)*T - h == 0
when we solve for the final condition y(T)=0.
This yields
T = v*sin(a)/g + sqrt(v*sin(a)*v*sin(a) + 2*g*h)/g
I just can't figure out where the first part -v*sin(angl) in your equation comes from. Everything else looks just fine. So it seems not to be with your code but with the equation you started.
The equation you want is:
s =ut + 1/2 at^2
s = Total distance traveled. (Height of the cliff)
u = Starting velocity (In your case negative as you are throwing
away from the target. And take into account
that not all the starting velocity is away
from the target (eg angle 0 mean u = 0))
a = acceleration (9.81 m/s2)
t = time (The value you want to calculate).
Rearrange the formula to solve for t
To find the solution for t where s = 0...
This formula is you basic quadratic:
y = a.x^2 + b.x + c
Where:
x/y are variables.
a/b/c are constants.
The solution for a quadratic equation where y is 0 is:
x = [ -b ± sqrt(b^2 - 4ac) ] / 2a
Notice the ± symbol. There are actually two solutions to the problem.
You should be able to deduce which one is correct for you as the other
is probably negative.
In your particular case the map is:
x ==> t
y ==> 0
a ==> 1/2.g
b ==> u
c ==> -s
I would suggest a few things to "clean up" the code a bit:
If functions return int ensure that they do really return something. (main doesn't have to but other functions do).
Calculate v * sin(ang1) once then use it in your formula thereafter. Not only more efficient but will make your code clearer.
Like you have given Pi a "constant", do that with other numbers you are using like 9.8 (gravitational force?)
If you have a confusing formula in the code, just introduce more variable names until the meaning becomes obvious. So long as you don't reassign different values to the same variables, this will not make the program confusing.
int calcit (double hite_meters, double angl_deg, double v_mph)
{
double const gravity = 9.8;
double v_ms = v_mph * (1609.344/3600);
double angl_rad = angl_deg * (M_PI/180);
double v_vertical = v_ms * sin( angl_rad );
double time_up = v_vertical / gravity; // [m/s] / [m/s^2] = [s]
double time_down_over_cliff = time_up;
// use quadratic formula t = ( -v - ( v^2 - 4gd )^1/2 ) / 2g:
double time_under_cliff = ( - v_vertical
- sqrt( ( v_vertical * v_vertical )
- ( 4 * - gravity * hite_meters ) ) // negative gravity = down
) / ( 2 * - gravity ); // ( [m/s] + ([m/s]^2 - [m/s^2]*[m])^1/2 ) / [m/s^2]
// = [m/s] / [m/s^2] = [s]
double time_total = time_up + time_down_over_cliff + time_under_cliff;
double v_horizontal = v_ms * cos( angl_rad );
double dist_horizontal = v_ms * time_total;
cout << time_total << " " << dist_horizontal <<endl;
}
Every line of code produces a new, relevant piece of information. When converting to a new unit, I introduce a new variable with a new name. Formulas involving more than one unit get the unit types explained in a comment. This should help turn up unit conversion errors which otherwise I can't help you catch.
Writing this kind of code involves more typing, but the time saved on head-scratching and asking for help more than makes up for it.
The program itself is not any less efficient. More importantly, it may be easily modified, so it won't turn into an inefficient mess after a few revisions.