What does the atanh function do in MATLAB / RunMat?
Y = atanh(X) evaluates the inverse hyperbolic tangent of every element in X. Real inputs inside
the open interval (-1, 1) remain real. Values with |x| > 1 (including ±Inf) automatically
promote to complex results that match MATLAB's principal branch.
How does the atanh function behave in MATLAB / RunMat?
- Accepts scalars, vectors, matrices, and N-D tensors using MATLAB broadcasting semantics.
- Logical values are promoted to double precision (
true → 1,false → 0) before evaluation. The results follow MATLAB's rules for infinities at the endpoints (atanh(1) = Inf,atanh(-1) = -Inf). - Real values with magnitude greater than
1return complex numbers whose imaginary part is±π/2. The runtime automatically promotes the entire tensor toValue::ComplexTensorso downstream consumers see the MATLAB-compatible complex result. - Complex inputs are evaluated with MATLAB's definition
atanh(z) = 0.5 * log((1 + z) / (1 - z)), including correct handling of branch cuts, NaNs, and infinities. - Character arrays are treated as their numeric code points and converted to doubles before the inverse hyperbolic tangent is applied.
- Empty arrays return empty outputs with matching shape and type.
atanh Function GPU Execution Behaviour
RunMat Accelerate keeps tensors on the GPU when:
- A provider is registered and implements the
unary_atanhhook. - Every element satisfies
|x| ≤ 1(allowing the endpoints for the ±Inf behaviour).
The runtime first calls the provider's reduce_min/reduce_max hooks to prove that the entire operand
stays within the real domain [-1, 1]. If those hooks are missing, return an error, or detect a value
outside the domain, RunMat gathers the tensor to the host, performs the computation with the CPU
reference implementation, and returns MATLAB-accurate complex results. Users do not need to micromanage
residency with gpuArray/gather; the runtime transparently falls back only when necessary.
Examples of using the atanh function in MATLAB / RunMat
Inverse hyperbolic tangent of a real scalar
y = atanh(0.5);
Expected output:
y = 0.5493
Applying atanh element-wise to a vector
x = linspace(-0.9, 0.9, 5);
y = atanh(x);
Expected output:
y = [-1.4722 -0.4847 0 0.4847 1.4722]
Dealing with values near ±1 in atanh
A = [0.99 1.0 -1.0; 0.0 0.5 -0.5];
B = atanh(A);
Expected output:
B =
2.6467 Inf -Inf
0 0.5493 -0.5493
Producing complex outputs for |x| > 1
values = [2 -3];
result = atanh(values);
Expected output:
result =
0.5493 + 1.5708i -0.3466 + 1.5708i
Computing atanh for complex numbers
Z = [1 + 2i, -0.5 + 0.75i];
W = atanh(Z);
Expected output:
W =
0.1733 + 1.1781i -0.3104 + 0.7232i
Running atanh on GPU arrays
G = gpuArray(linspace(-0.8, 0.8, 4));
gpuResult = atanh(G);
hostResult = gather(gpuResult);
Expected output:
hostResult = [-1.0986 -0.2733 0.2733 1.0986]
GPU residency in RunMat (Do I need gpuArray?)
You usually do not need to call gpuArray manually. The auto-offload planner keeps tensors on
the GPU whenever the provider exposes a working unary_atanh hook and every element satisfies |x| ≤ 1.
If any element requires complex promotion or the provider lacks native support, RunMat automatically
gathers to the host and still returns MATLAB-compatible results. Manual gpuArray / gather remains
available for workflows that demand explicit residency control.
FAQ
When does atanh return complex numbers?
Whenever an element has magnitude strictly greater than 1, including ±Inf, MATLAB defines the
result as complex with an imaginary component of ±π/2. RunMat mirrors that behaviour exactly.
How are the endpoints ±1 handled?
atanh(1) returns positive infinity and atanh(-1) returns negative infinity, matching MATLAB. These
values still count as real outputs, so the GPU path can handle them without falling back.
What happens with NaN inputs?
NaNs propagate through the computation. If the GPU provider supports unary_atanh, the operation can
remain on the device; otherwise the runtime falls back to the host and returns the same NaN results.
Does the GPU path differ in precision from the CPU path?
Both paths evaluate the inverse hyperbolic tangent in the provider's precision (f32 or f64). Small
rounding differences may occur but stay within MATLAB's tolerance requirements.
Can complex inputs stay on the GPU?
Not yet. GPU tensor handles represent real buffers. When complex outputs are required (either because
the input is complex or a real value exceeds the domain), RunMat promotes the result to
Value::Complex/Value::ComplexTensor on the host so the semantics match MATLAB.
Will atanh participate in fusion and autodiff?
Yes. The builtin registers element-wise fusion metadata so the planner can inline it into fused WGSL kernels, and the same metadata feeds future autodiff tooling.
Are logical and integer inputs supported?
Yes. They are promoted to doubles before evaluation. Outputs follow MATLAB's double or complex-double conventions depending on the values.
What if my provider does not implement unary_atanh?
RunMat automatically gathers the data, evaluates atanh on the CPU, and returns correct results.
Consider enabling the in-process provider for development or the WGPU provider for production to keep
the operation on the GPU.
See Also
tanh, asinh, acosh, atan, gpuArray, gather
Source & Feedback
- The full source code for the implementation of the
atanhfunction is available at:crates/runmat-runtime/src/builtins/math/trigonometry/atanh.rs - Found a bug or behavioural difference? Please open an issue with details and a minimal repro.