-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement a fast atan approximation function (#1583)
implement a fast atan function using an approximate function for x in [-1, 1], for |x| > 1, the identity arctan(x) = sign(pi/2, x) - arctan(1/x) (Thanks to Eric) is used. Two versions of the approximate functions are included. 1. Efficient Approximations for the Arctangent Function by Rajan 2006: Equation 9: Max error ~0.0015 rad 2. https://stackoverflow.com/questions/42537957/fast-accurate-atan-arctan-approximation-algorithm: Max error ~0.00063 rad Generally I find the form from stackoverflow is more accurate and also faster. 1) is also discussed in 2). In general, from testing, atanf is roughly more than 2 times faster than std::atan.
- Loading branch information
Showing
11 changed files
with
686 additions
and
403 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
700 changes: 350 additions & 350 deletions
700
unit_test/test_ase/make_table/ci-benchmarks/ase_nse_net_make_table_unit_test.out
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
CEXE_headers += approx_math.H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#ifndef APPROX_MATH_H | ||
#define APPROX_MATH_H | ||
|
||
#include <AMReX_REAL.H> | ||
#include <microphysics_math.H> | ||
|
||
using namespace amrex::literals; | ||
|
||
AMREX_GPU_HOST_DEVICE AMREX_INLINE | ||
amrex::Real fast_atan_1(const amrex::Real x) { | ||
/// | ||
/// This calculates atan within [-1, 1] range. | ||
/// | ||
|
||
/// | ||
/// Approximation of atan for x in [-1, 1] | ||
/// Max absolute error for this is ~0.0015 rad | ||
/// See Ref: | ||
/// Efficient Approximations for the Arctangent Function by Rajan 2006 | ||
/// | ||
|
||
// constexpr amrex::Real PI_4 = GCEM_PI / 4.0_rt; | ||
|
||
// return PI_4*x - x*(std::abs(x) - 1.0_rt) * | ||
// (0.2447_rt + 0.0663_rt*std::abs(x)); | ||
|
||
|
||
/// | ||
/// Another approximation of atan for x in [-1, 1] | ||
/// Max absolute error for this is ~0.00063 rad | ||
/// See Ref: | ||
/// https://stackoverflow.com/questions/42537957/fast-accurate-atan-arctan-approximation-algorithm | ||
/// | ||
|
||
constexpr amrex::Real A = 0.0776509570923569_rt; | ||
constexpr amrex::Real B = -0.287434475393028_rt; | ||
constexpr amrex::Real C = GCEM_PI / 4.0_rt - A - B; | ||
|
||
amrex::Real x2 = x*x; | ||
return ((A*x2 + B)*x2 + C)*x; | ||
} | ||
|
||
|
||
AMREX_GPU_HOST_DEVICE AMREX_INLINE | ||
amrex::Real fast_atan(const amrex::Real x) { | ||
/// | ||
/// Fast atan approximation calculations. | ||
/// | ||
|
||
constexpr amrex::Real PI_2 = 0.5_rt * GCEM_PI; | ||
|
||
/// | ||
/// If x < 0.113, then using arctan(x) ~ x | ||
/// gives better answer than the approximation below. | ||
/// And accuracy increase as x << 0.113. | ||
/// Also significantly faster. | ||
/// | ||
|
||
if (std::abs(x) < 0.113_rt) { | ||
return x; | ||
} | ||
|
||
// Check for large number, close to infinity. | ||
// Error is ~1e-8 rad by not checking actual inf | ||
|
||
if (x > 1.e8_rt) { | ||
return PI_2; | ||
} | ||
if (x < -1.e8_rt) { | ||
return -PI_2; | ||
} | ||
|
||
// Now calculate Atan(x) using approximations | ||
|
||
if (x > 1.0_rt) { | ||
return PI_2 - fast_atan_1(1.0_rt / x); | ||
} | ||
if (x < -1.0_rt) { | ||
return -PI_2 - fast_atan_1(1.0_rt / x); | ||
} | ||
return fast_atan_1(x); | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
PRECISION = DOUBLE | ||
PROFILE = FALSE | ||
|
||
DEBUG = FALSE | ||
|
||
DIM = 3 | ||
|
||
COMP = gnu | ||
|
||
USE_MPI = FALSE | ||
USE_OMP = FALSE | ||
|
||
USE_REACT = TRUE | ||
|
||
EBASE = main | ||
|
||
# define the location of the Microphysics top directory | ||
MICROPHYSICS_HOME ?= ../../.. | ||
|
||
# This sets the EOS directory | ||
EOS_DIR := helmholtz | ||
|
||
# This sets the network directory | ||
NETWORK_DIR := aprox21 | ||
|
||
CONDUCTIVITY_DIR := stellar | ||
|
||
INTEGRATOR_DIR = VODE | ||
|
||
ifeq ($(USE_CUDA), TRUE) | ||
INTEGRATOR_DIR := VODE | ||
endif | ||
|
||
EXTERN_SEARCH += . | ||
|
||
Bpack := ../Make.package ./Make.package | ||
Blocs := ../ . | ||
|
||
include $(MICROPHYSICS_HOME)/unit_test/Make.unit_test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
CEXE_sources += main.cpp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
#include <test_fast_atan.H> | ||
|
||
int main() { | ||
|
||
// Accuracy tests | ||
|
||
// Test values including edge cases and some typical values | ||
|
||
test_fast_atan_accuracy(0.0_rt); | ||
test_fast_atan_accuracy(0.01_rt); | ||
test_fast_atan_accuracy(0.08_rt); | ||
test_fast_atan_accuracy(0.1_rt); | ||
test_fast_atan_accuracy(0.5_rt); | ||
test_fast_atan_accuracy(1.0_rt); | ||
test_fast_atan_accuracy(5.0_rt); | ||
test_fast_atan_accuracy(8.0_rt); | ||
test_fast_atan_accuracy(10.0_rt); | ||
test_fast_atan_accuracy(25.0_rt); | ||
test_fast_atan_accuracy(100.0_rt); | ||
test_fast_atan_accuracy(500.0_rt); | ||
test_fast_atan_accuracy(5.0e8_rt); | ||
|
||
test_fast_atan_accuracy(-0.01_rt); | ||
test_fast_atan_accuracy(-0.08_rt); | ||
test_fast_atan_accuracy(-0.1_rt); | ||
test_fast_atan_accuracy(-0.5_rt); | ||
test_fast_atan_accuracy(-1.0_rt); | ||
test_fast_atan_accuracy(-5.0_rt); | ||
test_fast_atan_accuracy(-8.0_rt); | ||
test_fast_atan_accuracy(-10.0_rt); | ||
test_fast_atan_accuracy(-25.0_rt); | ||
test_fast_atan_accuracy(-100.0_rt); | ||
test_fast_atan_accuracy(-500.0_rt); | ||
test_fast_atan_accuracy(-5.0e8_rt); | ||
|
||
// Inf Case | ||
|
||
test_fast_atan_accuracy(std::numeric_limits<amrex::Real>::infinity()); | ||
test_fast_atan_accuracy(-std::numeric_limits<amrex::Real>::infinity()); | ||
|
||
std::cout << "Accuracy tests passed!" << std::endl; | ||
|
||
// Now performance test | ||
|
||
int iters = 5; | ||
amrex::Real test_value = 160.0_rt; | ||
test_fast_atan_speed(100, iters, test_value); | ||
|
||
iters = 10; | ||
test_fast_atan_speed(100, iters, test_value); | ||
|
||
iters = 20; | ||
test_fast_atan_speed(100, iters, test_value); | ||
|
||
iters = 30; | ||
test_fast_atan_speed(100, iters, test_value); | ||
|
||
iters = 50; | ||
test_fast_atan_speed(100, iters, test_value); | ||
|
||
iters = 70; | ||
test_fast_atan_speed(100, iters, test_value); | ||
} |
Oops, something went wrong.