Wrong answer on bisection method program (C++) - c++

I am solving the typical bisection method task but with fixed tolerance (1e-20), fixed interval (0, 10) and given function: x^5 - a*x - 84422%100, where user inputs a as a parameter.
For the example with a = 5 I should get the answer 2.3227751229355622988 with precision 20 digits after floating point but I get 2.50000000000000000000. Where am I wrong here is my code:
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
const double e = 1e-20;
const int fn = 84422;
double f(int a, int x)
{
double y = x * x * x * x * x - a * x - fn % 100;
return (double)y;
}
int main()
{
double lv, rv, midv, mid, root, tol;
int left = 0;
int right = 10;
int a;
cin >> a;
do
{
mid = (left + right) / 2.0;
rv = f(a, right);
lv = f(a, left);
midv = f(a, mid);
if(midv == 0)
{
root = mid;
break;
}
if(midv * lv < 0)
{
right = mid;
}
else
left = mid;
} while ((right - left) > e);
root = (left + right) / 2.0;
cout << " The Root is approximately: ";
cout << fixed << setprecision(20) << root << endl;
cin.get();
cin.get();
return 0;
}

Your left and right are integers.
When you assign mid to them, you lose significant digits (all of them virtually).
Change them to be doubles.

Related

Floating point inaccuracies breaks idempotence in weird ways

I was wondering how bad floating point inaccuracies can get when normalizing vectors, specifically a 3D one. Normalizing once should give the same value as normalizing twice, but, as expected, floating point inaccuracies don't guarantee us that. So I decided to test some other things: if you normalize indefinitely, will it always "converge" to a value that normalizes to itself? The answer is no. For example, a few seconds testing and I found a value that loops between 2: -0.60445204839058564 -0.54547899327834748 -0.58059485795902943 and -0.60445204839058575 -0.54547899327834759 -0.58059485795902954. Some "converge" after 3, 5 steps. Here's my boring code:
#include <iostream>
#include <numeric>
#include <random>
using namespace std;
struct Point
{
double x, y, z;
bool operator==(const Point& o) const
{
return
x == o.x &&
y == o.y &&
z == o.z;
}
};
auto square(auto x)
{
return x * x;
}
Point normalize(const Point& p)
{
auto l = sqrt(square(p.x) + square(p.y) + square(p.z));
return { p.x / l, p.y / l, p.z / l };
}
std::mt19937 mt(24);
std::uniform_real_distribution d(-1., 1.);
int main()
{
while (true)
{
auto
x = d(mt),
y = d(mt),
z = d(mt);
Point p{ x, y, z };
auto
n1 = normalize(p),
n2 = normalize(normalize(p));
int cnt = 1;
while (n1 != n2)
{
n1 = n2;
cnt++;
n2 = normalize(n2);
auto len = square(n2.x) + square(n2.y) + square(n2.z);
if (len != 1.)
{
__debugbreak();
}
}
if (cnt != 2)
{
cout << x << ' ' << y << ' ' << z
<< " took " << cnt << '\n';
}
}
}
So I have a few curiosities:
What inputs create the longest loop/cycle and never converge?
What inputs take longest to converge?
After normalizing once, what input gives the maximum error from a length of 1?

Cross the yard without getting wet

Here is the question:
There is a house with a backyard which is square bounded by
coordinates (0,0) in the southwest to (1000,1000) in
the northeast. In this yard there are a number of water sprinklers
placed to keep the lawn soaked in the middle of the summer. However,
it might or might not be possible to cross the yard without getting
soaked and without leaving the yard?
Input The input starts with a line containing an integer 1≤n≤1000, the
number of water sprinklers. A line follows for each sprinkler,
containing three integers: the (x,y)(x,y) location of the sprinkler
(0≤x,y,≤10000) and its range r (1≤r≤1000). The sprinklers will soak
anybody passing strictly within the range of the sprinkler (i.e.,
within distance strictly less than r).
The house is located on the west side (x=0) and a path is needed to
the east side of the yard (x=1000).
Output If you can find a path through the yard, output four real
numbers, separated by spaces, rounded to two digits after the decimal
place. These should be the coordinates at which you may enter and
leave the yard, respectively. If you can enter and leave at several
places, give the results with the highest y. If there is no way to get
through the yard without getting soaked, print a line containing
“IMPOSSIBLE”.
Sample Input
3
500 500 499
0 0 999
1000 1000 200
Sample output
0.00 1000.00 1000.00 800.00
Here is my thought process:
Define circle objects with x,y,r and write a function to determine if a given point is wet or not(inside the circle or not) on the circumference is not wet btw.
class circle {
int h;
int k;
int r;
public:
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
};
bool iswet(pair<int,int>* p){
if (pow(this->r - 0.001, 2) > (pow(p->first - this->h, 2) +
pow(p->second - this->k, 2) ) ) {
return true;
}
else
return false;
};
Then implement a depth first search, prioritizing to go up and right whenever possible.
However since circles are not guaranteed to be pass on integer coordinates an the result is expected in floats with double precision (xxx.xx). So if we keep everything in integers the grid suddenly becomes 100,000 x 100,000 which is way too big. Also the time limit is 1 sec.
So I thought ok lets stick to 1000x1000 and work with floats instead. Loop over int coordinates and whenever I hit a sprinkle just snap in the perimeter of the circle since we are safe in the perimeter. But in that case could not figure out how DFS work.
Here is the latest trial
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <deque>
#include <utility>
#include <unordered_set>
#include <iomanip>
using namespace std;
const int MAXY = 1e3;
const int MAXX = 1e3;
const int MINY = 0;
const int MINX = 0;
struct pair_hash {
inline std::size_t operator()(const std::pair<int,int> & v) const {
return v.first*31+v.second;
}
};
class circle {
int h;
int k;
int r;
public:
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
};
bool iswet(pair<float,float>* p){
if (pow(this->r - 0.001, 2) > (pow(p->first - this->h, 2) + pow(p->second - this->k, 2) ) ) {
this->closest_pair(p);
return true;
}
else
return false;
};
void closest_pair(pair<float,float>* p){
float vx = p->first - this->h;
float vy = p->second - this->k;
float magv = sqrt(vx * vx + vy * vy);
p->first = this->h + vx / magv * this->r;
p->second = this->k + vy / magv * this->r;
}
};
static bool test_sprinkles(vector<circle> &sprinkles, pair<float,float>* p){
for (int k = 0; k < sprinkles.size(); k++)
if (sprinkles[k].iswet(p)) return false;
return true;
}
int main(){
int n; // number of sprinkles
while (cin >> n){
vector<circle> sprinkles_array;
sprinkles_array.reserve(n);
int h, k, r;
while (n--){
cin >> h >> k >> r;
sprinkles_array.push_back(circle(h, k, r));
}/* code */
pair<float,float> enter = make_pair(0, MAXY);
deque<pair<float,float>> mystack;
mystack.push_back(enter);
pair<float,float>* cp;
bool found = false;
unordered_set<pair<float, float>, pair_hash> visited;
while (!mystack.empty()){
cp = &mystack.back();
if (cp->first == MAXX) {
found = true;
break;
}
visited.insert(*cp);
if (cp->second > MAXY || cp->second < MINY || cp ->first < MINX ) {
visited.insert(*cp);
mystack.pop_back();
continue;
}
if (!test_sprinkles(sprinkles_array,cp)) {
continue;
}
pair<int,int> newpair = make_pair(cp->first, cp->second + 1);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first + 1 , cp->second);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first, cp->second - 1);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
newpair = make_pair(cp->first - 1, cp->second);
if (visited.find(newpair) == visited.end()) {
mystack.push_back(newpair);
continue;
}
else visited.insert(newpair);
mystack.pop_back();
}
cout << setprecision(2);
cout << fixed;
if (found){
double xin = mystack.front().first;
double yin = mystack.front().second;
pair <float, float> p = mystack.back();
p.second++;
for (int k = 0; k < sprinkles_array.size(); k++)
if (sprinkles_array[k].iswet(&p)) break;
double xout = p.first;
double yout = p.second;
cout << xin << " " << yin << " " << xout << " " << yout << endl;
}
else
{
cout << "IMPOSSIBLE" << endl;
}
}
}
Yes #JosephIreland is right. Solved it with grouping intersecting (not touching) circles. Then these groups have maxy and min y coordinates. If it exceeds the yard miny and maxy the way is blocked.
Then these groups also have upper and lower intersection points with x=0 and x=1000 lines. If the upper points are larger than the yard maxy then the maximum entry/exit points are lower entery points.
#include <iostream>
#include <cmath>
#include <string>
#include <vector>
#include <utility>
#include <iomanip>
using namespace std;
const int MAXY = 1e3;
const int MAXX = 1e3;
const int MINY = 0;
const int MINX = 0;
struct circle {
int h;
int k;
int r;
float maxy;
float miny;
circle();
circle(int h, int k, int r){
this->h = h;
this->k = k;
this->r = r;
this->miny = this->k - r;
this->maxy = this->k + r;
};
};
struct group {
float maxy = -1;
float miny = -1;
vector<circle*> circles;
float upper_endy = -1;
float upper_starty = -1;
float lower_endy = -1;
float lower_starty = -1;
void add_circle(circle& c){
if ((c.maxy > this->maxy) || this->circles.empty() ) this->maxy = c.maxy;
if ((c.miny < this->miny) || this->circles.empty() ) this->miny = c.miny;
this->circles.push_back(&c);
// find where it crosses x=minx and x= maxx
float root = sqrt(pow(c.r, 2) - pow(MINX - c.h, 2));
float y1 = root + c.k;
float y2 = -root + c.k;
if (y1 > this->upper_starty) this->upper_starty = y1;
if (y2 > this->lower_starty) this->lower_starty = y2;
root = sqrt(pow(c.r, 2) - pow(MAXX - c.h, 2));
y1 = root + c.k;
y2 = -root + c.k;
if (y1 > this->upper_endy) this->upper_endy = y1;
if (y2 > this->lower_endy) this->lower_endy = y2;
};
bool does_intersect(circle& c1){
for(circle* c2 : circles){
float dist = sqrt(pow(c1.h - c2->h,2)) + sqrt(pow(c1.k - c2->k,2));
(dist < (c1.r + c2->r)) ? true : false;
};
};
};
int main(){
int n; // number of sprinkles
while (cin >> n){
vector<circle> sprinkles_array;
sprinkles_array.reserve(n);
int h, k, r;
while (n--){
cin >> h >> k >> r;
sprinkles_array.push_back(circle(h, k, r));
}/* code */
vector<group> groups;
group newgroup;
newgroup.add_circle(sprinkles_array[0]);
groups.push_back(newgroup);
for (int i = 1; i < sprinkles_array.size(); i++){
bool no_group = true;
for (group g:groups){
if (g.does_intersect(sprinkles_array[i])){
g.add_circle(sprinkles_array[i]);
no_group = false;
break;
}
}
if (no_group) {
group newgroup;
newgroup.add_circle(sprinkles_array[i]);
groups.push_back(newgroup);
}
}
float entery = MAXY;
float exity = MAXY;
bool found = true;
for (group g : groups){
if ((g.miny < MINY) && (g.maxy > MAXY)){
found = false;
break;
}
if (g.upper_starty > entery)
entery = g.lower_starty;
if (g.upper_endy > exity)
exity = g.lower_endy;
}
cout << setprecision(2);
cout << fixed;
if (found){
cout << float(MINX) << " " << entery << " " << float(MAXX) << " " << exity << endl;
}
else
{
cout << "IMPOSSIBLE" << endl;
}
}
}

Sum to infinity of geometric sequence

Question:
Write C++ function to evaluate the following formula for a given x:
The following code was designed in C++ on Visual Studio to be a solution of the above mentioned problem. However whenever I run the code what I am returned is the value of x; or the same value I input.
I don't understand what the problem may be, so I would appreciate any help given.
#include <iostream>
using namespace std;
unsigned long fact(int n) {
if (n <= 1) {
return 1;
}
else {
return n * fact(n - 1);
}
}
unsigned long f(int x, int n) {
static unsigned long term;
static unsigned long sum = 0;
do {
term = pow(x, (2 * n + 1)) / fact((2 * n) + 1);
n++;
sum += term;
} while (term < 0.000001);
return sum;
}
int main() {
int y = 0;
int x;
cout << "enter x" << endl;
cin >> x;
cout << f(x, y) << endl;
system("pause");
}
I suggest you don't calculate powers and factorials on each iteration. Each next term can be generated by multiplying the previous one by x^2 / [n(n+1)]:
double sinh_in_disguise(const double x) {
const double x_sq = x * x;
double term = x;
double sum = 0;
double n = 2;
while (true) {
const double new_sum = sum + term;
if (new_sum == sum)
break;
sum = new_sum;
term *= x_sq / (n * (n + 1));
n += 2;
}
return sum;
}
int main() {
std::cout.precision(16);
double x = 2.019;
std::cout << sinh_in_disguise(x) << std::endl; // prints 3.699001094869803
std::cout << std::sinh(x) << std::endl; // prints 3.699001094869803
}
put double datatype in the whole code and it will work perfectly

Sin algorithm not working

I made a c++ program that calculates sin without math.h. Im using this algorithm for my program https://ibb.co/bTnQnS. I enter 45 degrees, the program converts degrees to radians, the program uses the algorithm, and the program outputs -0.868597. The program should output 0.70710678 or √2/2. What am I doing wrong with the algorithm?
Code:
#include "stdafx.h"
#include <iostream>
using namespace std;
double sin(int input, int decimal_count);
int factorial(int n);
double deg_to_rad(int deg);
double power(double base, int power);
int main(){
double angle;
int decimal;
cout << sin(45,8) << endl;
//end
system("pause");
return 0;
}
double sin(int input, int accuracy) {
int odds = 3;
double sin;
double rads = deg_to_rad(input);
for (int i = 1; i <= accuracy; i += 1) {
if (i==1) {
sin = power(rads, odds) / factorial(odds);
}
else if (i%2==0) {
sin = (power(rads, odds) / factorial(odds)) + sin;
}
else {
sin = (power(rads, odds) / factorial(odds)) - sin;
}
odds = odds + 2;
}
sin = sin - rads;
return sin;
}
int factorial(int n) {
int fact = 1;
for (int j = 1; j <= n; j+=1) {
fact = fact * j;
}
return fact;
}
double deg_to_rad(int deg) {
return deg*(3.14159265/180);
}
double power(double base, int power) {
double ans = 1;
for (int k = 1; k <= power; k+=1) {
ans = ans * base;
}
return ans;
}
your taylor series expansion function is incorrect. :)
you have to disregard all even terms.
I have fixed it for you (i removed some windows specific stuff as I don;t have a windows machine: the stdfax.h header and the calls to pause were removed)
# include <cstdlib>
# include <iostream>
using namespace std;
double sin(int input, int decimal_count);
int factorial(int n);
double deg_to_rad(int deg);
double power(double base, int power);
int main(){
double angle;
int decimal;
cout << "The sine value is: " << sin(45,8) << endl;
//end
system("sleep 2");
return 0;
}
double sin(int input, int accuracy) {
int odds = 3;
double sin;
double rads = deg_to_rad(input);
bool negative_flag = true;
cout << "You entered " << input << " degrees" << endl;
cout << "This is " << rads << " radians" << endl;
sin = rads;
for (int taylor_term = 3; taylor_term <= 7; taylor_term += 2) {
double term = (double)(power(rads, taylor_term) / factorial(taylor_term));
if (negative_flag) {
term = -1 * term;
}
negative_flag = !(negative_flag);
sin += term;
}
return sin;
}
int factorial(int n) {
int fact = 1;
for (int j = 1; j <= n; j+=1) {
fact = fact * j;
}
return fact;
}
Running this output
You entered 45 degrees
This is 0.785398 radians
The sine value is: 0.707106
Explanation
The taylor series expansion for sine is a series of terms with odd taylor's coefficients that alternate in sign. In my code the alternating signs is effected by the flag. I've also taken into account only the first 3 terms of the taylor series expansion.
Other than that, the line double term = (double)(power(rads, taylor_term) / factorial(taylor_term)); calculates every term in the taylor series expansion.
negative_flag = !(negative_flag); resets the flag sign for the next term.
Addressing your comment and where your code was a bit wrong
Below is your sin func with minimal changes to make it work.
What you were doing wrong
These are just minimal edits, performing these edits would naturally be followed up with some code style cleanup. eg: the if and else block(not else if) have almost the exact same code
sin was not being initialized before being modified
the attribution to correct signs the taylor terms in the if blocks was not correct.
the extra subtraction of rads at the end from sin was not required. Once these things were fixed, your code works :)
int odds = 3;
double sin ;
double rads = deg_to_rad(input);
sin = rads;
for (int i = 1; i <= accuracy; i += 1) {
if (i==1) {
sin = sin - power(rads, odds) / factorial(odds);
}
else if (i%2==0) {
sin = (power(rads, odds) / factorial(odds)) + sin;
}
else {
sin = -(power(rads, odds) / factorial(odds)) + sin;
}
odds = odds + 2;
}
return sin;

terminated by signal SIGSEGV (Address boundary error) in recursive function

I'm trying to implement Karatsuba algorithm for multiplication. I'm kinda follow the pseudocode in this wiki page. But I'm always getting this error:
terminated by signal SIGSEGV (Address boundary error)
When I replaced the lines that cause the recursion to happen with something else:
z0 = multiply(a, c);
z1 = multiply(b, d);
z2 = multiply(a+b, c+d);
the error disappeared.
Here's my code:
#include <iostream>
#include <math.h>
long int multiply(int x, int y);
int get_length(int val);
int main()
{
int x = 0, y = 0;
long int result = 0;
std::cout << "Enter x: ";
std::cin >> x;
std::cout << "Enter y: ";
std::cin >> y;
result = multiply(x, y);
std::cout << "Result: " << result << std::endl;
return 0;
}
long int multiply(int x, int y)
{
if(x < 10 || y < 10) {
return x * y;
}
int x_len = get_length(x);
int y_len = get_length(y);
long int z0 = 0 , z1 = 0, z2 = 0;
int a = 0, b = 0, c = 0, d = 0;
a = x / pow(10, x_len);
b = x - (a * pow(10, x_len));
c = y / pow(10, y_len);
d = y - (c * pow(10, y_len));
z0 = multiply(a, c);
z1 = multiply(b, d);
z2 = multiply(a+b, c+d);
return (pow(10, x_len) * z0) + (pow(10, x_len/2) * (z2 - z1 - z0)) + z1;
}
int get_length(int val)
{
int count = 0;
while(val > 0) {
count++;
val /= 10;
}
return count;
}
I found the problem cause.
It was because of these lines:
a = x / pow(10, x_len);
b = x - (a * pow(10, x_len));
c = y / pow(10, y_len);
d = y - (c * pow(10, y_len));
It should be x_len / 2 instead of x_len and the same with y_len. Since it causes the recursion to be infinite.
You are using the pow function to do integer powers. It is not an integer function. Code your own pow function that's suitable for your application. For example:
int pow(int v, int q)
{
int ret = 1;
while (q > 1)
{
ret*=v;
q--;
}
return ret;
}
Make sure to put an int pow(int, int); at the top.