How to fix Runtime error in my C++ script - c++

My code tries to check if there is a solution to unknown value n in this equation:
x1 + nv1 = x2 + nv2
with given inputs x1, v1, x2, v2 with input for x1 v1 x2 v2. So that I can tell "YES" if there is a value that meets in the same value for both sides of the equation.
n is addressed as output in my code.
For curious here is the problem link
string kangaroo(int x1, int v1, int x2, int v2) {
string output;
int x3;
int v3;
x3 = x1-x2;
v3 = v2-v1;
int div = x3/v3;
int remain = x3%v3;
if(div > 0 && remain == 0){
output = "YES";
}else{
output = "NO";
}
return output;
}
My code works but it raises runtime error where x1 v1 x2 v2 are 43 2 70 2 which is too big for my solution. I am asking what possible improvements can be implemented for my case?
here is my resolution to this problem
if(x1<x2 && v1<v2){
return "NO";
}else{
if(v1!=v2 && ((x2-x1)%(v1-v2)==0)){
return "YES";
}else{
return "NO";
}
}
As a result:
1. check if x1,x2 and v1,v2 values are creating any unwanted result
(x1-x2 and v1-v2 are negative then this is unwanted)
2. check for divider not be zero (if v1 != v2, no divide by zero
situation)
Regards.

You are receiving runtime_error which indicates this error can only be detected during runtime.
int div = x3/v3;
Here you have to make sure v3 is not zero.

You should study math, linear algebra, in more detail. For v1 = v2, any value of these variables will result in a runtime error because you will be dividing by zero.
The system of equations is unsolvable for v1 = v2 case.

Related

Using three points (x, y), How to find whether it is triangle or not

I have an assignment in codeforces which says:
Like all problem solvers, Ebram loves eating crepe! As we all know, crepe usually served in a triangular shape. Now Ebram 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 Ebram! Given the coordinates Ebram 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 Ebram used. Each point on a separate line.
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 "Poor boy"
Examples
input
1 1
3 1
3 9
output
68
input
-10 8
9 100
3 8
output
8825
input
7 3
3 3
19 3
output
Poor boy
Here is my code that I used:
#include <iostream>
#include <cmath>
using namespace std;
int main () {
double x1,y1,x2,y2,x3,y3;
double area;
double s1,s2,s3;
double slope1, slope2;
cin >> x1 >> y1;
cin >> x2 >> y2;
cin >> x3 >> y3;
slope1 =((y2-y1)/(x2-x1));
slope2 =((y3-y2)/(x3-x2));
area = 0.5*abs(((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)));
if (slope1!=slope2 && (area)!=0){
s1 = sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
s2 = sqrt(((x2-x3)*(x2-x3))+((y2-y3)*(y2-y3)));
s3 = sqrt(((x1-x3)*(x1-x3))+((y1-y3)*(y1-y3)));
if (s1 > s2 && s1 > s3)
cout<<s1*s1<<endl;
if (s2 > s1 && s2 > s3)
cout<<s2*s2<<endl;
if (s3 > s1 && s3 > s2)
cout <<s3*s3<<endl;
}
else
cout <<"Poor boy";
return 0;
}
First I find the slope1 and slope2 to check if the three points aren't at the same line. So If they're not equal it forms a triangle (crepe).
Using this:
slope1 =((y2-y1)/(x2-x1));
slope2 =((y3-y2)/(x3-x2));
Then I wrote a relation to find the area of triangle using this formula:
area = 0.5*abs(((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1)));
Finally I put the if statements to find if it is a triangle or not and find the length of each side of the triangle then find the maximum length and print the square of it.
if (slope1!=slope2 && (area)!=0){
s1 = sqrt(((x1-x2)*(x1-x2))+((y1-y2)*(y1-y2)));
s2 = sqrt(((x2-x3)*(x2-x3))+((y2-y3)*(y2-y3)));
s3 = sqrt(((x1-x3)*(x1-x3))+((y1-y3)*(y1-y3)));
if (s1 > s2 && s1 > s3)
cout<<s1*s1<<endl;
if (s2 > s1 && s2 > s3)
cout<<s2*s2<<endl;
if (s3 > s1 && s3 > s2)
cout <<s3*s3<<endl;
}
else
cout <<"Poor boy";
return 0;
}
I tested the code in my compiler and it runs the i/o shown in the example perfectly fine. I submitted the code on codeforces but I stuck wrong answer at test 8 I don't know why?, and my code runs inputs and outputs fine. I will be very pleased if you help guys.
As in Sani's answer, I recommend calculating the rise and run between each pair of points:
rise1 = y2 - y1
rise2 = y3 - y2
rise3 = y1 - y3
run1 = x2 - x1
run2 = x3 - x2
run3 = x1 - x3
Also the same, I recommend checking whether any two points are coincident. Note that this is equivalent to what Sani's code is checking:
if (rise1 = run1 = 0) or (rise2 = run2 = 0) or (rise3 = run3 = 0) then
print "Poor Boy"
return 0
Now, similar to Sani, we move on to checking whether the points are on a line. However, we can simplify the conditions to check somewhat. Note that, if no two points are on a vertical line, then the three points are on one line if the slopes between any two points are equal. That is, m1 = m2, m2 = m3, or m3 = m1, equivalently. We can check whether m1 = m2. This is true when rise1/run1 = rise2/run2, which is safe since we assume no points are on a vertical line. We can rearrange this to rise1 * run2 = rise2 * run1, again safely. If no two points are on a vertical line, this is the only check we need.
What if two points are on a vertical line? Then at least one of run1 and run2 will be zero. However, because we have already guaranteed no two points are coincident, we can be absolutely sure that if either of these is zero, the corresponding rise is non-zero. There are two other cases (besides no two points being on a vertical line):
Exactly two points are on a vertical line. Then either run1 or run2, but not both, are zero. Without loss of generality, assume run1 is zero. Then the condition rise1 * run2 = rise2 * run1 simplifies to rise1 * run2 = 0. Because we know rise1 is not zero, this is satisfied only if run2 = 0, which contradicts our assumed case. This means that, in this case, the condition we derived earlier will produce the correct result and identify the points as not being on the same line.
Three points are on a vertical line. Then both run1 and run2 are zero. Then the condition rise1 * run2 = rise2 * run1 simplifies to 0 = 0, which is always true. In this case, the condition will produce the correct result and identify three points as being on the same line.
Because the condition we derived for the case of no two points on a vertical line happens to produce the correct result for all other possible cases, we can use it in all cases (under the assumption no two points are coincident). Therefore, we don't need to check anything except rise1 * run2 = rise2 * run1:
if rise1 * run2 = rise2 * run1 then
print "Poor Boy"
return 0
Now we know we have a triangle and need to return the largest of the three sides. We need the sum of squared differences of respective coordinates. Luckily, we already have the coordinate differences, so:
d1 = (rise1 * rise1) + (run1 * run1)
d2 = (rise2 * rise2) + (run2 * run2)
d3 = (rise3 * rise3) + (run3 * run3)
return max(d1, d2, d3)
Your biggest problem is that you keep getting division by 0 on inputs where the denominator is 0 when calculating the slope. I.e. Points (3, 4), (3, 5) and (5, 6) will yield -1/0.
Another thing is that you are "over-complicating" things.
This is a step by step example for clarity how to approach this (I.e. not optimal code):
// Check if any two points are the same. I.e. no triangle
if (x1 == x2 && y1 == y2 || x1 == x3 && y1 == y3 || x2 == x3 && y2 == y3) {
cout << "Poor boy";
return 0;
}
// Check if all points are on the same horizontal or vertical line
if (x1 == x2 && x1 == x3 || y1 == y2 && y1 == y3) {
cout << "Poor boy";
return 0;
}
// Calculate the nominators and denominators
nominator1 = y2-y1;
denominator1 = x2-x1;
nominator2 = y3-y2;
denominator2 = x3-x2;
nominator3 = y1-y3;
denominator3 = x1-x3;
// Calculate the slopes, if possible.
if (denominator1 == 0) slope1 = 0;
else slope1 = nominator1 / denominator1;
if (denominator2 == 0) slope2 = 0;
else slope2 = nominator2 / denominator2;
if (denominator3 == 0) slope3 = 0;
else slope3 = nominator3 / denominator3;
// Check if the three points form a triangle or a straight line.
// I.e. if all slopes are the same, it is a line.
if ((slope1 == slope2 && slope1 == slope3)) {
cout << "Poor boy";
return 0;
}
// Calculate the square of the length of each side
// (No abs is needed since a square of negative numbers is positive.)
// (Also no sqrt is needed since we're only interrested in the square of the longest side.)
side1 = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
side2 = (x3-x2)*(x3-x2) + (y3-y2)*(y3-y2);
side3 = (x1-x3)*(x1-x3) + (y1-y3)*(y1-y3);
// Note: This can be used instead which is the same calculation:
// side1 = denominator1 * denominator1 + nominator1 * nominator1;
// side2 = denominator2 * denominator2 + nominator2 * nominator2;
// side3 = denominator3 * denominator3 + nominator3 * nominator3;
// Get the longest side squared.
maxSide = side1 > side2 ? side1 > side3 ? side1 : side2 > side3 ? side2 : side3;
cout << maxSide;
Disclaimer: Code not tested!

nFinding Xcrossing point using Data Points

I was going through Algorithm which identify crossing point using data points on x axis. I can understand calculation but could not understand purpose of this calculation. As per my understanding, it determine each time new y point and slope and subtract them.
I want to insert Image also but I do not have 10 reputation point.
Please let me know if I need to provide info.
//This function determine the crossing point when the graph is intersecting x axis.
XPoint findXingPoint(Curve & curve, double rfix, double vcc, int type, int pull_up)
{
//curve class contain x and y data point
// rfix is fixed value which is generally 50
// vcc also fix value
// type contain 0 and 1
//pull up to identify graph
XPoint p = { 0.0, 0.0 };
double r_fix = rfix;
double m = -1 / r_fix;
double c = vcc / r_fix;
if(type)
c=0;
double r, s, X1, X2, Y1, Y2, Y3, Y4;
r = (m * curve[0].first) + c;
// r is a kind of y value which determine from x and y point
s = abs(r);
for (Curve::iterator i = curve.begin(); i != curve.end(); i++) {
curve_point p = (*i);
double xcurve = p.first;
double ycurve = p.second;
double yloadline = m * xcurve + c;
double B = ycurve - yloadline;
if (B >= 0 && r >= B) {
r = B;
X1 = xcurve;
Y1 = yloadline;
Y2 = ycurve;
}
if (B <= 0 && r >= abs(B)) {
s = abs(B);
X2 = xcurve;
Y4 = yloadline;
Y3 = ycurve;
}
}
#could not understand purpose of B calculation
if (s == 0)
X1 = X2;
if (r == 0)
X2 = X1;
if (X1 != X2) {
double m1, m2, c1, c2;
m1 = (Y3 - Y2) / (X2 - X1);
m2 = (Y4 - Y1) / (X2 - X1);
c1 = Y3 - (m1 * X2);
c2 = Y4 - (m2 * X2);
// CASE m1==m2 should be handled.
p.x = (c2 - c1) / (m1 - m2);
p.y = (m2 * p.x) + c2;
} else {
p.x = X1;
p.y = Y1;
}
#not able to also understand calculation
if (verbosityValue >= 1)
loginfo<<"found crossing point # " << p.x << " " << p.y << endl;
return p;
}
Output:
first
found crossing point # 7.84541e-08 -1.96135e-09 with type 0
found crossing point # 0.528564 0.0182859 with type 1
second
found crossing point # 0.654357 -0.0163589 with type 0
found crossing point # 1.25827 4.31937e-05 with type 1
This appears to be a straightforward implementation. For a given point x,y on the curve, find the slope, draw a line through the slope, find where that line would cross the x axis, and then find the new y value at that point. For well-behaved functions, the new y value is a lot closer to 0 than the initial y value. You iterate until the approximation is good enough.
If you look at the graph, you see that the middle part is quite straight. Hence, the slope of the line is a locally good approximation of the curve, and your new y value is a lot closer to zero (At least 10x times, probably 100x, looking at the graph.0. If you start on the the steeper slopes on either side, you'll need one extra step. Your second x point will be on the middle part.

Calculate intersection of two lines using integers only

I can quite easily calculate the point of intersection given two lines. If I start with two vertices:
(x1,y1)
(x2,y2)
I can calculate the slope by doing (y1-y2)/(x1-x2), and then calculating the intercept
y1 - slope * x1
Then do that again, so I have to sets of slope and intercept, then just do:
x = (intercept2 - intercept1) / (slope1 - slope2)
y = slope1 * x + intercept1
(disclaimer: this might not even work, but i've gotten something very close to it to work, and it illustrates my general technique)
BUT that only works with data types with decimals, or non integral. Say the vertices are:
(0,1)
(10,2)
To calculate the slope would result in (1-2)/(0-10), which is -1/-10 which is not 1/10, it is 0.
How can I get code that yields a valid result using only integers?
Edit: I can't use floats AT ALL!. No casting, no nothing. Also, values are capped at 65535. And everything is unsigned.
In high school when subtracting fractions, our teachers taught us to find a common denominator
So 1/4 - 1/6 = 3/12 - 2/12 = 1/12
So do the same with your slopes.
int slope1 = n1 / d1; // numerator / denominator
int slope2 = n2 / d2;
// All divisions below should have 0 for remainder
int g = gcd( d1, d2 ); // gcd( 4, 6 ) = 2
int d = d1 * d2 / g; // common denominator (12 above)
int n = (d/d1) * n1 - (d/d2) * n2; // (1 in 1/12 above)
// n1/d1 - n2/d2 == n/d
I hope I got that right.
Hm..
(0,1)
(10,2)
and (y1-y2)/(x1-x2). Well, this is the description of one line, not the intersection of two lines.
As far as I remember lines are described in the form of x * v with x an skalar and v be a vector. Then it's
x * (0,1) = v2 and
x * (10, 2) = v2.
therefore the lines only intersect if exactly one solution to both equitions exist, overlap when there are infinitive numbers of solutions and don't intersect when they are parallel.
http://www.gamedev.net/topic/647810-intersection-point-of-two-vectors/
explains the calcuclation based on the dot - product.
Input: line L passing thru (x1, y1) and (x2, y2), and line M passing thru (X1, Y1) and (X2, Y2)
Output: (x, y) of the intersecting point of two lines L and M
Tell Wolfram Alpha to solve y = (y1-y2)/(x1-x2)*(x-x1)+y1 and y = (Y1-Y2)/(X1-X2)*(x-X1)+Y1 for x, y to get this solution:
http://www.wolframalpha.com/share/clip?f=d41d8cd98f00b204e9800998ecf8427e3at5u9evl8
But I have no idea on how to write a program to implement the above solution for your calculator with only uint16_t ALU.
Thanks to Graham Toal's answer, below is a primitive Rust implementation of the linked C code in their answer, modified to return the point of intersection for the complete line, as opposed to the line segment. It doesn't use much Rust-specific magic so should be reasonably easy to port to other languages.
The function returns a Point where the Lines intersect, if at all, and a flag denoting whether the intersection point lies on both intersected lines (true) or not (false).
/// 2D integer point
struct Point {
/// The x coordinate.
pub x: i32,
/// The y coordinate.
pub y: i32,
}
/// Line primitive
struct Line {
/// Start point
pub start: Point,
/// End point
pub end: Point,
}
/// Check signs of two signed numbers
///
/// Fastest ASM output compared to other methods. See: https://godbolt.org/z/zVx9cD
fn same_signs(a: i32, b: i32) -> bool {
a ^ b >= 0
}
/// Integer-only line segment intersection
///
/// If the point lies on both line segments, the second tuple argument will return `true`.
///
/// Inspired from https://stackoverflow.com/a/61485959/383609, which links to
/// https://webdocs.cs.ualberta.ca/~graphics/books/GraphicsGems/gemsii/xlines.c
fn intersection(l1: &Line, l2: &Line) -> Option<(Point, bool)> {
let Point { x: x1, y: y1 } = l1.start;
let Point { x: x2, y: y2 } = l1.end;
let Point { x: x3, y: y3 } = l2.start;
let Point { x: x4, y: y4 } = l2.end;
// First line coefficients where "a1 x + b1 y + c1 = 0"
let a1 = y2 - y1;
let b1 = x1 - x2;
let c1 = x2 * y1 - x1 * y2;
// Second line coefficients
let a2 = y4 - y3;
let b2 = x3 - x4;
let c2 = x4 * y3 - x3 * y4;
let denom = a1 * b2 - a2 * b1;
// Lines are colinear
if denom == 0 {
return None;
}
// Compute sign values
let r3 = a1 * x3 + b1 * y3 + c1;
let r4 = a1 * x4 + b1 * y4 + c1;
// Sign values for second line
let r1 = a2 * x1 + b2 * y1 + c2;
let r2 = a2 * x2 + b2 * y2 + c2;
// Flag denoting whether intersection point is on passed line segments. If this is false,
// the intersection occurs somewhere along the two mathematical, infinite lines instead.
//
// Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1, the
// line segments do not intersect.
//
// Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line
// segment, the line segments do not intersect.
let is_on_segments = (r3 != 0 && r4 != 0 && same_signs(r3, r4))
|| (r1 != 0 && r2 != 0 && same_signs(r1, r2));
// If we got here, line segments intersect. Compute intersection point using method similar
// to that described here: http://paulbourke.net/geometry/pointlineplane/#i2l
// The denom/2 is to get rounding instead of truncating. It is added or subtracted to the
// numerator, depending upon the sign of the numerator.
let offset = if denom < 0 { -denom / 2 } else { denom / 2 };
let num = b1 * c2 - b2 * c1;
let x = if num < 0 { num - offset } else { num + offset } / denom;
let num = a2 * c1 - a1 * c2;
let y = if num < 0 { num - offset } else { num + offset } / denom;
Some((Point::new(x, y), is_on_segments))
}

Better way than if else if else... for linear interpolation

question is easy.
Lets say you have function
double interpolate (double x);
and you have a table that has map of known x-> y
for example
5 15
7 18
10 22
note: real tables are bigger ofc, this is just example.
so for 8 you would return 18+((8-7)/(10-7))*(22-18)=19.3333333
One cool way I found is
http://www.bnikolic.co.uk/blog/cpp-map-interp.html
(long story short it uses std::map, key= x, value = y for x->y data pairs).
If somebody asks what is the if else if else way in title
it is basically:
if ((x>=5) && (x<=7))
{
//interpolate
}
else
if((x>=7) && x<=10)
{
//interpolate
}
So is there a more clever way to do it or map way is the state of the art? :)
Btw I prefer soutions in C++ but obviously any language solution that has 1:1 mapping to C++ is nice.
Well, the easiest way I can think of would be using a binary search to find the point where your point lies. Try to avoid maps if you can, as they are very slow in practice.
This is a simple way:
const double INF = 1.e100;
vector<pair<double, double> > table;
double interpolate(double x) {
// Assumes that "table" is sorted by .first
// Check if x is out of bound
if (x > table.back().first) return INF;
if (x < table[0].first) return -INF;
vector<pair<double, double> >::iterator it, it2;
// INFINITY is defined in math.h in the glibc implementation
it = lower_bound(table.begin(), table.end(), make_pair(x, -INF));
// Corner case
if (it == table.begin()) return it->second;
it2 = it;
--it2;
return it2->second + (it->second - it2->second)*(x - it2->first)/(it->first - it2->first);
}
int main() {
table.push_back(make_pair(5., 15.));
table.push_back(make_pair(7., 18.));
table.push_back(make_pair(10., 22.));
// If you are not sure if table is sorted:
sort(table.begin(), table.end());
printf("%f\n", interpolate(8.));
printf("%f\n", interpolate(10.));
printf("%f\n", interpolate(10.1));
}
You can use a binary search tree to store the interpolation data. This is beneficial when you have a large set of N interpolation points, as interpolation can then be performed in O(log N) time. However, in your example, this does not seem to be the case, and the linear search suggested by RedX is more appropriate.
#include <stdio.h>
#include <assert.h>
#include <map>
static double interpolate (double x, const std::map<double, double> &table)
{
assert(table.size() > 0);
std::map<double, double>::const_iterator it = table.lower_bound(x);
if (it == table.end()) {
return table.rbegin()->second;
} else {
if (it == table.begin()) {
return it->second;
} else {
double x2 = it->first;
double y2 = it->second;
--it;
double x1 = it->first;
double y1 = it->second;
double p = (x - x1) / (x2 - x1);
return (1 - p) * y1 + p * y2;
}
}
}
int main ()
{
std::map<double, double> table;
table.insert(std::pair<double, double>(5, 6));
table.insert(std::pair<double, double>(8, 4));
table.insert(std::pair<double, double>(9, 5));
double y = interpolate(5.1, table);
printf("%f\n", y);
}
Store your points sorted:
index X Y
1 1 -> 3
2 3 -> 7
3 10-> 8
Then loop from max to min and as soon as you get below a number you know it the one you want.
You want let's say 6 so:
// pseudo
for i = 3 to 1
if x[i] <= 6
// you found your range!
// interpolate between x[i] and x[i - 1]
break; // Do not look any further
end
end
Yes, I guess that you should think in a map between those intervals and the natural nummbers. I mean, just label the intervals and use a switch:
switch(I) {
case Int1: //whatever
break;
...
default:
}
I don't know, it's the first thing that I thought of.
EDIT Switch is more efficient than if-else if your numbers are within a relative small interval (that's something to take into account when doing the mapping)
If your x-coordinates must be irregularly spaced, then store the x-coordinates in sorted order, and use a binary search to find the nearest coordinate, for example using Daniel Fleischman's answer.
However, if your problem permits it, consider pre-interpolating to regularly spaced data. So
5 15
7 18
10 22
becomes
5 15
6 16.5
7 18
8 19.3333333
9 20.6666667
10 22
Then at run-time you can interpolate with O(1) using something like this:
double interp1( double x0, double dx, double* y, int n, double xi )
{
double f = ( xi - x0 ) / dx;
if (f<0) return y[0];
if (f>=(n-1)) return y[n-1];
int i = (int) f;
double w = f-(double)i;
return dy[i]*(1.0-w) + dy[i+1]*w;
}
using
double y[6] = {15,16.5,18,19.3333333, 20.6666667, 22 }
double yi = interp1( 5.0 , 1.0 , y, 5, xi );
This isn't necessarily suitable for every problem -- you could end up losing accuracy (if there's no nice grid that contains all your x-samples), and it could have a bad cache penalty if it would make your table much much bigger. But it's a good option for cases where you have some control over the x-coordinates to begin with.
How you've already got it is fairly readable and understandable, and there's a lot to be said for that over a "clever" solution. You can however do away with the lower bounds check and clumsy && because the sequence is ordered:
if (x < 5)
return 0;
else if (x <= 7)
// interpolate
else if (x <= 10)
// interpolate
...

Is there a C/C++ function to safely handle division by zero?

We have a situation we want to do a sort of weighted average of two values w1 & w2, based on how far two other values v1 & v2 are away from zero... for example:
If v1 is zero, it doesn't get weighted at all so we return w2
If v2 is zero, it doesn't get weighted at all so we return w1
If both values are equally far from zero, we do a mean average and return (w1 + w2 )/2
I've inherited code like:
float calcWeightedAverage(v1,v2,w1,w2)
{
v1=fabs(v1);
v2=fabs(v2);
return (v1/(v1+v2))*w1 + (v2/(v1+v2)*w2);
}
For a bit of background, v1 & v2 represent how far two different knobs are turned, the weighting of their individual resultant effects only depends how much they are turned, not in which direction.
Clearly, this has a problem when v1==v2==0, since we end up with return (0/0)*w1 + (0/0)*w2 and you can't do 0/0. Putting a special test in for v1==v2==0 sounds horrible mathematically, even if it wasn't bad practice with floating-point numbers.
So I wondered if
there was a standard library function to handle this
there's a neater mathematical representation
You're trying to implement this mathematical function:
F(x, y) = (W1 * |x| + W2 * |y|) / (|x| + |y|)
This function is discontinuous at the point x = 0, y = 0. Unfortunately, as R. stated in a comment, the discontinuity is not removable - there is no sensible value to use at this point.
This is because the "sensible value" changes depending on the path you take to get to x = 0, y = 0. For example, consider following the path F(0, r) from r = R1 to r = 0 (this is equivalent to having the X knob at zero, and smoothly adjusting the Y knob down from R1 to 0). The value of F(x, y) will be constant at W2 until you get to the discontinuity.
Now consider following F(r, 0) (keeping the Y knob at zero and adjusting the X knob smoothly down to zero) - the output will be constant at W1 until you get to the discontinuity.
Now consider following F(r, r) (keeping both knobs at the same value, and adjusting them down simulatneously to zero). The output here will be constant at W1 + W2 / 2 until you go to the discontinuity.
This implies that any value between W1 and W2 is equally valid as the output at x = 0, y = 0. There's no sensible way to choose between them. (And further, always choosing 0 as the output is completely wrong - the output is otherwise bounded to be on the interval W1..W2 (ie, for any path you approach the discontinuity along, the limit of F() is always within that interval), and 0 might not even lie in this interval!)
You can "fix" the problem by adjusting the function slightly - add a constant (eg 1.0) to both v1 and v2 after the fabs(). This will make it so that the minimum contribution of each knob can't be zero - just "close to zero" (the constant defines how close).
It may be tempting to define this constant as "a very small number", but that will just cause the output to change wildly as the knobs are manipulated close to their zero points, which is probably undesirable.
This is the best I could come up with quickly
float calcWeightedAverage(float v1,float v2,float w1,float w2)
{
float a1 = 0.0;
float a2 = 0.0;
if (v1 != 0)
{
a1 = v1/(v1+v2) * w1;
}
if (v2 != 0)
{
a2 = v2/(v1+v2) * w2;
}
return a1 + a2;
}
I don't see what would be wrong with just doing this:
float calcWeightedAverage( float v1, float v2, float w1, float w2 ) {
static const float eps = FLT_MIN; //Or some other suitably small value.
v1 = fabs( v1 );
v2 = fabs( v2 );
if( v1 + v2 < eps )
return (w1+w2)/2.0f;
else
return (v1/(v1+v2))*w1 + (v2/(v1+v2)*w2);
}
Sure, no "fancy" stuff to figure out your division, but why make it harder than it has to be?
Personally I don't see anything wrong with an explicit check for divide by zero. We all do them, so it could be argued that not having it is uglier.
However, it is possible to turn off the IEEE divide by zero exceptions. How you do this depends on your platform. I know on windows it has to be done process-wide, so you can inadvertantly mess with other threads (and they with you) by doing it if you aren't careful.
However, if you do that your result value will be NaN, not 0. I highly dooubt that's what you want. If you are going to have to put a special check in there anyway with different logic when you get NaN, you might as well just check for 0 in the denominator up front.
So with a weighted average, you need to look at the special case where both are zero. In that case you want to treat it as 0.5 * w1 + 0.5 * w2, right? How about this?
float calcWeightedAverage(float v1,float v2,float w1,float w2)
{
v1=fabs(v1);
v2=fabs(v2);
if (v1 == v2) {
v1 = 0.5;
} else {
v1 = v1 / (v1 + v2); // v1 is between 0 and 1
}
v2 = 1 - v1; // avoid addition and division because they should add to 1
return v1 * w1 + v2 * w2;
}
You chould test for fabs(v1)+fabs(v2)==0 (this seems to be the fastest given that you've already computed them), and return whatever value makes sense in this case (w1+w2/2?). Otherwise, keep the code as-is.
However, I suspect the algorithm itself is broken if v1==v2==0 is possible. This kind of numerical instability when the knobs are "near 0" hardly seems desirable.
If the behavior actually is right and you want to avoid special-cases, you could add the minimum positive floating point value of the given type to v1 and v2 after taking their absolute values. (Note that DBL_MIN and friends are not the correct value because they're the minimum normalized values; you need the minimum of all positive values, including subnormals.) This will have no effect unless they're already extremely small; the additions will just yield v1 and v2 in the usual case.
The problem with using an explicit check for zero is that you can end up with discontinuities in behaviour unless you are careful as outlined in cafs response ( and if its in the core of your algorithm the if can be expensive - but dont care about that until you measure...)
I tend to use something that just smooths out the weighting near zero instead.
float calcWeightedAverage(v1,v2,w1,w2)
{
eps = 1e-7; // Or whatever you like...
v1=fabs(v1)+eps;
v2=fabs(v2)+eps;
return (v1/(v1+v2))*w1 + (v2/(v1+v2)*w2);
}
Your function is now smooth, with no asymptotes or division by zero, and so long as one of v1 or v2 is above 1e-7 by a significant amount it will be indistinguishable from a "real" weighted average.
If the denominator is zero, how do you want it to default? You can do something like this:
static inline float divide_default(float numerator, float denominator, float default) {
return (denominator == 0) ? default : (numerator / denominator);
}
float calcWeightedAverage(v1, v2, w1, w2)
{
v1 = fabs(v1);
v2 = fabs(v2);
return w1 * divide_default(v1, v1 + v2, 0.0) + w2 * divide_default(v2, v1 + v2, 0.0);
}
Note that the function definition and use of static inline should really let the compiler know that it can inline.
This should work
#include <float.h>
float calcWeightedAverage(v1,v2,w1,w2)
{
v1=fabs(v1);
v2=fabs(v2);
return (v1/(v1+v2+FLT_EPSILON))*w1 + (v2/(v1+v2+FLT_EPSILON)*w2);
}
edit:
I saw there may be problems with some precision so instead of using FLT_EPSILON use DBL_EPSILON for accurate results (I guess you will return a float value).
I'd do like this:
float calcWeightedAverage(double v1, double v2, double w1, double w2)
{
v1 = fabs(v1);
v2 = fabs(v2);
/* if both values are equally far from 0 */
if (fabs(v1 - v2) < 0.000000001) return (w1 + w2) / 2;
return (v1*w1 + v2*w2) / (v1 + v2);
}