C++ Finding square root without sqrt function loop glitching - c++

So I am making this as a homework assignment. I understand that there are so many ways that this code could be more efficient and accurate but this is the way my professor wants it done.
I am having problems with the loop. When I ask for the square root of 67 it does find it but it loops the correct answer 3 times.
Enter a value to be square rooted:
67
33.5
guess = 17.75
guess = 10.7623
guess = 8.49387
guess = 8.19096
guess = 8.18535
guess = 8.18535
guess = 8.18535
The program took 7 guess to find an estimation.
When I try to find the square root of 5 it finds it but continues to loop indefinitely
using namespace std;
int main()
{
double guess2;
double squarenumber;
double guess1;
int numofguess = 0;
cout << "Enter a value to be square rooted: " << endl;
cin >> squarenumber;
guess1 = squarenumber/2;
cout << guess1 << endl;
do
{
guess2 = (guess1 - (((guess1 * guess1) - squarenumber)/(2* guess1)));
guess1 = guess2;
cout << "guess = " << guess2 << endl;
numofguess = numofguess + 1;
} while ((guess2 * guess2) > squarenumber);
cout<< "The program took "<< numofguess <<" guess to find an estimation.";
return 0;
}

I think that what you are missing is a proper exit condition.
Your code is written to loop indefinitely until the guess is "perfect".
You should have an exit condition checking if current guess is the same as previous guess, which obviously means that you won't do any better.
Here is my suggestion based on your code :
using namespace std;
int main()
{
double guess2;
double squarenumber;
double guess1;
int numofguess = 0;
cout << "Enter a value to be square rooted: " << endl;
cin >> squarenumber;
guess2 = guess1 = squarenumber/2;
cout << guess1 << endl;
const double epsilon = squarenumber * 1E-6;
do
{
guess1 = guess2;
guess2 = (guess1 - (((guess1 * guess1) - squarenumber)/(2* guess1)));
cout << "guess = " << guess2 << endl;
numofguess = numofguess + 1;
} while ((guess2 * guess2) > squarenumber && fabs(guess2-guess1) > epsilon);
cout<< "The program took "<< numofguess <<" guess to find an estimation.";
return 0;
}

Mickaël C. Guimarães's answer is basically correct, check for an episolon value (absolute difference from the correct answer and your answer). But the "(guess2 * guess2) > squarenumber" should be dropped completely. That's because the value could in theory overshoot and be too low. The algorithm actually goes upwards if the value is too low. e.g. if you want SQRT(25) and your "guess1" prediction is way too low at 2, then guess2 would equal
(2 - (((2 * 2) - 25)/(2* 2))) = 7.25;
And on the next iteration then falls to 6.725624, so heads in the right direction. Low values actually get boosted up and eventually approach the target. By stopping if the value drops below the true SQRT then you might get "false positives" where too low values are accepted as accurate enough.
The times when the system got "stuck" were basically like the story Acchiles and the Tortoise. At each step, the system was dividing the remaining distance to go by some amount, but the change was therefore smaller each step, and could in theory never converge on the exact value, therefore you decide how much accuracy you want so that it finishes in a set time.
Additionally, the issue where the system seemed to take too many steps to converge is because floating point numbers are stored in higher precision, but cout has limited display precision. You can control that by sending setting values to cout before the print commands:
std::cout << std::fixed; // force all values to show to the same decimals
std::cout << std::setprecision(6); // set how many places to show
These code can be streamed to cout in one command before the value to print as well:
std::cout << std::fixed << std::setprecision(6) << "guess = " << guess2 << endl;

Related

Babylonian square root algorithm output not matching example

I'm doing an assignment and while I have it pretty much entirely done, I've run into a problem. The program is supposed to find the square root of a number the user inputs using the Babylonian square root algorithm. I was given an example output, and mine does not quite match. Also if you see any more issues please, give me a heads up! Especially if it's about the do while loop (it was the only solution I could get that stopped an infinite loop issue I was having).
#include <ios>
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
std::cout << std::fixed << std::setprecision(4);
//variables
int input;
double guess, r, check, test;
//input
cout << "Enter a number and I will apply the\n";
cout << "Babylonian square root algorithm until\n";
cout << "I am within .001 of the correct answer\n";
cin >> input;
cout << "You input " << input << "\n";
//calculate
guess = input / 2;
do {
test = guess;
r = input / guess;
guess = (guess + r) / 2;
cout << "\nguessing " << guess;
} while (guess != test); //while end
//check
check = guess * guess;
cout << "\nThe Babylons algorithm gives " << guess;
cout << "\nChecking: " << guess << " * " << guess << " = " << check << "\n";
} //main end
**Example output:**
Enter a number and I will apply the Babylonian square root algorithm
until I am withing .001 of the correct answer.
151
You entered 151
guessing 38.75
guessing 21.3234
guessing 14.2024
guessing 12.4172
guessing 12.2889
The Babylons algorithm gives 12.2889
Checking: 12.2889 * 12.2889 = 151.016
Press any key to continue . . .
**My Output:**
Enter a number and I will apply the
Babylonian square root algorithm until
I am within .001 of the correct answer
151
You input 151
guessing 38.5067
guessing 21.2140
guessing 14.1660
guessing 12.4127
guessing 12.2888
guessing 12.2882
guessing 12.2882
guessing 12.2882
The Babylons algorithm gives 12.2882
Checking: 12.2882 * 12.2882 = 151.0000
Change the type of input from int to double:
double input;
which changes initial value of guess = input / 2 from floor(151/2) = 75.0 to 75.5 for the expected sequence of values. Alternatively, cast the enumerator input to a double in the expression with:
guess = (double) input / 2;
or more elegantly via implicit type conversion by using floating point value as the divisor at suggested by #AlanBirtles:
guess = input / 2.0;
To fix the loop test:
#include <math.h>
...
do {
...
} while(fabs(test - guest) > 0.001);

2 identical codes, get error at one

I added comments to the code, do I have a compiler issues? I can't figure it out, I tried looking on google and the book but I cant figure out why the first half of code only accepts the input with space between the number and unit and second code accepts the number and unit together.
I'm using code blocks. So far I tried closing it and opening it again.
int main(){
constexpr double dollar_to_euro = 0.91;
constexpr double dollar_to_yen = 117.07;
constexpr double dollar_to_pounds = 0.70;
double sum = 1;
char curr = '\0'; // tried replacing '\0' with '0' and ' '
cout << "Please enter sum, followed by currency for conversion.\n"
<< "U for dollar, E for euro, Y for yen and P for pounds.\n";
cin >> sum >> curr; // This is my issue, it does not want to accept "sumcurr" together, it only accepts it if theres space in between
// yet on the second code for inches or centimeters it does accept them being together. Look down.
// For example entering "5 E" works, yet "5E" does not work.
if(curr=='E')
cout << "The amount " << sum << " euro is " << sum/dollar_to_euro << " dollars\n";
else
cout << "GOD DAMMIT !!!!\n";
constexpr double cm_per_inch = 2.54;
double len = 1;
char unit = '\0';
cout << "Please enter length followed by unit.\n";
cin >> len >> unit; // Over here it works, this is an example from a book. Entering "5i" works.
if(unit=='i')
cout << len << " in == " << cm_per_inch*len << "cm.\n";
else
cout << "Wrong input !\n";
}
The problem here is that E/e is valid in a floating point number but 5E/5e is not a valid floating point number as you need a value after the E/e. So when you enter 5e the input for sum fails because of the invalid syntax where 5e0 would work. If you use anything other than E/e then it will work like your second example.
For more information on the format of floating point numbers see: Cppreference floating point literal

Getting an infinite loop in Babylonian Algorithm for square roots in C++

I have thoroughly searched for this topic all over the internet, and the threads are either dead, or use a different method than what is described in my book.
For example, http://www.geeksforgeeks.org/square-root-of-a-perfect-square/ . This doesn't work for me because my algorithm needs to loop until it reaches 1% of the last "guess".
Here is the question from the text.
The Babylonian algorithm to compute the square root of a number n is as follows:
Make a guess at the number (you can pick n/2 as your initial guess).
Compute r = n / guess
Set guess = (guess + r) / 2
Go back to step 2 for as many iterations as necessary. The more that steps 2 and 3 are repeated, the closer guess will become to the
square root of n.
Write a program that inputs an integer for n, iterates through the
Babylonian algorithm until guess is within 1% of the previous guess,
and outputs the answer as a double.
I have written the following code:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
int main()
{
int n;
double r, guess(4), lastGuess;
cout << "Enter a number to find the square root of: ";
cin >> n;
do
{
r = n / guess;
lastGuess = guess;
guess = ( guess + r ) / 2;
// cout <<"Guess: " << guess << endl;
// cout <<"Last Guess: " << lastGuess << endl;
cout << "Guess : " << guess << endl;
cout << "Last Guess 1% = " << lastGuess + ( lastGuess * 0.01 ) << endl;
cout << "r = " << r << endl;
} while( guess >= lastGuess * 0.01 );
cout << r;
return 0;
}
The program computes the right answer for r, but the loop doesn't terminate despite guess being greater than 1% added to lastGuess.
This program produces the following output when inputting 144 as n.
....
r = 12
Guess : 12
Last Guess 1% = 12.12
r = 12
Guess : 12
Last Guess 1% = 12.12
r = 12
Guess : 12
Last Guess 1% = 12.12
r = 12
Guess : 12
Last Guess 1% = 12.12
....
The root (r) is correct (12). The guess is LESS than lastGuess (12 < 12.12), which should return a false to the condition, correct?. Why is the loop not ending?
If you want to add 1% you need to multiply by 1.01, not 0.01.
while( guess >= lastGuess * 1.01 );
By the way, this iterates while guess is growing by more than 1%. You should also allow for the opposite, that it may have shrunk by more than 1%. The approximation could approach the answer from either direction. (It will approach positive roots from the right and negative roots from the left.)
While printing your lastGuess you are using
lastGuess + ( lastGuess * 0.01 )
But while checking loop condition you are using
lastGuess*0.01
So in loop condition use the same equation which you are using for printing lastGuess value.
To properly exit the loop, use something similar to this.
void f(int N)
{
double x = N / 4;
double prev = 0.0f;
while(1)
{
x = 0.5 * (x + N / x);
if (prev == x)
break;
prev = x;
printf("val: %f\n", x);
}
printf("SQRT(%d) = %f\n", N, x);
}
I had the same problem in my book. This is what I wrote and it works perfect.
#include <iostream>
using namespace std;
int main()
{
double guess, root, previousGuess;
int number;
cout << "Enter a number to find the Babylonian square root.\n";
cin >> number;
cout << "You want to find the square root of " << number << ".\n";
cout << "Enter a guess for the square root.\n";
cin >> guess;
do
{
root = number / guess;
previousGuess = guess;
guess = (guess + root ) / 2;
} while(guess < 0.99*previousGuess || guess > 1.01*previousGuess);
cout << "The answer is " << guess << ".\n";
return 0;
}

Simple C++ input files and if statements

I wrote the code and it works except the total is wrong. It is supposed to multiply the distanceRate by the rate and add each cost to make the total, but it's not doing that. Any help would be appreciated.
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
//Declare Variables
ifstream inFile;
double packageWeight;
double distance;
double totalCharge = 0;
double rate;
double distanceRate;
int customerNumber;
double shippingCharge;
int packageCount = 0;
inFile.open("shipping.txt");
if(inFile)
{
cout << "Customer Package Shipping" << endl;
cout << "Number Weight Distance" << endl;
while(!inFile.eof())
{
inFile >> customerNumber;
inFile >> packageWeight;
inFile >> distance;
if(0 < packageWeight <= 2)
rate = 1.10;
else if(2 < packageWeight <=6)
rate = 2.20;
else if(6 < packageWeight <= 10)
rate = 3.70;
else if(10 < packageWeight <=20)
rate = 4.80;
else
cout << "Invalid package weight" << endl;
if( 0 < distance <= 500)
distanceRate = 1;
else if( 500 < distance <= 1000)
distanceRate = 2;
else if(1000 < distance <= 1500)
distanceRate = 3;
else if(1500 < distance <= 2000)
distanceRate = 4;
else
cout << "Invalid distance" << endl;
packageCount += customerNumber;
shippingCharge = rate * distanceRate;
totalCharge += shippingCharge;
cout << fixed << setprecision(2) << showpoint;
cout << setw(2) << customerNumber
<< right << setw(14) << packageWeight
<< setw(13) << distance
<< endl;
} //End of while loop
cout << "\nPackage shipped : " << packageCount << endl;
cout << "Total Charge : $" << totalCharge << endl;
inFile.close();
}
else
{
cout << "Could not open file" << endl;
}
system("pause");
return 0;
}
Some issues that I see in the snippet you gave me are as follows:
As pointed out by billz in a comment, your if statements are invalid. The statement if( 0 < distance <= 500) is not doing what you expect, it evaluates from left to right, so you have 0 < distance (lets say that evaluates to true) so then you have true <= 1000 which isn't going to give the results that you think it will. This actually needs to be broken apart into two separate comparisons like distance > 0 && distance < 500.
As I noted in my comment, you're adding the customer number to the package count, this will most likely always give a wrong value for package count. If your customer numbers are 1, 2, 3, 4 then you claim the package count is 10 when it's actually only 4 (forgive me if I misunderstood the purpose of this field).
You have no default value for distanceRate but you still use it in an operation (possibly uninitialized) which will give unexpected results (as you are seeing). In your else, you should actually give it a dummy value that way you guarantee that it will always be set. You also do reset it, so if it gets set to 4, and then next distance fails the tests and enters the else, you have another calculation on the variable as 4 instead of it's default value. You should initialize any variable that you plan to use unless you have explicit reason not to give it a value at initialization, and anytime you use a variable in a loop you should reset it's value at the start of the loop.
Additional Note (EDIT)
I wouldn't recommend using system("pause"); as it does a lot more behind the scenes than you would want in a simple pause, a better approach I've seen used is:
#include <iostream>
#include <conio.h>
using namespace std;
int main() {
cout << "Press any key to continue!";
_getch();
cout << "Finished";
return 0;
}
EDIT 2
If statments can contain a single line or a code block to execute.
Single line:
if (someValueIsTrue)
executeThisFunction();
Code block:
if (someValueIsTrue) {
executeThisFunction();
alsoThisFunction();
}
Anytime you need to execute more than one statement in an if/else/while/for/do...while/etc... you'll need a code block. I imagine (based on your explanation) that you did:
if (blah)
// ....
else
distanceRate = 0;
cout << "Invalid Distance";
And the compiler only sees that you have the distanceRate = 0 nested in the loop, the cout statement is actually not part of the else but part of the previous block of code. You need to use a code block here.
!inFile.eof() // incorrect
inFile.good() // correct
read on eof() it doesn't do what you might think it does.
if( 0 < distance <= 500) // all the if statements are incorrect
if(distance>0 && distance<=500) // correct
The way you wrote the if condition, it does not do what you think it does.

Need help in basic C++ regarding how to properly loop through part and finding smallest value

Hi I'm needing some help. I'm in a intro to programming class and we are using c++. I am hoping someone can help me with an assignment that was due yesterday (I understand not to expect miracle responses but a girl can always try).
I'm having two problems that I know of. The first is regarding the smallest value.
The big one is in trying to make it loop for requirements of three times but not lose out on my total count. I cannot use arrays or anything I haven't learned yet which is why I've posted this. I've seen similar problems and questions but they have ended up with answers too complex for current progress in class. So here is the problems instructions:
Instructions
1) Write a program to find the average value, the largest value, and the smallest value of a set of numbers supplied as input from the keyboard. The number of values in the data set must be in the range 0 to 20, inclusive. The user will first enter the number of values in the data set(use variable int Number). Give the user 3 attempts at entering Number in the range given. If the value for Number entered is out of this range, write an error message but continue. If the user does not enter a valid value for Number within the 3 attempts print an error message and terminate the program.
2) Format only the output for the Average value to 3 decimal places when printed.
3) The values in the data set entered as input can be any value positive, negative, or zero.
4) Make the program output readable(see the example below). (Note: that you will notprint out the input values that were entered in this program like you normally are required to do. This is because we have not covered the “tool” needed to do so yet in our studies).
Below will be the output from the execution of your program:
(using these values in order for the data set --> 19.0 53.4 704.0 -15.2 0 100.0)
The largest number: 704
The smallest number: -15.2
The average of the 6 numbers entered: 143.533
yourName L4p2XX.cpp
Lab#4 prob 2 XX-XX-12
Here is my poor excuse at the solution:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double Number = 0, minValue, maxValue, average, total = 0;
int ct = 0, numCount;
cout << "How many numbers would you like to enter? ";
cin >> numCount;
for(ct = 1; ct <= numCount; ct += 1)
{
cout << "Enter Value from 0 to 20, inclusive: ";
cin >> Number;
if(Number > 20|| Number < 0)
for(int errorCt = 1; errorCt <= 4; errorCt += 1)
{
if(errorCt == 4)
{
cout << "You have had 3 attempts to enter a valid" <<
"number. \nPlease try this program again when you" <<
"are able to follow directions.";
cout <<"\nLBn\n"<<"L4P2LB.cpp\n"<<"11-05-12\n";
return 0;
}
cout << Number << "is not within range.\n" <<
"Please enter a number from 0 to 20: ";
cin >> Number;
} //end for loop
total += Number;
if(maxValue <= Number)
maxValue = Number;
if(Number <= minValue)
minValue = Number;
} //end for loop
cout << "The smallest number entered was " << minValue << endl;
cout << "The largest number you entered was " << maxValue << endl;
average = total/numCount;
cout << setprecision(3) << fixed << showpoint << "You entered " <<
numCount << " numbers. The average of these is " << average;
//Program ID
cout <<"\n" << "L4P2LB.cpp\n" << "11-05-12\n";
system ("pause");
return 0;
} // End main
Thank you in advance to anyone who can steer me in the right direction. Not looking for anyone to do my work I just need help in direction if nothing else or any suggestions as to what to do. Thanks again. Lynda
Also I need somehow to pause after the third time and exit properly. If I put the second pause in it won't work so am I missing something obvious there too!
The first problem I see is that you didn't initialize a couple of variables.
You should either initialize both minValue and maxValue variables with something which will overwritten in every case in the first loop (typically "positive/negative infinity", as provided by <limits>), or just set both to Number in the first iteration, regardless of their current value. So I'd suggest to fix this by replacing
if(maxValue <= Number)
maxValue = Number;
if(Number <= minValue)
minValue = Number;
with
if(maxValue <= Number || ct == 1)
maxValue = Number;
if(Number <= minValue || ct == 1)
minValue = Number;
as ct == 1 will be true in the first iteration.
That said, you check the 0..20 range condition on the wrong variable. You check it on the Number variable, but you should check the numCount variable. But you also didn't respect the requirement that the variable to store the "number of numbers" should be Number, so you did check the correct variable, but used the wrong to read the input into. This should fix this issue (I changed the variable name in the cin >>... line + moved the check outside your main loop):
cout << "How many numbers would you like to enter? ";
cin >> Number;
if(Number > 20|| Number < 0)
{
for(int errorCt = 1; errorCt <= 4; errorCt += 1)
...
if(errorCt == 4)
{
cout << "You have had 3 attempts to enter a valid" <<
"number. \nPlease try this program again when you" <<
"are able to follow directions.";
cout <<"\nLBn\n"<<"L4P2LB.cpp\n"<<"11-05-12\n";
return 0;
}
cout << Number << "is not within range.\n" <<
"Please enter a number from 0 to 20: ";
cin >> Number;
} //end for loop
}
for(ct = 1; ct <= Number; ct += 1)
{
...
}
...