RosettaCodeData/Task/Arithmetic-Complex/DuckDB/arithmetic-complex.duckdb

87 lines
2.2 KiB
Plaintext

CREATE TYPE COMPLEX AS STRUCT(r REAL, i REAL);
CREATE OR REPLACE FUNCTION isreal(a) AS (
if (try_cast(a as REAL), true, false)
);
CREATE OR REPLACE FUNCTION tocomplex(a) AS (
coalesce( try_cast(a as COMPLEX), {r: a, i:0.0 }::COMPLEX )
);
CREATE OR REPLACE FUNCTION complex_add_(a, b) AS (
{r: a.r + b.r, i:a.i + b.i}
);
CREATE OR REPLACE FUNCTION complex_add(a, b) AS (
complex_add_(tocomplex(a), tocomplex(b))
);
CREATE OR REPLACE FUNCTION complex_mul_(a, b) AS (
{r: a.r * b.r - a.i * b.i, i:a.r * b.i + a.i * b.r}
);
CREATE OR REPLACE FUNCTION complex_mul(a, b) AS (
complex_mul_(tocomplex(a), tocomplex(b))
);
CREATE OR REPLACE FUNCTION complex_mag(a) AS (
case when isreal(a)
then abs(a::REAL)
else sqrt( (a::COMPLEX).r ^ 2 + (a::COMPLEX).i ^2)
end
);
CREATE OR REPLACE FUNCTION complex_conj(a) AS (
case when isreal(a)
then {r: a::REAL, i: 0.0}
else {r: (a::COMPLEX).r, i: - (a::COMPLEX).i}
end
);
CREATE OR REPLACE FUNCTION complex_mag_squared(x) AS (
case when isreal(x)
then x::REAL*x::REAL
else (x::COMPLEX).r ^ 2 + (x::COMPLEX).i ^ 2
end
);
# Oddly, the a.r notation cannot currently be used here
CREATE OR REPLACE FUNCTION complex_div_(a, b) AS (
WITH denom AS (select complex_mag_squared(b) as denom,
a['r'] as ar, a['i'] as ai, b['r'] as br, b['i'] as bi
)
SELECT {r: (ar * br + ai * bi) / denom,
i: (ai * br - ar * bi) / denom }
FROM denom
);
CREATE OR REPLACE FUNCTION complex_div(a, b) AS (
complex_div_(tocomplex(a), tocomplex(b))
);
CREATE OR REPLACE FUNCTION complex_exp_(z) AS (
complex_mul_( {r: exp(z.r), i: 0.0}, {r: cos(z.i), i:sin(z.i) })
);
CREATE OR REPLACE FUNCTION complex_exp(z) AS (
if( isreal(z),
{r:exp(z::REAL), i:0.0},
complex_exp_( tocomplex(z) ) )
);
## Examples
.mode line
CREATE OR REPLACE FUNCTION test(x,y) as table (
select x as "x",
y as "y",
complex_add(x,y) as "add",
complex_mul(x,y) as "mul",
complex_div(1, x) as "1/x",
complex_conj(x) as "conj(x)",
complex_div(x,y).complex_mul(y) as "(x/y)*y"
);
from test({r:1,i:1}, {r:0,i:1} );
select complex_exp( {r:0, i:pi()} ) as "e^iπ";