MLX
 
Loading...
Searching...
No Matches
math.h
Go to the documentation of this file.
1// Copyright © 2024 Apple Inc.
2
3#pragma once
4
6
7namespace mlx::core::simd {
8
9constexpr float inf = std::numeric_limits<float>::infinity();
10
27template <typename T, int N>
29 if constexpr (is_complex<T>) {
30 return Simd<T, 1>{std::exp(in.value)};
31 } else {
32 Simd<float, N> x_init = in;
33 auto x = x_init * 1.442695f; // multiply with log_2(e)
34 Simd<float, N> ipart, fpart;
35 ipart = floor(x + 0.5);
36 fpart = x - ipart;
37
38 x = 1.535336188319500e-4f;
39 x = fma(x, fpart, 1.339887440266574e-3f);
40 x = fma(x, fpart, 9.618437357674640e-3f);
41 x = fma(x, fpart, 5.550332471162809e-2f);
42 x = fma(x, fpart, 2.402264791363012e-1f);
43 x = fma(x, fpart, 6.931472028550421e-1f);
44 x = fma(x, fpart, 1.000000000000000f);
45
46 // generate 2**ipart in the floating point representation using integer
47 // bitshifting
48 Simd<int, N> epart = (Simd<int, N>(ipart) + 127) << 23;
49
50 // Deal with NaN and Inf
51 auto result = select(isnan(x_init), x_init, (*(Simd<float, N>*)&epart) * x);
52 result = select(x_init > 88.0f, Simd<float, N>(inf), result);
53 result = select(x_init < -88.0f, Simd<float, N>(0), result);
54 return Simd<T, N>(result);
55 }
56}
57
58/* Implementation from:
59 * https://github.com/JishinMaster/simd_utils/blob/3c1433a86fb38edcc9b02039f3c9a65b16640976/neon_mathfun.h#L357
60 * which originally came from the Cephes math library.
61 */
62template <bool Sine, typename T, int N>
64 auto sign_mask_sin = in < 0;
65 in = abs(in);
66 Simd<float, N> x = in;
67
68 // scale by 4/Pi
69 auto y = x * 1.27323954473516f;
70
71 // store the integer part of y in mm0
72 Simd<uint32_t, N> emm2 = y;
73
74 // j=(j+1) & (~1) (see the cephes sources)
75 emm2 = emm2 + 1;
76 emm2 = emm2 & ~1;
77
78 y = emm2;
79
80 // Get the polynom selection mask. There is one polynom for 0 <= x <= Pi/4
81 // and another one for Pi/4<x<=Pi/2. Both branches will be computed.
82 auto poly_mask = (emm2 & 2) != 0;
83
84 // The magic pass: "Extended precision modular arithmetic"
85 // x = ((x - y * DP1) - y * DP2) - y * DP3
86 x = fma(y, Simd<float, N>(-0.78515625f), x);
87 x = fma(y, Simd<float, N>(-2.4187564849853515625e-4f), x);
88 x = fma(y, Simd<float, N>(-3.77489497744594108e-8f), x);
89
90 sign_mask_sin = sign_mask_sin ^ ((emm2 & 4) != 0);
91 auto sign_mask_cos = ((emm2 - 2) & 4) != 0;
92
93 // Evaluate the first polynom (0 <= x <= Pi/4) in y1,
94 // and the second polynom (Pi/4 <= x <= 0) in y2
95 auto z = x * x;
96
97 auto y1 =
98 fma(z, Simd<float, N>(2.443315711809948e-5f), -1.388731625493765e-3f);
99 auto y2 = fma(z, Simd<float, N>(-1.9515295891e-4f), 8.3321608736e-3f);
100 y1 = fma(y1, z, 4.166664568298827e-2f);
101 y2 = fma(y2, z, -1.6666654611e-1f);
102 y1 = y1 * z;
103 y2 = y2 * z;
104 y1 = y1 * z;
105 y2 = fma(x, y2, x);
106 y1 = fma(z, Simd<float, N>(-0.5f), y1);
107 y1 = y1 + 1.0f;
108
109 if constexpr (Sine) {
110 auto ys = select(poly_mask, y1, y2);
111 return select(sign_mask_sin, -ys, ys);
112 } else {
113 auto yc = select(poly_mask, y2, y1);
114 return select(sign_mask_cos, yc, -yc);
115 }
116}
117
118template <typename T, int N>
120 if constexpr (is_complex<T>) {
121 return std::sin(x.value);
122 } else {
123 return sincos<true>(x);
124 }
125}
126
127template <typename T, int N>
129 if constexpr (is_complex<T>) {
130 return std::cos(x.value);
131 } else {
132 return sincos<false>(x);
133 }
134}
135
136template <typename T, int N>
138 // https://github.com/pytorch/pytorch/blob/abf28982a8cb43342e7669d859de9543fd804cc9/aten/src/ATen/cpu/vec/vec256/vec256_float.h#L175
139 Simd<float, N> v = x;
140 auto t = recip(fma(Simd<float, N>(0.3275911f), abs(v), 1.0f));
141 auto r = fma(Simd<float, N>(1.061405429f), t, -1.453152027f);
142 r = fma(r, t, 1.421413741f);
143 r = fma(r, t, -0.284496736f);
144 r = fma(r, t, 0.254829592f);
145 auto e = -exp(-v * v);
146 auto result = Simd<T, N>(fma(e * t, r, 1.0f));
147 return select(x > 0, result, -result);
148}
149
150template <typename T, int N>
152 Simd<float, N> a = a_;
153 auto t = fma(a, 0.0f - a, 1.0f);
154 t = log(t);
155 auto lhs = [](auto t) {
157 p = 3.03697567e-10f; // 0x1.4deb44p-32
158 p = fma(p, t, 2.93243101e-8f); // 0x1.f7c9aep-26
159 p = fma(p, t, 1.22150334e-6f); // 0x1.47e512p-20
160 p = fma(p, t, 2.84108955e-5f); // 0x1.dca7dep-16
161 p = fma(p, t, 3.93552968e-4f); // 0x1.9cab92p-12
162 p = fma(p, t, 3.02698812e-3f); // 0x1.8cc0dep-9
163 p = fma(p, t, 4.83185798e-3f); // 0x1.3ca920p-8
164 p = fma(p, t, -2.64646143e-1f); // -0x1.0eff66p-2
165 return fma(p, t, 8.40016484e-1f); // 0x1.ae16a4p-1
166 };
167 auto rhs = [](auto t) {
169 p = 5.43877832e-9f; // 0x1.75c000p-28
170 p = fma(p, t, 1.43285448e-7f); // 0x1.33b402p-23
171 p = fma(p, t, 1.22774793e-6f); // 0x1.499232p-20
172 p = fma(p, t, 1.12963626e-7f); // 0x1.e52cd2p-24
173 p = fma(p, t, -5.61530760e-5f); // -0x1.d70bd0p-15
174 p = fma(p, t, -1.47697632e-4f); // -0x1.35be90p-13
175 p = fma(p, t, 2.31468678e-3f); // 0x1.2f6400p-9
176 p = fma(p, t, 1.15392581e-2f); // 0x1.7a1e50p-7
177 p = fma(p, t, -2.32015476e-1f); // -0x1.db2aeep-3
178 return fma(p, t, 8.86226892e-1f); // 0x1.c5bf88p-1
179 };
180 auto thresh = 6.125f;
181 // Compute both branches and select if N > 1
182 if constexpr (N == 1) {
183 if ((abs(t) > thresh).value) { // maximum ulp error = 2.35793
184 return a * lhs(t);
185 } else { // maximum ulp error = 2.35002
186 return a * rhs(t);
187 }
188 } else {
189 return a * select(t > thresh, lhs(t), rhs(t));
190 }
191}
192
193} // namespace mlx::core::simd
Definition accelerate_fp16_simd.h:9
Simd< bool, N > isnan(Simd< T, N > v)
Definition accelerate_simd.h:146
constexpr int N
Definition neon_fp16_simd.h:9
Simd< T, N > abs(Simd< T, N > v)
Definition accelerate_simd.h:112
Simd< T, N > erf(Simd< T, N > x)
Definition math.h:137
constexpr bool is_complex
Definition base_simd.h:43
Simd< T, N > erfinv(Simd< T, N > a_)
Definition math.h:151
constexpr float inf
Definition math.h:9
Simd< T, N > exp(Simd< T, N > in)
Compute exp(x) in an optimizer friendly way as follows:
Definition math.h:28
Simd< float16_t, N > log(Simd< float16_t, N > v)
Definition accelerate_fp16_simd.h:37
Simd< T, N > floor(Simd< T, N > v)
Definition accelerate_simd.h:113
Simd< T, N > fma(Simd< T, N > x, Simd< T, N > y, U z)
Definition accelerate_simd.h:269
Simd< T, N > cos(Simd< T, N > x)
Definition math.h:128
Simd< T, N > sin(Simd< T, N > x)
Definition math.h:119
Simd< T, N > sincos(Simd< T, N > in)
Definition math.h:63
Simd< T, N > recip(Simd< T, N > v)
Definition accelerate_simd.h:131
Simd< T1, N > select(Simd< MaskT, N > mask, Simd< T1, N > x, Simd< T2, N > y)
Definition accelerate_simd.h:236
Definition accelerate_simd.h:55
asd::Vector< scalar_t, N >::packed_t value
Definition accelerate_simd.h:80