this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <cerrno>
3#include <cmath>
4
5#include "api-handle.h"
6#include "float-builtins.h"
7#include "runtime.h"
8#include "type-builtins.h"
9
10namespace py {
11
12PY_EXPORT double _Py_c_abs(Py_complex x) {
13 double result = std::hypot(x.real, x.imag);
14 if (std::isfinite(result)) {
15 errno = 0;
16 return result;
17 }
18 errno = 0;
19 if (std::isinf(x.real)) return std::fabs(x.real);
20 if (std::isinf(x.imag)) return std::fabs(x.imag);
21 return NAN;
22}
23
24PY_EXPORT Py_complex _Py_c_diff(Py_complex x, Py_complex y) {
25 return {x.real - y.real, x.imag - y.imag};
26}
27
28PY_EXPORT Py_complex _Py_c_neg(Py_complex x) { return {-x.real, -x.imag}; }
29
30PY_EXPORT Py_complex _Py_c_prod(Py_complex x, Py_complex y) {
31 double real = x.real * y.real - x.imag * y.imag;
32 double imag = x.real * y.imag + x.imag * y.real;
33 return {real, imag};
34}
35
36PY_EXPORT Py_complex _Py_c_quot(Py_complex x, Py_complex y) {
37 double real;
38 double imag;
39 if (y.imag == 0.0) {
40 errno = EDOM;
41 real = 0.0;
42 imag = 0.0;
43 } else if (std::fabs(y.real) >= std::fabs(y.imag)) {
44 double ratio = y.imag / y.real;
45 double den = y.real + y.imag * ratio;
46 real = (x.real + x.imag * ratio) / den;
47 imag = (x.imag - x.real * ratio) / den;
48 } else if (std::fabs(y.imag) >= std::fabs(y.real)) {
49 double ratio = y.real / y.imag;
50 double den = y.real * ratio + y.imag;
51 real = (x.real * ratio + x.imag) / den;
52 imag = (x.imag * ratio - x.real) / den;
53 } else {
54 real = NAN;
55 imag = NAN;
56 }
57 return {real, imag};
58}
59
60PY_EXPORT Py_complex _Py_c_sum(Py_complex x, Py_complex y) {
61 return {x.real + y.real, x.imag + y.imag};
62}
63
64PY_EXPORT int PyComplex_CheckExact_Func(PyObject* p) {
65 return ApiHandle::asObject(ApiHandle::fromPyObject(p)).isComplex();
66}
67
68PY_EXPORT int PyComplex_Check_Func(PyObject* p) {
69 return Thread::current()->runtime()->isInstanceOfComplex(
70 ApiHandle::asObject(ApiHandle::fromPyObject(p)));
71}
72
73PY_EXPORT Py_complex PyComplex_AsCComplex(PyObject* pycomplex) {
74 Thread* thread = Thread::current();
75 Runtime* runtime = thread->runtime();
76 HandleScope scope(thread);
77 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pycomplex)));
78 if (runtime->isInstanceOfComplex(*obj)) {
79 Complex comp(&scope, complexUnderlying(*obj));
80 return {comp.real(), comp.imag()};
81 }
82
83 // Try calling __complex__
84 Object result(&scope, thread->invokeMethod1(obj, ID(__complex__)));
85 if (!result.isError()) {
86 if (!runtime->isInstanceOfComplex(*result)) {
87 thread->raiseWithFmt(LayoutId::kTypeError,
88 "__complex__ should returns a complex object");
89 return {-1.0, 0.0};
90 }
91 Complex comp(&scope, complexUnderlying(*result));
92 return {comp.real(), comp.imag()};
93 }
94 // If __complex__ is not defined, call __float__
95 if (result.isErrorNotFound()) {
96 // Use __float__ for the real part and set the imaginary part to 0
97 if (!runtime->isInstanceOfFloat(*obj)) {
98 obj = thread->invokeFunction1(ID(builtins), ID(_float), obj);
99 if (obj.isError()) return {-1.0, 0.0};
100 }
101 return {floatUnderlying(*obj).value(), 0.0};
102 }
103 DCHECK(result.isErrorException(), "result should be an exception");
104 return {-1.0, 0.0};
105}
106
107PY_EXPORT PyObject* PyComplex_FromCComplex(Py_complex cmp) {
108 Runtime* runtime = Thread::current()->runtime();
109 return ApiHandle::newReferenceWithManaged(
110 runtime, runtime->newComplex(cmp.real, cmp.imag));
111}
112
113PY_EXPORT double PyComplex_ImagAsDouble(PyObject* pycomplex) {
114 Thread* thread = Thread::current();
115 Runtime* runtime = thread->runtime();
116 HandleScope scope(thread);
117 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pycomplex)));
118 if (!runtime->isInstanceOfComplex(*obj)) return 0.0;
119 Complex comp(&scope, complexUnderlying(*obj));
120 return comp.imag();
121}
122
123PY_EXPORT double PyComplex_RealAsDouble(PyObject* pycomplex) {
124 Thread* thread = Thread::current();
125 Runtime* runtime = thread->runtime();
126 HandleScope scope(thread);
127 Object obj(&scope, ApiHandle::asObject(ApiHandle::fromPyObject(pycomplex)));
128 if (runtime->isInstanceOfComplex(*obj)) {
129 Complex comp(&scope, complexUnderlying(*obj));
130 return comp.real();
131 }
132 if (!runtime->isInstanceOfFloat(*obj)) {
133 obj = thread->invokeFunction1(ID(builtins), ID(_float), obj);
134 if (obj.isError()) return -1;
135 }
136 return floatUnderlying(*obj).value();
137}
138
139PY_EXPORT PyTypeObject* PyComplex_Type_Ptr() {
140 Runtime* runtime = Thread::current()->runtime();
141 return reinterpret_cast<PyTypeObject*>(ApiHandle::borrowedReference(
142 runtime, runtime->typeAt(LayoutId::kComplex)));
143}
144
145PY_EXPORT PyObject* PyComplex_FromDoubles(double real, double imag) {
146 Runtime* runtime = Thread::current()->runtime();
147 return ApiHandle::newReferenceWithManaged(runtime,
148 runtime->newComplex(real, imag));
149}
150
151} // namespace py