this repo has no description
at trunk 151 lines 4.9 kB view raw
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