I have two three-dimensional non-zero vectors which I know to be parallel, and thus I can multiply each component of one vector by a constant to obtain the other. In order to determine this constant, I can take any of the fields from both vectors and divide them by one another to obtain the scale factor.
For example:
vec3 vector1(1.0, 1.5, 2.0);
vec3 vector2(2.0, 3.0, 4.0);
float scaleFactor = vector2.x / vector1.x; // = 2.0
Unfortunately, picking the same field (say the x-axis) every time risks the divisor being zero.
Dividing the lengths of the vectors is not possible either because it does not take a negative scale factor into account.
Is there an efficient means of going about this which avoids zero divisions?
So we want something that:
1- has no branching
2- avoids division by zero
3- ensures the largest possible divider
These requirements are achieved by the ratio of two dot-products:
(v1 * v2) / (v2 * v2)
=
(v1.x*v2.x + v1.y*v2.y + v1.z*v2.z) / (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z)
In the general case where the dimension is not a (compile time) constant, both numerator and denominator can be computed in a single loop.
Pretty much, this.
inline float scale_factor(const vec3& v1, const vec3& v2, bool* fail)
{
*fail = false;
float eps = 0.000001;
if (std::fabs(vec1.x) > eps)
return vec2.x / vec1.x;
if (std::fabs(vec1.y) > eps)
return vec2.y / vec1.y;
if (std::fabs(vec1.z) > eps)
return vec2.z / vec1.z;
*fail = true;
return -1;
}
Also, one can think of getting 2 sums of elements, and then getting a scale factor with a single division. You can get sum effectively by using IPP's ippsSum_32f, for example, as it is calculated using SIMD instructions.
But, to be honest, I doubt that you can really improve these methods. Either sum all -> divide or branch -> divide will provide you with the solution pretty close to the best.
To minimize the relative error, use the largest element:
if (abs(v1.x) > abs(v1.y) && abs(v1.x) > abs(v1.z))
return v2.x / v1.x;
else if (abs(v1.y) > abs(v1.x) && abs(v1.y) > abs(v1.z))
return v2.y / v1.y;
else
return v2.z / v1.z;
This code assumes that v1
is not a zero vector.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.