#818·codon

[GPU] complex `sin` op results `nan`

Author: BI71317Created May 24, 2026Updated May 24, 2026

Summary

This issue appears to be a partial manifestation of #781, the uninitialized GV issue.

MRE

python
import cmath
import gpu


@gpu.kernel
def kernel(xs, out_real, out_imag):
    z = cmath.sin(xs[0])
    out_real[0] = z.real
    out_imag[0] = z.imag


x = complex(0.5, 0.25)
cpu = cmath.sin(x)
out_real = [0.0]
out_imag = [0.0]

kernel([x], out_real, out_imag, grid=1, block=1)
gpu_result = complex(out_real[0], out_imag[0])

print("input:", x)
print("CPU cmath.sin:", cpu)
print("GPU cmath.sin:", gpu_result)

results

bash
$ codon run -release mre_complex_sin.codon 
input: (0.5+0.25j)
CPU cmath.sin: (0.494486+0.221688j)
GPU cmath.sin: (nan+nanj)

Root Cause

For complex values, cmath.sin is not lowered to the primitive sin(float) operation directly.

Instead, it is evaluated using the Euler-based complex formula:

For complex var C = a + bi
sin(C) = sin(a) * cosh(b) + i * cos(a) * sinh(b)

The CPU implementation appears to compute this correctly, while the GPU version returns nan.

In cmath.codon, the complex implementation uses GV-backed constants/functions:

    if math.fabs(z.real) > _CM_LOG_LARGE_DOUBLE:
        x_minus_one = z.real - math.copysign(1., z.real)
        r_real = math.cos(z.imag) * math.sinh(x_minus_one) * e
        r_imag = math.sin(z.imag) * math.cosh(x_minus_one) * e
    else:
        r_real = math.cos(z.imag) * math.sinh(z.real)
        r_imag = math.sin(z.imag) * math.cosh(z.real)

As discussed in #781, this seems likely to be caused by the uninitialized GV issue.