Condition operators (< , >) do not work in gsl interpolation function - c++

I have a question that seems very unusual to me. I have a condition statement that doesn't work as it should. Particularly, I have
double maxx = *max_element(v1.begin(), v1.end());
if(x > maxx){
cout << x << "\t" << maxx << endl;
}
where v1 is a vector. The weird thing is the output: it gives me equal numbers, i.g.
168.68 168.68
This statement is related to gsl interpolation function. In fact, it duplicates a statement in interp.c:150 that causes an error of gsl: interp.c:150: ERROR: interpolation error. So when a number that should be executed normally comes to the function it actually gives true instead of false and I have no idea why, as the number (x) is actually equal to the maximal value allowed.
P.S.: I have checked the if statement on its own (with elementary entries) and it seems to work fine.
P.P.S.: A piece of code from interp.c:
double gsl_interp_eval (const gsl_interp * interp,
const double xa[], const double ya[], double x,
gsl_interp_accel * a){
double y;
int status;
if (x < interp->xmin || x > interp->xmax)
{
GSL_ERROR_VAL("interpolation error", GSL_EDOM, GSL_NAN);
}
status = interp->type->eval (interp->state, xa, ya, interp->size, x, a, &y);
DISCARD_STATUS(status);
return y;}
So it returns an error even for x = interp->xmax, although it definitely should not.
UPDATE: I changed double to long double in declaration. This fixed some places (I use this function more than once), but not all of them.

Looks like floating point inaccuracy. Try printing the values without limiting the number decimal places or printing (x-maxx) as suggested by Oli Charlesworth.
The usual solution to this kind of problem is to apply a small 'epsilon' on comparisons.

Floating point is a tricky business, especially when comparing values. If the values are very close, they may well print the same, but still be different.
Have a look at:
http://floating-point-gui.de/

Related

Why this program is giving nan is the distance between the points?

Why this program is giving nan is the distance between the points?
I have made it to use friend function and oop concept but whenever i try to find the distance between coords it shows either zero of nan
#include<iostream>
#include<cmath>
using namespace std;
class point{
int x,y;
friend void disCoord(point,point);
public:
point(int a,int b){
x=a;
y=b;
}
void displaypoint(){
cout<<"the point is("<<x<<","<<y<<")"<<endl;
}
};//END OF CLASS
void disCoord(point o1,point o2){
double dis=sqrt(pow(o2.x-o1.x,2)-pow(o2.y-o1.y,2));
cout<<"The distance between point"<<"("<<o1.x<<","<<o1.y<<") and point"<<"("<<o2.x<<","
<<o2.y<<") is "<<dis<<endl;
}
int main(){
point A=point(1,2);
point B=point(1,3);
A.displaypoint();
B.displaypoint();
disCoord(A,B);
return 0;
}
The problem is that you are using incorrect formula which result in taking square root of negative number. In particular, in your case
dis = sqrt((1-1)2 - (3-2)2)
= sqrt(0 - 1) = sqrt(-1)
And i quote from nan documentation
The NaN values are used to identify undefined or non-representable values for floating-point elements, such as the square root of negative numbers or the result of 0/0.
To solve this, replace double dis=sqrt(pow(o2.x-o1.x,2)-pow(o2.y-o1.y,2)); with:
double dis=sqrt(pow(o2.x-o1.x,2) + pow(o2.y-o1.y,2));
Note there is a + in between while you were using - for some reason.
This is because the actual(correct) formula for calculating distance is:
d(P,Q) = sqrt((x2-x1)2 + (y2-y1)2)
As others said, the formula you're using is incorrect. BUT, the reason you're getting a NaN or 0 as a result is slightly more complicated.
Your test points (1,2) and (1,3) share the same X component. So, your formula:
double dis=sqrt(pow(o2.x-o1.x,2)-pow(o2.y-o1.y,2));
Resolves to:
dis = sqrt(pow(1-1,2) - pow(3-2,2))
or
dis = sqrt(0 - 1)
Which we all affectionately know as i, the square root of -1. That's one of the few cases that will (correctly) yield a result of NaN. (NAN means "Not A Number," in case that wasn't clear.)
The correct distance formula:
sqrt(pow(o2.x-o1.x,2) + pow(o2.y-o1.y,2))
Doesn't allow for a negative argument to sqrt, so this never happens.
It's tough to find these issues if you're not sure what you're looking for. It'd be easier to debug if you didn't do everything on one line:
double a2 = pow(o2.x-o1.x,2);
double b2 = pow(o2.y-o1.y,2);
double c2 = a2 + b2;
double c = sqrt(c2);
That's overly verbose, but the general idea is to split complex statements up into components. It's easier to read, easier to debug, and, if you'd done this, you'd have seen that c2 was negative.
White space is cheap, carriage returns cost nothing. Don't scrimp on keystrokes in order to save time.

Recursion for evaluating log(1+x) using taylor series of the same

#include<iostream>
using namespace std;
double log(double x,int n)
{
static double p = x ;
double s;
if(n==1)
return x;
else
{
s=log(x,n-1);
p*=x;
if(n%2==0)
return s - (p/n);
else
return s + (p/n);
}
}
int main()
{
double r = log(1,15);
cout << r;
return 0;
}
I tried writing the above function for evaluating the log(1+x) function using its taylor series with recursion. But it didn't gave the result as I expected.
Eg :
ln(2) = 0.693 whereas my code gave 0.725. In the above code, n represents the number of terms.
Also I am new to this platform, so can I say that the above question is complete or does it need some additional information for further explanation?
There is nothing wrong with that piece of code: this has obviously got to do with the rate of convergence of the Taylor series.
If you take n = 200 instead of n = 15 in your code, the approximation error will be low enough that the first two decimals of the exact solution ln(2) = 0.693147... will be the correct ones.
The more you increase the n parameter, the better approximation you will get of ln(2).
Your program does converge to the right number, just very slowly...
log(1,15) returns 0.725, as you noticed, log(1,50) is 0.683, log(1,100) is 0.688, and log(1,200) is 0.691. That's getting close to the number you expected, but still a long way to go...
So there is no C++ or recursion bug in your code - you just need to find a better Taylor series to calculate log(X). Don't look for a Taylor series for log(1+x) - these will typically assume x is small, and converge quickly for small x, not for x=1.

Prevent a user from entering a value which would cause integer to overflow

I'm very new to C++ programming, and have written a simple program to calculate the factorial of an integer provided by the user. I am attempting to account for inputs which would cause an error, or do not make sense (e.g. I have accounted for input of a negative number/-1 already). I want to print out an error if the user enters a number whose factorial would be larger than the maximum integer size.
I started with:
if(factorial(n) > INT_MAX)
std::cout << "nope";
continue
I tested this with n = ~25 or 26 but it doesn't prevent the result from overflowing and printing out a large negative number instead.
Second, I tried assigning this to a variable using a function from the 'limits.h' header and then comparing the result of factorial(n) against this. Still no luck (you can see this solution in the code sample below).
I could of course assign the result to a long and test against that but you wouldn't have to go very far until you started to wrap around that value, either. I'd prefer to find a way to simply prevent the value from being printed if this happens.
#include <iostream>
#include <cstdlib>
#include <limits>
int factorial(int n)
{
auto total = 1;
for(auto i = 1; i <= n; i++)
{
total = total * i; //Product of all numbers up to n
}
return total;
}
int main()
{
auto input_toggle = true;
auto n = 0;
auto int_max_size = std::numeric_limits<int>::max();
while(input_toggle = true)
{
/* get user input, check it is an integer */
if (factorial(n) > int_max_size)
{
std::cout << "Error - Sorry, factorial of " << n << " is larger than \nthe maximum integer size supported by this system. " << std::endl;
continue;
}
/* else std::cout << factorial(n) << std::endl; */`
As with my other condition(s), I expect it to simply print out that small error message and then continue asking the user for input to calculate. The code does work, it just continues to print values that have wrapped around if I request the factorial of a value >25 or so. I feel this kind of error-checking will be quite useful.
Thanks!
You are trying to do things backwards.
First, no integer can actually be bigger than INT_MAX, by definition - this is a maximum value integer can be! So your condition factorial(n) > int_max_size is always going to be false.
Moreover, there is a logical flaw in your approach. You calculate the value first and than check if it is less than maximum value allowed. By that time it is too late! You have already calculated the value and went through any overflows you might have encountered. Any check you might be performing should be performed while you are still doing your calculations.
In essence, you need to check if multiplying X by Z will be within allowed range without actually doing the multiplication (unfortunately, C++ is very strict in leaving signed integer overflow undefined behavior, so you can't try and see.).
So how do you check if X * Y will be lesser than Z? One approach would be to divide Z by Y before engaging in calculation. If you end up with the number which is lesser than X, you know that multiplying X by Y will result in overflow.
I believe, you know have enough information to code the solution yourself.

Calculating the value of arctan(x) in C++

I have to calculate the value of arctan(x) . I have calculated the value of this by evaluating the following series :
Arctan (x) = x – x^3/3 + x^5/5 – x^7/7 + x^9/9 - …
But the following code can not calculate the actual value. For example, calculate_angle(1) returns 38.34 . Why?
const double DEGREES_PER_RADIAN = 57.296;
double calculate_angle(double x)
{
int power=5,count=3;
double term,result,prev_res;
prev_res = x;
result= x-pow(x,3)/3;
while(abs(result-prev_res)<1e-10)
{
term = pow(x,power)/power;
if(count%2==0)
term = term*(-1);
prev_res=result;
result=result+term;
++count;
power+=2;
// if(count=99)
// break;
}
return result*DEGREES_PER_RADIAN;
}
EDIT: I found the culprit. You forgot to include stdlib.h, where the function abs resides. You must have ignored the warning about abs being implicitly declared. I checked that removing the include yields the result 38.19 and including it yields the result ~45.
The compiler is not required to stop compilation when an undeclared function is being used (in this case abs). Instead, it is allowed to make assumptions on how the function is declared (in this case, wrong one.)
Besides, like other posters already stated, your use of abs is inappropriate as it returns an int, not a double or float. The condition in the while should be >1e-100 not <1e-100. The 1e-100 is also too small.
--
You forgot to increase count and power after calculating the first two summands:
prev_res = x;
result= x-pow(x,3)/3;
count = 4; <<<<<<
power = 5; <<<<<<
while(abs(result-prev_res)<1e-100)
{
term = pow(x,power)/power;
if(count%2==1)
term = term*(-1);
Also I consider your use of the count variable counterintuitive: it is intialized with 3 like if it denotes the last used power; but then, loop iterations increase it by 1 instead of 2 and you decide the sign by count%2 == 1 as opposed to power%4 == 3
The series converges to tan^{-1} x, but not very fast. Consider the series when x=1:
1 - 1/3 + 1/5 - 1/7 + 1/9 - ...
What is the error when truncating at the 1/9 term? It's around 1/9. To get 10^{-100} accuracy, you would need to have 10^{100} terms. The universe would end before you'd get that. And, catastrophic round-off error and truncation error would make the answer utterly unreliable. You only have 14 digits to play with for doubles.
Look at reference works like Abramowitz and Stegun [AMS 55] or the new NIST Digital Library of Mathematical Functions at http://dlmf.nist.gov to see how these are done in practice. Often, one uses Padé approximants instead of Taylor series. Even when you stick with Taylor series, you often use Chebyshev approximation to cut down on the total error.
I also recommend Numerical Methods that [Usually] Work, by Forman Acton. Or the Numerical Recipes in ... series.
Your sign is the wrong way around after the first two terms. It should be:
if(count%2==0)
term = term*(-1);
Your comparison is the wrong way around in the while condition. Also, you're expecting an unrealistically high level of precision. I would suggest something more like this:
while(fabs(result-prev_res)>1e-8)
Finally, you'll get a more accurate result with a better value for DEGREES_PER_RADIAN. Why not something like this:
const double DEGREES_PER_RADIAN = 180/M_PI;

Is this the correct way to test to see if two lines are colinear?

My code in the colinear does not seem to work and its frustrating the hell out of me. Am i going the best way to use my line class by using two points in my point class? My test for colinearlirty is crashing so I am stuck in a rut for the past few days.
bool line::isColinear(line)
{
bool line2=false;
line l1,l2;
if (l1.slope()==l2.slope())
{
if (l1.y_int()==l2.y_int())
{
line2 =true;
return line2;
}
}
else
{
line2 =false;
}
}
//Heres a copy of my line class
class line
{
private:
point p1,p2;
public:
bool isColinear(line);
bool isParallel(line);
point solve(line);
double slope();
double y_int();
void Display(ostream&);
};
You are storing line as between two points. Slope of a line is usually defined as
slope = (y2 - y1) / ( x2 - x1 )
if x1 is equal to x2, you can have a division by zero error/exception.
Other things to be careful about
If you are storing point coordinates as integers, you could be doing just a integer division and not get what you expect
If you are using doubles throughout, please use a tolerance when comparing them
There's not nearly enough here to really judge what's going wrong, so a few generalities:
Never compare floating-point values directly for equality. It won't work a surprising amount of the time. Instead, compare their difference with an amount so small that you're content to call it "zero" (normally we call it "epsilon"):
if (abs((num1 - num2)) < 0.001) {
/* pretend they're equal */
} else {
/* not equal */
}
line2 is unnecessary in this example. You might as well return true or false directly from the conclusions. Often even the return true or return false is needlessly confusing. Lets assume you re-write this method a little to three methods. (Which might or might not be an improvement. Just assume it for a bit.)
bool line::compare_slope(line l2) {
return fabs((l2.slope() - self.slope()) < 0.001; // don't hardcode this
}
bool line::compare_origin(line l2) {
return fabs((l2.y_int() - self.y_int()) < 0.001; // nor this
}
bool line::is_colinear(line l2) {
return compare_slope(l2) && compare_origin(l2);
}
No true or false hard coded anywhere -- instead, you rely on the value of the conditionals to compute true or false. (And incidentally, the repetition in those functions goes to show that a function floating_comparison(double f1, double f2, double epsilon), could make it far easier to modify epsilon either project-wide or compute an epsilon based on the absolute values of the floating point numbers in question.)
My guess is that since l1 and l2 are uninitialized, their slope methods are doing a divide by zero. Initialize those properly or switch to the proper variables and you'll fix your crash.
Even once you get that working, the test is likely to fail. You can't compare floating point numbers and expect them to be equal, even if it seems they ought to be equal. You should read What Every Computer Scientist Should Know About Floating-Point Arithmetic.
A simple formula for a line (in 2D) (derived from here) is:
P1(x1,y1) and P2(x2,y2) are the points determining the line.
(y-y1) (x2-x1) + (y1-y2) (x-x1) = 0 ( let's use f(x,y) = 0 )
To test if two lines match imagine that a second line is defined by points P3(x3,y3), P4(x4,y4).
To make sure that those lines are 'quite' the same you should test if the two points (P3, P4) determining the second line are close 'enough' to the previous line.
This is easily done by computing f(x3,y3) and f(x4,y4). If those values are close to 0 then the lines are the same.
Pseudocode:
// I would chose tolerance around 1
if ( f(x3,y3) < tolerance && f(x4,y4) < tolerance )
{
// line P1,P2 is the same as P3,P4
}