Improve numerical accuracy of LineLine intersection method (3D) - c++

I coded the following LineLine intersection method:
double LineLineIntersection(
const Eigen::Vector3d& origin1,
const Eigen::Vector3d& ray1,
const Eigen::Vector3d& origin2,
const Eigen::Vector3d& ray2)
{
if(abs((origin1 - origin2).norm() - 1.0) < 0.000001) return 0;
auto n1 = (origin2 - origin1).cross(ray2);
auto n2 = ray1.cross(ray2);
// Use this to test whether the vectors point in the same or opposite directions
auto n = n2.normalized();
// If n2 is the 0 vector or if the cross products are not colinear, no solution exists
if(n2.norm() < 0.00001 || abs(abs(n1.dot(n)) - n1.norm()) > 0.000001)
return std::numeric_limits<double>::infinity();;
return n1.dot(n) / n2.dot(n);
}
The theory for how this works is explained here. However the page has a mistake, taking just the absolute value has only the magnitude, it erases the direction. So instead, the dot product with the cross direction must be taken. That way the distance can be either positive or negative depending on whether the vectors point in the same direction or not.
This technically works but I am running into big numerical errors. For example in one of my tests I am getting:
The difference between i1.x() and Eigen::Vector3d(-0.581, 1.232, 0).x() is 0.0024061184231309873, which exceeds 0.001, where
i1.x() evaluates to -0.58340611842313095,
Eigen::Vector3d(-0.581, 1.232, 0).x() evaluates to -0.58099999999999996, and
0.001 evaluates to 0.001.
An error bigger than 0.001 is huge. What can I do to make the method more accurate?
This is the value of i1: -0.583406 1.23237 0 sorry to not have included it before.

You're using the type "double", try to change it to "long double" or "__float128" if it exists in your version of G++. Also, you can use "BigDecimal" in Java for better accuracy or maybe some long arithmetics from Python.

Related

Incorrect variable range behavior in RooFit

The RooFit package allows me to import some TTree branches, but it constrains values included in those branches between the min and max value set by a RooRealVar. For instance:
RooRealVar t1("t1", "Some variable", 0.0, 1.0);
RooDataSet data("data", "My Dataset", RooArgSet(t1), Import(*myttree));
so long as the TTree myttree contains a branch called t1. This is all fine and good, until you start getting close to floating point values in the range. My particular problem occurs because I have a variable like t1 which maps to some variable with an exponential distribution. I'm trying to fit this distribution, but the fits fail for values of t1 ~ 0.0. My solution was to just change the range a bit to cut off potential events where the stored value of t1 in the tree is actually zero or close to it (all the following code is run in the ROOT interpreter, but I have confirmed it works in compiled code as well):
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
However, note the following annoying behavior:
root[1] t1 = 0.000998;
root[2] t1.getVal();
(double) 0.0010000000
// this is correct, as 0.000998 < 0.001 so RooFit set it as the lower limit
root[3] t1 = 0.000999;
root[4] t1.getVal();
(double) 0.00099900000
// this is incorrect.
Yes, the extra zero is printed in the second case, which I also don't understand, but I'm mostly concerned with the failure to recognize that 0.000999 < 0.001. When I compare these values later in an if-statement, I find that C++ can tell the difference. Everything appears to be double precision here, and I've been tracing through the code to see where the precision error seems to crop up. Correct me if I'm wrong, but a float should still hold these numbers up to comparison precision, right? What's going on here? If this is some floating point error problem, what's the best way to resolve it? I have several events with values like t1 = 0.000999874, and changing the bounds to something like 0.0001 doesn't really help either, there are still events which live on this edge.
Edit: I want to emphasize that while this is probably a floating point problem, it really shouldn't be. For instance, the following code works:
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
root[1] t1 = 0.000999;
root[2] t1.getVal() < 0.001;
(bool) true
Well everyone, I found the answer (and I hate it). It actually has very little to do with floating point arithmetic, and I'm honestly not sure why the code was written this way. From the source code that determines if a value is "in range":
bool RooAbsRealLValue::inRange(double value, const char* rangeName, double* clippedValPtr) const
{
// double range = getMax() - getMin() ; // ok for +/-INIFINITY
double clippedValue(value);
bool isInRange(true) ;
const RooAbsBinning& binning = getBinning(rangeName) ;
double min = binning.lowBound() ;
double max = binning.highBound() ;
// test this value against our upper fit limit
if(!RooNumber::isInfinite(max) && value > (max+1e-6)) {
clippedValue = max;
isInRange = false ;
}
// test this value against our lower fit limit
if(!RooNumber::isInfinite(min) && value < min-1e-6) {
clippedValue = min ;
isInRange = false ;
}
if (clippedValPtr) *clippedValPtr=clippedValue ;
return isInRange ;
}
As we can see here, RooFit doesn't actually check if min < val < max or even min <= val <= max but rather min - 1e-6 < value < max + 1e-6! I couldn't find a single place where this was documented explicitly, but I'm even more concerned that there is a separate implementation of inRange which takes a variable name (or comma separated list of variable names) and returns a result which is incompatible with the prior implementation:
bool RooAbsRealLValue::inRange(const char* name) const
{
const double val = getVal() ;
const double epsilon = 1e-8 * fabs(val) ;
if (!name || name[0] == '\0') {
const auto minMax = getRange(nullptr);
return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
}
const auto& ranges = ROOT::Split(name, ",");
return std::any_of(ranges.begin(), ranges.end(), [val,epsilon,this](const std::string& range){
const auto minMax = this->getRange(range.c_str());
return minMax.first - epsilon <= val && val <= minMax.second + epsilon;
});
}
Here, we can see the creation of an epsilon = 1e-8 * fabs(val) rather than the arbitrary 1e-6 given in the first definition. This comparison uses a <= rather than a < also. It should be noted that the method used to filter trees when imported in this way uses the first implementation (source here).
Somewhere along the way (I'm not entirely sure where actually), some of these arbitrary comparisons lead to the following paradoxical behavior:
root[0] RooRealVar t1("t1", "Some variable", 0.001, 1.0);
root[1] t1 = 0.001 - 1e-6;
(RooAbsArg &) RooRealVar::t1 = 0.000999 L(0.001 - 1)
root[2] t1 = 0.001 - 1e-8 * 0.001;
(RooAbsArg &) RooRealVar::t1 = 0.001 L(0.001 - 1)
root[3] t1 = 0.00099999999;
(RooAbsArg &) RooRealVar::t1 = 0.001 L(0.001 - 1)
I would classify this as a bug. Under no circumstances should 0.00099900000 be classified as within the range of (0.001 - 1) where 0.00099999999 is not!

Conditional statements with SSE

I'm trying to do some calculations for my game, and I'm trying to calculate the distance between two points. Essentially, I'm using the equation of a circle to see if the points are inside of the radius that I define.
(x - x1)^2 + (y - y1)^2 <= r^2
My question is: how do I evaluate the conditional statement with SSE and interpret the results? So far I have this:
float distSqr4 = (pow(x4 - k->getPosition().x, 2) + pow(y4 - k->getPosition().y, 2));
float distSqr3 = (pow(x3 - k->getPosition().x, 2) + pow(y3 - k->getPosition().y, 2));
float distSqr2 = (pow(x2 - k->getPosition().x, 2) + pow(y2 - k->getPosition().y, 2));
float distSqr1 = (pow(x1 - k->getPosition().x, 2) + pow(y1 - k->getPosition().y, 2));
__m128 distances = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);
Once I get the result variable, I get lost. How do I use the result variable that I just got? My plan was, if the condition evaluated turned out to be true, to do some lighting calculations and then draw the pixel on the screen. How do I interpret true vs false in this case?
Any help towards the right direction is greatly appreciated!
My plan was, if the condition evaluated turned out to be true, to do some lighting calculations and then draw the pixel on the screen.
Then you really have little choice but to branch.
The big advantage of doing conditional tests using SSE is that it allows you to write branchless code, which can lead to massive speed improvements. But in your case, you pretty much have to branch because, if I'm understanding you correctly, you never want to output anything on the screen if the condition evaluated to false.
I mean, I guess you could do all of the calculations unconditionally (speculatively) and then just use the result of the conditional to twiddle bits in the pixel values, essentially causing you to draw off of the screen. That would give you branchless code, but it's pretty silly. There is a penalty for branch mispredictions, but it won't be anywhere near as expensive as all of the calculations and drawing code.
In other words, the parallelism you're using SIMD to exploit is exhausted once you have the final result. It's just a simple, scalar compare-and-branch. First you test whether the condition evaluated to true. If not, you'll jump over the code that does the lighting calculations and pixel-drawing. Otherwise, you'll just fall through to execute that code.
The tricky part is that the compiler won't let you use an __m128 variable in a regular old if statement, so you need to "convert" result to an integer that you can use as the basis for a conditional. The easiest way to do that would be the _mm_movemask_epi8 intrinsic.
So you would basically just do:
__m128 distances = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);
if (_mm_movemask_epi8(result) == (unsigned)-1)
{
// All distances were less-than-or-equal-to the maximum, so
// go ahead and calculate the lighting and draw the pixels.
CalcLightingAndDraw(…);
}
This works because _mm_cmple_ps sets each packed double-word to all 1s if the comparison is true, or all 0s if the comparison is false. _mm_movemask_epi8 then collapses that into an integer-sized mask and moves it to an integer value. You then can use that integer value in a normal conditional statement.
Note: With Clang and ICC, you can get away with passing a __m128 value to the _mm_movemask_epi8 intrinsic. On GCC, it insists upon a __m128i value. You can handle this with a cast: _mm_movemask_epi8((__m128i)result).
Of course, I'm assuming here that you are only going to do the drawing if all of the distances are less-than-or-equal-to the maximum distance. If you want to treat each of the four distances independently, then you need to add more conditional tests on the mask:
__m128 distances = _mm_set_ps(distSqr1, distSqr2, distSqr3, distSqr4);
__m128 maxDistSqr = _mm_set1_ps(k->getMaxDistance() * k->getMaxDistance());
__m128 result = _mm_cmple_ps(distances, maxDistSqr);
unsigned condition = _mm_movemask_epi8(result);
if (condition != 0)
{
// One or more of the distances were less-than-or-equal-to the maximum,
// so we have something to draw.
if ((condition & 0x000F) != 0)
{
// distSqr1 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr1);
}
if ((condition & 0x00F0) != 0)
{
// distSqr2 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr2);
}
if ((condition & 0x0F00) != 0)
{
// distSqr3 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr3);
}
if ((condition & 0xF000) != 0)
{
// distSqr4 was less-than-or-equal-to the maximum
CalcLightingAndDraw(distSqr4);
}
}
This won't result in very efficient code, since you have to do so many conditional test-and-branch operations. You might be able to continue parallelizing some of the lighting calculations inside of the main if block. I can't say for sure if this is workable, since I don't have enough details about your algorithm/design.
Otherwise, if you can't see any way to wring more parallelism out of the drawing code, the use of explicit SSE intrinsics isn't buying you much here. You were able to parallelize one comparison (_mm_cmple_ps), but the overhead of setting up for that comparison (_mm_set_ps, which will probably compile into vinsertps or unpcklps+movlhps instructions, assuming the inputs are already in XMM registers) will more than cancel out any trivial gains you might get. You'd arguably be just as well off writing the code like so:
float maxDistSqr = k->getMaxDistance() * k->getMaxDistance();
if (distSqr1 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr1);
}
if (distSqr2 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr2);
}
if (distSqr3 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr3);
}
if (distSqr4 <= maxDistSqr)
{
CalcLightingAndDraw(distSqr4);
}

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;

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

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/

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
}