[
https://issues.apache.org/jira/browse/GEOMETRY-119?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17313120#comment-17313120
]
Matt Juntunen commented on GEOMETRY-119:
----------------------------------------
I just ran some JMH benchmarks and there is a definite gain when using the
{{normalizeOrDefault}} method over an explicit check on the norm before calling
{{normalize}}, and a very small gain over using a try-catch.
Benchmark method bodies:
{code:java}
// safeNormalize3D
// (should also check for NaN, etc in actual usage)
if (v.norm() != 0.0) {
return v.normalize();
}
return v;
// catchNormalize3D
try {
return v.normalize();
} catch (IllegalArgumentException exc) {
return null;
}
// normalizeOrDefault
v.normalizeOrDefault(null);
{code}
Results:
||Benchmark||(size)||Mode||Cnt||Score||Error||Units||
|VectorPerformance.safeNormalize3D|100|avgt|5|2831.197|± 135.857|ns/op|
|VectorPerformance.safeNormalize3D|10000|avgt|5|293549.458|± 8534.388|ns/op|
|VectorPerformance.catchNormalize3D|100|avgt|5|2699.497|± 685.524|ns/op|
|VectorPerformance.catchNormalize3D|10000|avgt|5|257472.523|± 19955.218|ns/op|
|VectorPerformance.normalizeOrDefault|100|avgt|5|2491.177|± 541.369|ns/op|
|VectorPerformance.normalizeOrDefault|10000|avgt|5|256620.115|± 49329.504|ns/op|
In addition to the performance benefits, there is the benefit of not requiring
the caller to handle possible NaN or infinite norms (or inverse norms) before
calling {{normalize}}.
If the current method signature is the issue (and not the functionality), then
I would consider signatures like {{normalizeOrNull()}} or {{tryNormalize()}},
neither of which accept an argument. Now, that I think about it,
{{normalizeOrNull()}} sounds better to me than {{normalizeOrDefault()}}.
> Vector normalizeOrDefault() method
> ----------------------------------
>
> Key: GEOMETRY-119
> URL: https://issues.apache.org/jira/browse/GEOMETRY-119
> Project: Apache Commons Geometry
> Issue Type: Improvement
> Reporter: Matt Juntunen
> Priority: Major
>
> A frequent use case when working with vectors, especially vectors coming from
> external data, is attempting to normalize the vector, and if this is not
> possible, to use an alternative value. For example, the
> {{QuaternionRotation}} code
> [here|https://github.com/apache/commons-geometry/blob/master/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/rotation/QuaternionRotation.java#L86]
> does exactly this; it attempts to normalize a vector and failing that (ie,
> if the vector is exactly zero), it returns a substitute value. The
> {{QuaternionRotation}} class is able to take advantage of our internal
> {{Vectors.tryNormalize()}} but callers outside of the library are not able to
> do so and so are left with 2 choices:
> 1. wrap the {{normalize()}} call in a try-catch and handle the exception
> thrown on illegal norm values, or
> 2. compute and test the norm prior to calling {{normalize()}} to ensure that
> the call won't fail, resulting in 2 computations of the norm.
> Neither of these options are very good.
> I propose adding a new method to the Euclidean Vector classes to handle this
> situation: {{normalizeOrDefault()}}. The method would accept a default value
> (possibly null) to return if the vector cannot be normalized. The normal
> would then only need to be computed once and an exception would not need to
> be thrown in case of failure. The behavior of the current {{normalize}}
> method would be the same.
> Examples:
> {code:java}
> // get some kind of normal, preferably vec but +z will also do
> Vector3D.Unit norm = vec.normalizeOrDefault(Vector3D.Unit.PLUS_Z);
> {code}
> {code:java}
> // throw a very use-case specific error message
> Vector3D norm = vec.normalizeOrDefault(null);
> if (norm == null) {
> throw new Exception("Invalid triangle at index " + i + ": cannot compute
> normal.");
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.3.4#803005)