Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The average and largest error are significantly better for this version (2-3 orders of magnitude), and it can be slightly faster. For comparison, this implementation uses one
Math.sqrt()
call (on a float argument and cast to float, which HotSpot optimizes well), whereas the implementation it replaces uses one float division. These seem to have about the same performance cost on modern Intel hardware; it may be different on AMD processors or ARM. In terms of accuracy, there's no comparison; the previous asin() in MathUtils was only usable if the high error near inputs of -1 and 1 wasn't noticeable.This algorithm was described in a 1955 research study by RAND Corp, "Approximations for Digital Computers." There are other approximations for asin() described, but the first one, on sheet 35, is the fastest. It's also the least precise of the approximations they give, but it's still much more precise than the current one, which is by Dennis Kjaer Christensen.
I did a comparative benchmark for the previous MathUtils (in GDXASinBench), this PR (in ASin35FloatBench, 35 because the approximation was on sheet 35), and Math (MathASinBench). Higher is better; each of these measures ops/second:
The acos() implementation here is slightly faster than asin(), because it can avoid adding or subtracting PI or HALF_PI in one of its branches. I benchmarked all of these on a 10th-gen i7 hexacore laptop processor, and performance is likely to vary somewhat on much older PCs because of how thoroughly Math.sqrt() gets optimized on recent CPUs.
I also compared the absolute average error, relative average error, and largest single absolute error for both approximations. These were computed for 2048 equally-spaced floats from -1 (inclusive) to 1 (exclusive).
If anyone has any questions, just ask; the previous approximations for asin() and acos() weren't tested enough by me when I had suggested them a while ago. I knew they were fast, but I didn't know there were faster approximations that had better accuracy.