|
 |
On 5/11/21 4:50 AM, William F Pokorny wrote:
> OK. Been running both approaches within the c++ 'vectors.h' framework of
> POV-Ray. Initial idea is both forms could be in one inbuilt function and
> therefore "munction" too.
>
> // Original macro approach:
>
> #macro VAngle(V1, V2)
> acos(max(-1,min(1,vdot(vnormalize(V1),vnormalize(V2)))))
> #end
>
>
> // Tor Olav's proposal for better accuracy:
> #macro AngleBetweenVectors(v1, v2)
>
> #local v1n = vnormalize(v1);
> #local v2n = vnormalize(v2);
>
> (2*atan2(vlength(v1n - v2n), vlength(v1n + v2n)))
>
> #end // macro AngleBetweenVectors
>
...
>
> I have still a few other tests in mind(1), but busy for a couple days -
> starting now.
>
> (1) - Different optimizations, etc.
...
All more complicated than expected and I'm not normally concise, but
I'll try...
I now have an inbuilt f_vangle() which supports both the old and Tor
Olav's method - and where both are faster when used within VAngle making
it now a "munction." I'll post more about f_vangle later in povray
unofficial patches.
---
Using more targeted random vectors near the noisy parts:
Largest diff 2 ver 0.00000003650005986 ~ 1e-7
Max dot prod sum +1.00000000000000067 (3x DBL_EPSILON)
Min dot prod sum -1.00000000000000067
Min abs dot prod sum 0.00000000000000000
---
With the results above, one might ask how did we not have domain errors
on the -1 side with all those acos(dot(... based macros we have?
Ans: It turns out the parser version of acos tests the inputs, clamps if
need be and issues a warning on each bad-domain call. This means any
math.inc clamping is really there to suppress the warning messages.
Why not a parse error over a warning is a good question - given warnings
can be ignored. It would be better for the user to learn and correct code.
---
The raw acos result and so the vm version of acos returns nan (not a
number) for bad inputs. Peripherally related compiler optimizations
related to the -ffastmath optimizations cause internal routines like
POV_ISINF, POV_ISNAN (std::isnan and the like too) to always return
false. And, POV_ISFINITE and IsFinite() to always return true. These are
not much used, but this caught me up as I was trying to use them to pick
up domain errors initially.
---
Related to this VAngle look we have in math.inc a macro called
VCos_Angle which I believe should be clamped and it now is in my version.
// Cosine of angle between V1 and V2
// #macro VCos_Angle(V1, V2) vdot(vnormalize(V1), vnormalize(V2)) #end
// +14% over million calls to clamp, but we should clamp.
#macro VCos_Angle(V1, V2)
max(-1,min(1,vdot(vnormalize(V1),vnormalize(V2))))
#end
---
By experiment only it looks like the old method gives us about 7
significant digits, Tor Olav's 12 significant digits. This is at
extremes, however.
---
I ran both approaches posted at top against over a million random vector
calls to measure the performance impact of the more accurate method.
One million calls to VAngle
9.65user 5.52system 0:15.70elapsed <-- Original acos(dot..)macro.
10.01user 5.24system 0:15.79elapsed with both min and max clip.
9.69user 5.35system 0:15.58elapsed
9.69user 5.36system 0:15.58elapsed
"9.65 9.69 9.69"
One million calls to AngleBetweenVectors
11.21user 5.31system 0:17.05elapsed
11.35user 5.26system 0:17.14elapsed
11.57user 5.48system 0:17.57elapsed
11.43user 5.45system 0:17.42elapsed
"11.21 11.35 11.43" 29.03 -> 33.99 ---> +17.09%
Expect similar performance differences in any v3.8 based branch.
Bill P.
Post a reply to this message
|
 |