简体   繁体   中英

How do I efficiently determine the scale factor of two parallel vectors?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM