imate
C++/CUDA Reference
Loading...
Searching...
No Matches
special_functions.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: Copyright 2021, Siavash Ameli <sameli@berkeley.edu>
3 * SPDX-License-Identifier: BSD-3-Clause
4 * SPDX-FileType: SOURCE
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the license found in the LICENSE.txt file in the root
8 * directory of this source tree.
9 */
10
11
12// =======
13// Headers
14// =======
15
16// Before including cmath, define _USE_MATH_DEFINES. This is only required to
17// define the math constants like M_PI, etc, in win32 operating system.
18#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && \
19 !defined(__CYGWIN__)
20 #define _USE_MATH_DEFINES
21#endif
22
23#include <cmath> // sqrt, log, exp, erf, INFINITY, M_PI
24#include "./special_functions.h"
25#include "../_c_arithmetics/c_arithmetics.h" // c_arithmetics
26
27
28// ====
29// sign
30// ====
31
34
35double _sign(const double x)
36{
37 return (x > 0) - (x < 0);
38}
39
40
41// =======
42// erf inv
43// =======
44
64
65double erf_inv(const double x)
66{
67 // Output
68 double r;
69
70 // Check extreme values
72 {
73 r = _sign(x) * INFINITY;
74 return r;
75 }
76
77 double a[4] = {0.886226899, -1.645349621, 0.914624893, -0.140543331};
78 double b[5] = {1.0, -2.118377725, 1.442710462, -0.329097515, 0.012229801};
79 double c[4] = {-1.970840454, -1.62490649, 3.429567803, 1.641345311};
80 double d[3] = {1.0, 3.543889200, 1.637067800};
81
82 double z = _sign(x) * x;
83
84 if (z <= 0.7)
85 {
86 double x2 = z * z;
87 r = z * (((a[3] * x2 + a[2]) * x2 + a[1]) * x2 + a[0]);
88 r /= (((b[4] * x2 + b[3]) * x2 + b[2]) * x2 + b[1]) * x2 + b[0];
89 }
90 else
91 {
92 double y = sqrt(-log((1.0 - z) / 2.0));
93 r = (((c[3] * y + c[2]) * y + c[1]) * y + c[0]);
94 r /= ((d[2] * y + d[1]) * y + d[0]);
95 }
96
97 r = r * _sign(x);
98 z = z * _sign(x);
99
100 // These two lines below are identical and repeated for double refinement.
101 // Comment one line below for a single refinement of the Newton method.
102 r -= (erf(r) - z) / ((2.0 / sqrt(M_PI)) * exp(-r * r));
103 r -= (erf(r) - z) / ((2.0 / sqrt(M_PI)) * exp(-r * r));
104
105 return r;
106}
bool is_equal(DataType x, DataType y)
Check if two floating point numbers are equal within a tolerance.
Definition _c_is_equal.h:49
double erf_inv(const double x)
Inverse error function.
double _sign(const double x)
sign function.