Interval for bisection method - c++

I've been assigned a project to determine the square root of a number without using division or the math.h library. Upon doing my own research I've decided to tackle the problem by using the bisection method. I used the pseudo code portion from the Bisection Wikipedia page:
https://en.wikipedia.org/wiki/Bisection_method#Example:_Finding_the_root_of_a_polynomial
to setup the algorithm.
My Code
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
void __attribute__((weak)) check(double alt_sqrt(double));
//default check function - definition may be changed - will not be graded
void __attribute__((weak)) check(double alt_sqrt(double))
{
if(alt_sqrt(123456789.0) == sqrt(123456789.0))cout << "PASS\n";
else cout << "FAIL\n";
return;
}
//change this definition - will be graded by a different check function
double my_sqrt(double x)
{
int i = 0;
double a = 0.0; // Lower Bound
double b = x + 1; // Upper Bound
double c = 0.0; // Guess for square root
double error = 0.00001;
double fc = 0.0;
while(i < 10000)
{
c = (a+b)*0.5;
fc = c * c - x;
if(abs(fc) < error || (b-a)*0.5 < error) // Check for solution
{
cout << "Square root is: " << c << endl;
break;
}
if(fc < 0) // Setup new interval
{
a = c;
cout << "a is: " << a << endl;
}
else b = c;
cout << "b is: " << b << endl;
i++;
}
return c;
}
//Do not change this function
int main()
{
check(my_sqrt);
return 0;
}
The output I am currently getting for my professor's test case in main is
Square root is: 1.23457e+08
FAIL
When the correct output should be
Square root is: 11,111.11106
PASS
I believe that I am going wrong in the way that I setup my new intervals. My thinking is that if the difference between the two values is negative, then I need to push the lower bound up, and if the difference is positive, then I need to bump the upper bound down.
I would appreciate any advice y'all could give me. Thank you for your time.

The condition fb - fa < 0 is wrong because ignoring floating-point errors, fa < fb, which is a * a - x < b * b < x will be always true for 0 <= a < b.
Changing the condition to fc < 0 improved the accuracy, but unfortunately this improvement coundl't make the program print "PASS". To improve the accuracy to have the program print "PASS", delete the harmful breaking part
if(abs(fc) < error || (b-a)*0.5 < error) // Check for solution
{
cout << "Square root is: " << c << endl;
break;
}
Removing this harmful breaking and adding the line
cout << "Square root is: " << c << endl;
just before
return c;
gave me
Square root is: 11111.1
PASS
but unfortunately this is not what you want.
To have what you want printed,
#include <iomanip>
should be added and the printing part should be
std::cout.imbue(std::locale(""));
cout << fixed << setprecision(5) << "Square root is: " << c << endl;

Related

Specific right-angled Triangles are not being recognized as right-angled in Cpp

I have to take the coordinates of the vertices of a triangle from the user and tell if it is a right-angled triangle or not. I'm using Pythagoras Theorem to Find out i.e. h * h = b * b + p * p
But surprisingly this doesn't work for some specific right-angled triangles.
Here is one such Triangle:
Vertex A: (x, y) = (1, 3)
Vertex B: (x, y) = (1, 1)
Vertex C: (x, y) = (5, 1)
It calculates perfectly, which I figured out by printing the calculation, but still doesn't work.
Then I tried by using sqrt() function from the cmath library this way:
h = sqrt(b * b + p * p)
Logically it is the same, but it worked.
I want to understand, why the earlier method is not working?
Here is a simplified version of My Code:
#include <iostream>
#include <cmath>
using namespace std;
class Vertex {
double x, y;
public:
void take_input(char obj) {
cout << endl << " Taking Coordinates of Vertex " << obj << ": " << endl;
cout << " Enter the x component: ";
cin >> x;
cout << " Enter the y component: ";
cin >> y;
}
double distance(Vertex p) {
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
return dist;
}
};
class Triangle {
Vertex a, b, c;
public:
void take_inp(string obj) {
cout << endl << "Taking Vertices of the Triangle " << obj << ": " << endl;
cout << " Verteces should be in a counter clockwise order (as per convention)." << endl;
a.take_input('A');
b.take_input('B');
c.take_input('C');
}
void is_rt_ang() {
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
/*
// Strangely this attempt works which is logically the same:
double h = a.distance(c);
double bp = sqrt(a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c));
*/
if (h == bp) {
cout << "Angle is 90" << endl;
cout << h << " = " << bp << endl;
cout << "It is Right-Angled" << endl;
}
else {
cout << "Angle is not 90!" << endl;
cout << h << " != " << bp << endl;
cout << "It is Not a Right-Angled" << endl;
}
}
};
int main()
{
Triangle tri1, tri2;
tri1.take_inp("tri1");
tri1.is_rt_ang();
return 0;
}
The line
double dist = sqrt((x-p.x)*(x-p.x) + (y-p.y)*(y-p.y));
in the Vertex::distance method gives you an approximation of a square root which is rarely going to coincide with an exact answer. This is because most real numbers can't be represented in floating point arithmetic.
But in given code sample you can make do without sqrt. Replace Vertex::distance method with a method
double distance_square(Vertex p) {
double dist_square = (x-p.x)*(x-p.x) + (y-p.y)*(y-p.y);
return dist_square;
}
and call it like this in Triangle::is_rt_ang:
double h = a.distance_square(c);
double bp = a.distance_square(b) + b.distance_square(c);
This solution is still flawed because floating-point multiplication is also a subject to rounding errors. But if it is guaranteed that you are going to work only with integer coordinates, you can replace all doubles in your code with ints and for them there is no problem with multiplication (besides possibly going out of bounds for large numbers).
EDIT: Also a comment on printing
It calculates perfectly, which I figured out by printing the
calculation, but still doesn't work.
When you print doubles you need to set precision manually in order to avoid rounding. If in your code I replace a line
cout << h << " != " << bp << endl;
with
cout << std::setprecision(std::numeric_limits<double>::digits10) << std::fixed << h << " != " << bp << endl;
then for example triangle from the question I get the output
Angle is not 90!
20.000000000000004 != 20.000000000000000
It is Not a Right-Angled
For this to compile you will need to add #include <limits> and #include <iomanip>.
In your is_rt_ang function you're assuming that your hypotenuse is always going to be the edge AC, but it doesn't seem like you're doing anything to verify this.
double h = a.distance(c)*a.distance(c);
double bp = a.distance(b)*a.distance(b) + b.distance(c)*b.distance(c);
You could try getting the squares of all your distances first, (AC)^2, (AB)^2, and (BC)^2, then finding the candidate for hypotenuse by taking the max value out of the three, then do something like:
bool isRightTriangle = max == (min1 + min2)
You may also be running into some kind of round-off error with floating point numbers. It is common to use a an epsilon value when comparing floating point numbers because of the inherent round-off errors with them. If you don't need floating point values maybe use an integer, or if you do need floating point values try using an epsilon value in your equalities like:
abs(h - bp) <= epsilon
You should be able to find more information about floating point values, round-off errors, and machine epsilons on the web.
Here is a link to a SO Q/A that talks about floating point math that may be a good resource for you: Is floating point math broken?

How do we use a float and double variable to calculate and print an operation in C++?

To clarify, this is a lab for class. I'm just learning all the fundamentals right now. I am trying to figure out how to print the total using a float variable AND a double variable (I thought we can just choose one or the other) while using loop mechanisms (while, do-while or for). I decided to go with the for loop. Any suggestions would be helpful. What I have now prints every single fraction until it gets to the very last one. I tried different variations but so far I got nothing.
I need help calculating the total for:
1/1 + 1/2 + 1/3 + 1/4 +....... 1/99999999 + 1/100000000
This is what I have so far:
#include <iostream>
using namespace std;
int main()
{
float answer = 0;
int num;
for (int den = 1; den <= 100000000; ++den)
{
num = 1;
cout << num << "/" << den;
if (den == 100000000)
cout << " = " << endl;
else
cout << " + ";
answer += ( (float)num ) / ( (float)den );
}
cout << answer << endl;
}
Thanks!
At any point in time, your program has to be using either a float or a double, so I guess you're wanting to reuse your calculation code for each of those types in turn. Here's an example of how to do the calculation twice using a template - first for float, then for double:
#include <iostream>
template <typename T>
void calculate()
{
T answer = 0;
for (int den = 1; den <= 100000000; ++den)
answer += T(1) / T(den);
std::cout << answer << '\n';
}
int main()
{
calculate<float>();
calculate<double>();
}

Boundary value analysis in C++ with CppUnit

I'm trying to implement boundary tests in CppUnit. I want to check the limit value itself as well as the boundaries around this limit.
For the upper boundary I wanted to add the smallest inkrement possible. For double this increment can be accessed with
numeric_limits<double>::epsilon()
However, if I add epsilon to my limit I get Not-a-Number (NaN) as result:
#include <stdio.h>
#include <iostream>
#include <limits>
#include <math.h>
using namespace std;
const double WARNING_LIMIT = 8000.0;
int main(void) {
double warningLowerLimit = WARNING_LIMIT - numeric_limits<double>::epsilon();
if(warningLowerLimit < WARNING_LIMIT ) {
cout << "lower" << endl;
}
else if (warningLowerLimit > WARNING_LIMIT) {
cout << "upper" << endl;
}
else if ( fabs(warningLowerLimit) < 0.001) {
cout << "same" << endl;
}
else {
cout << "NaN" << endl; // <-- result
}
}
Can somebody please explain me, why the result is not lower that the limit?
Best regards
else if ( fabs(warningLowerLimit) < 0.001) {
cout << "same" << endl;
}
That should be
fabs(warningLowerLimit - WARNING_LIMIT)
there. Without checking the difference, you get to the cout << "NaN" if warningLowerLimit == WARNING_LIMIT for example.

Increment double by smallest possible valueTest

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 );
}
}

Handling an 'else' type situation within a loop

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.