SMPCIRC - Two Circles - c++

I dont know where I have a mistake
It work for the example but the result shows me "bad answer"
THE PROBLEM:
https://www.spoj.com/problems/SMPCIRC/
SMPCIRC - Two Circles
plane-geometry #basics
Given two circles: O1 with the center o1 = (xo1, yo1) and a radius r1
and O2 with the center o2 = (xo2, yo2) and radius r2, please compute
if O1 is inside O2 or if O2 is inside O1.
Input description First t < 1000, the number of test cases. In each of
the following t lines, 6 integers: xo1 yo1 r1 xo2 yo2 r2. Where 0 ≤
xo1, yo1, xo2, yo2 ≤ 10000 and 0 < r1, r2 ≤ 10000.
Output description For each test case print one character: I, if O1 is
inside O2 (or if O2 is inside O1), E, if O1 is internally tangent to
O2 (or if O2 is internally tangent to O1), O, in other cases.
Example
Input: 2 103 104 5 100 100 10 103 104 10 100 100 10
Output: E O
MY CODE:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int t;
cin>>t;
for(int i=0;i<t;i++)
{
double x1, y1, r1, x2, y2, r2, dl;
cin>>x1>>y1>>r1>>x2>>y2>>r2;
dl=sqrt(pow(x2-x1,2) + pow(y2-y1,2));
if(dl+r1==r2)
cout<<"E";
else if(dl+r2==r1)
cout<<"E";
else if (dl+r1<r2)
cout<<"I";
else if(dl+r2<r1)
cout<<"I";
else
cout<<"O";
}
return 0;
}

When using floating point types, a certain amount of numerical errors are to be expected. Sometimes this may be unacceptable for the kind of problem we are trying to solve.
The quote in OP's question, clearly state that the inputted variables are (emphasis mine)
6 integers: xo1 yo1 r1 xo2 yo2 r2. Where 0 ≤ xo1, yo1, xo2, yo2 ≤ 10000 and 0 < r1, r2 ≤ 10000.
Given the nature of the underlying mathematical problem, it's safe to use integer variables for the calculation too, applying just a bit of algebra:
#include <iostream>
constexpr long int square(long int x)
{
return x * x;
}
int main()
{
int t;
// Usually, the input is well defined in this kind of assignments
std::cin >> t;
for(int i=0; i < t; i++)
{
long int x1, y1, r1, x2, y2, r2;
std::cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
// Calculte the square of the distance
long int d2 = square(x2 - x1) + square(y2 - y1);
// Instead of d == r2 - r1, check if d^2 == (r2 - r1)^2
long int dr21 = square(r2 - r1);
if ( d2 > dr21 )
std::cout << "O\n";
else if ( d2 < dr21 )
std::cout << "I\n";
else // This is probably the least likely case
std::cout << "E\n";
}
return 0;
}

You shouldn't use == operator to compare two double values. Use
fabs(a - b) < eps instead of == operator. You can choose eps = 1e-7.
Also print a new line after each output.

Related

Not receiving output even after writing printf("...")

I've written a code to find the reciprocal of a number without using division but rather approximating it using bisection method. Got two doubts. One, what should I keep the lower limit and the upper limit for x? Also is there a faster method to converge from the limits to the required value(reciprocal of the input) rather than just averaging it? And the main doubt, when I try to run it, It just stops after receiving the input number from the user. Any hints so solve that?
Here is the code:
#include<stdio.h>
#include<cstdlib>
#define epsilon 0.0001
float f(float x, float &m)
{
if(m==0)
{
printf("Reciprocal not defined");
return 0.0;
}
else
{
return x+1/m;
}
}
int main(void)
{
float m,g1,x,g2,c;
printf("Enter a number:\n");
scanf("%f",f(x,m));
g1=epsilon;
g2=m;
while(abs(f(g1,m)-f(g2,m))>epsilon)
{
c=(g1+g2)/2;
if(f(g1,m)*f(c,m)<0)
{
g2=c;
}
else if(f(c,m)*f(g2,m)<0)
{
g1=c;
}
}
printf("The reciprocal is approximately %f",c);
}
The code is expected to work as follows:
Enter a number: 5
The reciprocal is approximately 0.2
Enter a number: 0
Reciprocal is not defined
Instead of this, it shows:
Enter a number:
Reciprocal is not defined
(without accepting any input)
Your overall code is far too convoluted and your usage of scanf doesn't make sens.
You probbaly want something like this:
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#define epsilon 0.0001f
int main(void)
{
float m, g1, g2, c, diff;
printf("Enter a number:\n");
scanf("%f", &m);
g1 = epsilon;
g2 = m;
do
{
c = (g1 + g2) / 2;
diff = c * m - 1.0f;
if (diff > 0)
g2 = c;
else
g1 = c;
} while (fabs(diff) > epsilon);
printf("The reciprocal is approximately %f", c);
}
For your question "Also is there a faster method to converge from the limits to the required value (reciprocal of the input) rather than just averaging it?", I have no idea, but searching by bisection is generally rather fast.
Test program that tests for a range of values:
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#define epsilon 0.0001f
int main(void)
{
float g1, g2, c, diff;
for (float m = 1; m < 20; m += 1)
{
g1 = epsilon;
g2 = m;
do
{
c = (g1 + g2) / 2;
diff = c * m - 1.0f;
if (diff > 0)
g2 = c;
else
g1 = c;
} while (fabs(diff) > epsilon);
printf("The reciprocal of %f is approximately %f vs. %f, diff %f\n", m, c, 1/m, c-1/m);
}
}
Live demonstration

Check if three points are coo linear or not

I have got a problem to check if three points form a triangle or not. If it forms a triangle the program should print the square of maximum length of the three sides of the triangle. If not the program will print "Coolinear". Anyways here is a sample of what I have tried:
#include <iostream>
#include <cmath>
using namespace std;
int main () {
double x1,y1,x2,y2,x3,y3;
double area;
double s1,s2,s3;
cin >> x1 >> y1;
cin >> x2 >> y2;
cin >> x3 >> y3;
area = 0.5*abs(((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)));
s1 = ((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2));
s2 = ((x2-x3)*(x2-x3))+((y2-y3)*(y2-y3));
s3 = ((x1-x3)*(x1-x3))+((y1-y3)*(y1-y3));
if (area!=0){
if (s1 >= s2 && s1 >= s3)
cout<<s1<<endl;
if (s2 >= s1 && s2 >= s3)
cout<<s2<<endl;
if (s3 >= s1 && s3 >= s2)
cout <<s3<<endl;
}
else
cout <<"Coollinear";
return 0;
}
I submitted this code on codeforces website as it is my last problem on a contest. It gives me wrong answer at test 9, What else should I use? and Why is my answer wrong?
Anyways Here is the text of the problem:
Like all problem solvers, Meiko loves eating crepe! As we all know, crepe usually served in a triangular shape. Now Meiko wants to know how large can a crepe side be! So he tries to draw a triangle on a plane using three points and calculate the maximum length of the three sides of the triangle. But sometimes he falls asleep as he has been busy with the team preparing the training problems! As a result, the three points he uses may not form a triangle that could represent a piece of crepe! A triangle can represent a piece of crepe only if it has a positive area. So you are here to help Meiko! Given the coordinates Meiko used, determine whether they form a triangle that could represent a piece of crepe or not.
Input
Three integer coordinates (X,Y) that represent the three points Meiko used. Each point on a separate line. (-10^9<=X,Y<=10^9)
Output
If the points form a triangle that can represent a piece of crepe, print the square of the maximum length of the three sides of the triangle. Otherwise print "Collinear" without quotes.
If at least two sides have same length and are longer than the third one then this code will output multiple results. The three if-statements must be fixed
#include <iostream>
#include <cmath>
using namespace std;
int main () {
double x1,y1,x2,y2,x3,y3;
double area;
double s1,s2,s3;
cin >> x1 >> y1;
cin >> x2 >> y2;
cin >> x3 >> y3;
area = 0.5*abs(((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)));
s1 = ((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2));
s2 = ((x2-x3)*(x2-x3))+((y2-y3)*(y2-y3));
s3 = ((x1-x3)*(x1-x3))+((y1-y3)*(y1-y3));
if (area!=0){
if (s1 >= s2 && s1 >= s3)
cout<<s1<<endl;
else if (s2 >= s1 && s2 >= s3)
cout<<s2<<endl;
else if (s3 >= s1 && s3 >= s2)
cout <<s3<<endl;
}
else
cout <<"Coollinear";
return 0;
}
Your code will output multiple results if the maximum length is not unique.
You can get rid of the complicated logic:
#include <algorithm>
//...
if (area == 0) {
cout << "Collinear";
}
else {
cout << max({s1, s2, s3}));
}
Late addendum, in case this hasn't been solved yet (and I can't sleep):
The clue to solving this is in the word "integers" in the description.
The test case you're failing on has been constructed so that
(x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)
is non-zero when using floating point, and zero when using integers.
You don't need 0.5 * abs(... to determine whether the area is zero or not, and I expect the following to work:
#include <algorithm>
#include <iostream>
using namespace std;
int square(int x) { return x * x; }
int main () {
int x1, y1, x2, y2, x3, y3;
cin >> x1 >> y1;
cin >> x2 >> y2;
cin >> x3 >> y3;
int area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
if (area != 0){
int s1 = square(x1 - x2) + square(y1 - y2);
int s2 = square(x2 - x3) + square(y2 - y3);
int s3 = square(x1 - x3) + square(y1 - y3);
cout << max(s1, max(s2, s3));
}
else
{
cout <<"Collinear";
}
}

Triangles and Cubic Polynomials?

Given 2 cubic equations of the form (A∗X^3+B∗X^2+C∗X)
find out how many obtuse triangles could be formed from the roots of the 2 equations.
Note that only positive roots could be a triangle side, so any triangle should be formed of 333 positive roots (sides).
Input Constraints:
1≤T≤10^6
(−4∗10^8)≤A1,B1,C1,A2,B2,C2≤(4∗10^8)
Format of the input file:
First line : T i.e number of testcases
For each testcase :
First line : Three space separated integers A1, B1 and C1
Second line : Three space separated integers A2, B2 and C2.
images for test case2
My code is:
#include <iostream>
#include <math.h>
using namespace std;
int* roots()
{
long int a,b,c;
int *x=new int[2];
int determinant;
cin >> a >> b >> c;
determinant = b*b - 4*a*c;
if (determinant > 0) {
x[1] = (-b + sqrt(determinant)) / (2*a);
x[0] = (-b - sqrt(determinant)) / (2*a);
}
else {
x[1] = -b/(2*a);
x[0]=x[1];
}
return x;
}
int main()
{int t;
int *a,*b,x,y,z,c,i;
cin>>t;
do{c=0;
a=roots();
b=roots();
for(i=0;i<2;i++)
{x=a[i]*a[i];
y=b[i]*b[i];
if(x!=0&&y!=0)
{switch(i)
{
case 0:z=a[1]*a[1];
if(((x+y)<z||y+z<x||x+z<y)&&z!=0)
c++;
z=b[1]*b[1];
if(((x+y)<z||y+z<x||x+z<y)&&z!=0)
c++;
break;
case 1:z=a[0]*a[0];
if(((x+y)<z||y+z<x||x+z<y)&&z!=0)
c++;
z=b[0]*b[0];
if(((x+y)<z||y+z<x||x+z<y)&&z!=0)
c++;
break;
}
}
}
cout<<c<<"\n";
t--;
}while(t);
return 0;
}

Durand-Kerner method to find roots of nonlinear equation

I am being asked to find the roots of f(x) = 5x(e^-mod(x))cos(x) + 1 . I have previously used the Durand-Kerner method to find the roots of the function x^4 -3x^3 + x^2 + x + 1 with the code shown below. I thought I could simply reuse the code to find the roots of f(x) but whenever I replace x^4 -3x^3 + x^2 + x + 1 with f(x) the program outputs nan for all the roots. What is wrong with my Durand-Kerner implementation and how do I go about modifying it to work for f(x)? I would be very grateful for any help.
#include <iostream>
#include <complex>
#include <math.h>
using namespace std;
typedef complex<double> dcmplx;
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 1;
double a3 = -3;
double a2 = 1;
double a1 = 1;
double a0 = 1;
return (a4 * pow(x,4) + a3 * pow(x,3) + a2 * pow(x,2) + a1 * x + a0);
}
int main()
{
dcmplx p(.9,2);
dcmplx q(.1, .5);
dcmplx r(.7,1);
dcmplx s(.3, .5);
dcmplx p0, q0, r0, s0;
int max_iterations = 100;
bool done = false;
int i=0;
while (i<max_iterations && done == false)
{
p0 = p;
q0 = q;
r0 = r;
s0 = s;
p = p0 - f(p0)/((p0-q)*(p0-r)*(p0-s));
q = q0 - f(q0)/((q0-p)*(q0-r)*(q0-s));
r = r0 - f(r0)/((r0-p)*(r0-q)*(r0-s0));
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
// if convergence within small epsilon, declare done
if (abs(p-p0)<1e-5 && abs(q-q0)<1e-5 && abs(r-r0)<1e-5 && abs(s-s0)<1e-5)
done = true;
i++;
}
cout<<"roots are :\n";
cout << p << "\n";
cout << q << "\n";
cout << r << "\n";
cout << s << "\n";
cout << "number steps taken: "<< i << endl;
return 0;
}
The only thing I have been changing so far is the dcmplx f function. I have been changing it to
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 5;
double a0 = 1;
return (a4 * x * exp(-x) * cos(x) )+ a0;
}
The Durand-Kerner method that you're using requires the function to be continuous on the interval you are working.
Here we ahve a discrepancy between the mathematical view and the limits of the numeric applications. I'd propose you to plot your function (typing the formula in google will give you a quick overview of course for the real part). You'll notice that:
there are an infinity of roots due to the periodicity of the cosinus.
due to the x*exp(-x) the absolute value quickly rises up beyond the maximum precision that a floating point number can hold.
To understand the consequences on your code, I invite you to trace the different iteration. You'll notice that p, r and s are converging very quicky while q is diverging (apparently on the track of one of the huge peak):
At the 2nd iteration q is already at 1e74
At 3rd iteration already beyond what a double can store.
As q is used in the calculation of p,r and s, the error is propagated to the other terms
At 5th iteration, all terms are at NAN
It then continues bravely through the 100 iterations
Perhap's you could make it work by choosing different starting points. If not, you'll have to use some other method and carefully select the interwall on which you're working.
You should have noted in your documentation of the Durand-Kerner method (invented by Karl Weierstrass around 1850) that it only applies to polynomials. Your second function is far from being a polynomial.
Indeed, because of the mod function it has to be declared as a nasty function for numerical methods. Most of them rely on the continuity of the given function, i.e., if the value is close to zero, there is a good chance that there is a root nearby and if the sign changes on an interval then there is a root in the interval. Even the most basic derivate-free methods as the bisection method or Brents method on the sophisticated end of that class pre-suppose these properties.

What's wrong with my durand-kerner implementation?

Implementing this simple root-finding algorithm.
http://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method
I cannot for the life of me figure out what's wrong with my implementation. The roots keep blowing up and no sign of convergence. Any suggestions?
Thanks.
#include <iostream>
#include <complex>
using namespace std;
typedef complex<double> dcmplx;
dcmplx f(dcmplx x)
{
// the function we are interested in
double a4 = 3;
double a3 = -3;
double a2 = 1;
double a1 = 0;
double a0 = 100;
return a4 * pow(x,4) + a3 * pow(x,3) + a2 * pow(x,2) + a1 * x + a0;
}
int main()
{
dcmplx p(.9,2);
dcmplx q(.1, .5);
dcmplx r(.7,1);
dcmplx s(.3, .5);
dcmplx p0, q0, r0, s0;
int max_iterations = 20;
bool done = false;
int i=0;
while (i<max_iterations && done == false)
{
p0 = p;
q0 = q;
r0 = r;
s0 = s;
p = p0 - f(p0)/((p0-q0)*(p0-r0)*(p0-s0));
q = q0 - f(q0)/((q0-p)*(q0-r0)*(q0-s0));
r = r0 - f(r0)/((r0-p)*(r0-q)*(r0-s0));
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
// if convergence within small epsilon, declare done
if (abs(p-p0)<1e-5 && abs(q-q0)<1e-5 && abs(r-r0)<1e-5 && abs(s-s0)<1e-5)
done = true;
i++;
}
cout<<"roots are :\n";
cout << p << "\n";
cout << q << "\n";
cout << r << "\n";
cout << s << "\n";
cout << "number steps taken: "<< i << endl;
return 0;
}
A half year late: The solution to the enigma is that the denominator should be an approximation of the derivative of the polynomial, and thus needs to contain the leading coefficient a4 as factor.
Alternatively, one can divide the polynomial value by a4 in the return statement, so that the polynomial is effectively normed, i.e., has leading coefficient 1.
Note that the example code in wikipedia by Bo Jacoby is the Seidel-type variant of the method, the classical formulation is the Jordan-like method where all new approximations are simultaneously computed from the old approximation. Seidel can have faster convergence than the order 2 that the formulation as a multidimensional Newton method provides for Jacobi.
However, for large degrees Jacobi can be accelerated using fast polynomial multiplication algorithms for the required multi-point evaluations of polynomial values and the products in the denominators.
Ah, the problem was that the coefficients of an N-degree polynomial have to be specified as
1*x^N + a*x^(N-1) + b*x^(N-2) ... etc + z;
where 1 is the coefficient of the largest degree term. Otherwise the first root will never converge.
You haven't implemented for formulae correctly. For instance
s = s0 - f(s0)/((s0-p0)*(s0-q0)*(s0-r0));
should be
s = s0 - f(s0)/((s0-p)*(s0-q)*(s0-r));
Look again at the wiki article