this repo has no description
at trunk 230 lines 7.6 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "complex-builtins.h" 3 4#include <cmath> 5 6#include "builtins.h" 7#include "float-builtins.h" 8#include "frame.h" 9#include "int-builtins.h" 10#include "objects.h" 11#include "runtime.h" 12#include "type-builtins.h" 13 14namespace py { 15 16word complexHash(RawObject value) { 17 RawComplex value_complex = RawComplex::cast(value); 18 uword hash_real = static_cast<uword>(doubleHash(value_complex.real())); 19 uword hash_imag = static_cast<uword>(doubleHash(value_complex.imag())); 20 21 uword result = hash_real + kHashImag * hash_imag; 22 if (result == static_cast<uword>(word{-1})) { 23 result--; 24 } 25 return static_cast<word>(result); 26} 27 28static RawObject unpackNumber(Thread* thread, const Object& obj, double* real, 29 double* imag) { 30 Runtime* runtime = thread->runtime(); 31 if (runtime->isInstanceOfInt(*obj)) { 32 HandleScope scope(thread); 33 Int obj_int(&scope, intUnderlying(*obj)); 34 *imag = 0.0; 35 return convertIntToDouble(thread, obj_int, real); 36 } 37 if (runtime->isInstanceOfFloat(*obj)) { 38 *real = floatUnderlying(*obj).value(); 39 *imag = 0.0; 40 return NoneType::object(); 41 } 42 if (runtime->isInstanceOfComplex(*obj)) { 43 RawComplex obj_complex = complexUnderlying(*obj); 44 *real = obj_complex.real(); 45 *imag = obj_complex.imag(); 46 return NoneType::object(); 47 } 48 return NotImplementedType::object(); 49} 50 51void initializeComplexType(Thread* thread) { 52 HandleScope scope(thread); 53 Type type(&scope, 54 addBuiltinType(thread, ID(complex), LayoutId::kComplex, 55 /*superclass_id=*/LayoutId::kObject, kNoAttributes, 56 /*size=*/0, /*basetype=*/true)); 57 type.setBuiltinBase(LayoutId::kComplex); 58} 59 60RawObject METH(complex, __abs__)(Thread* thread, Arguments args) { 61 HandleScope scope(thread); 62 Runtime* runtime = thread->runtime(); 63 Object self_obj(&scope, args.get(0)); 64 if (!runtime->isInstanceOfComplex(*self_obj)) { 65 return thread->raiseRequiresType(self_obj, ID(complex)); 66 } 67 Complex self(&scope, complexUnderlying(*self_obj)); 68 double real = self.real(); 69 double imag = self.imag(); 70 double magnitude = std::sqrt(real * real + imag * imag); 71 return runtime->newFloat(magnitude); 72} 73 74RawObject METH(complex, __add__)(Thread* thread, Arguments args) { 75 HandleScope scope(thread); 76 Runtime* runtime = thread->runtime(); 77 Object self_obj(&scope, args.get(0)); 78 if (!runtime->isInstanceOfComplex(*self_obj)) { 79 return thread->raiseRequiresType(self_obj, ID(complex)); 80 } 81 Complex self(&scope, complexUnderlying(*self_obj)); 82 double other_real, other_imag; 83 Object other(&scope, args.get(1)); 84 other = unpackNumber(thread, other, &other_real, &other_imag); 85 if (!other.isNoneType()) { 86 return *other; 87 } 88 return runtime->newComplex(self.real() + other_real, 89 self.imag() + other_imag); 90} 91 92RawObject METH(complex, __hash__)(Thread* thread, Arguments args) { 93 HandleScope scope(thread); 94 95 Object self_obj(&scope, args.get(0)); 96 if (!thread->runtime()->isInstanceOfComplex(*self_obj)) { 97 return thread->raiseRequiresType(self_obj, ID(complex)); 98 } 99 Complex self(&scope, complexUnderlying(*self_obj)); 100 return SmallInt::fromWord(complexHash(*self)); 101} 102 103RawObject METH(complex, __mul__)(Thread* thread, Arguments args) { 104 HandleScope scope(thread); 105 Runtime* runtime = thread->runtime(); 106 Object self_obj(&scope, args.get(0)); 107 if (!runtime->isInstanceOfComplex(*self_obj)) { 108 return thread->raiseRequiresType(self_obj, ID(complex)); 109 } 110 Complex self(&scope, complexUnderlying(*self_obj)); 111 double other_real, other_imag; 112 Object other(&scope, args.get(1)); 113 other = unpackNumber(thread, other, &other_real, &other_imag); 114 if (!other.isNoneType()) { 115 return *other; 116 } 117 118 double self_real = self.real(); 119 double self_imag = self.imag(); 120 double res_real = self_real * other_real - self_imag * other_imag; 121 double res_imag = self_real * other_imag + self_imag * other_real; 122 return runtime->newComplex(res_real, res_imag); 123} 124 125RawObject METH(complex, __neg__)(Thread* thread, Arguments args) { 126 Runtime* runtime = thread->runtime(); 127 HandleScope scope(thread); 128 129 Object self_obj(&scope, args.get(0)); 130 if (!runtime->isInstanceOfComplex(*self_obj)) { 131 return thread->raiseRequiresType(self_obj, ID(complex)); 132 } 133 Complex self(&scope, complexUnderlying(*self_obj)); 134 return runtime->newComplex(-self.real(), -self.imag()); 135} 136 137RawObject METH(complex, __pos__)(Thread* thread, Arguments args) { 138 HandleScope scope(thread); 139 140 Object self_obj(&scope, args.get(0)); 141 if (!thread->runtime()->isInstanceOfComplex(*self_obj)) { 142 return thread->raiseRequiresType(self_obj, ID(complex)); 143 } 144 return complexUnderlying(*self_obj); 145} 146 147RawObject METH(complex, __rsub__)(Thread* thread, Arguments args) { 148 HandleScope scope(thread); 149 Runtime* runtime = thread->runtime(); 150 Object self_obj(&scope, args.get(0)); 151 if (!runtime->isInstanceOfComplex(*self_obj)) { 152 return thread->raiseRequiresType(self_obj, ID(complex)); 153 } 154 Complex self(&scope, complexUnderlying(*self_obj)); 155 double other_real, other_imag; 156 Object other(&scope, args.get(1)); 157 other = unpackNumber(thread, other, &other_real, &other_imag); 158 if (!other.isNoneType()) { 159 return *other; 160 } 161 return runtime->newComplex(other_real - self.real(), 162 other_imag - self.imag()); 163} 164 165RawObject METH(complex, __sub__)(Thread* thread, Arguments args) { 166 HandleScope scope(thread); 167 Runtime* runtime = thread->runtime(); 168 Object self_obj(&scope, args.get(0)); 169 if (!runtime->isInstanceOfComplex(*self_obj)) { 170 return thread->raiseRequiresType(self_obj, ID(complex)); 171 } 172 Complex self(&scope, complexUnderlying(*self_obj)); 173 double other_real, other_imag; 174 Object other(&scope, args.get(1)); 175 other = unpackNumber(thread, other, &other_real, &other_imag); 176 if (!other.isNoneType()) { 177 return *other; 178 } 179 return runtime->newComplex(self.real() - other_real, 180 self.imag() - other_imag); 181} 182 183RawObject METH(complex, __truediv__)(Thread* thread, Arguments args) { 184 HandleScope scope(thread); 185 Runtime* runtime = thread->runtime(); 186 Object self_obj(&scope, args.get(0)); 187 if (!runtime->isInstanceOfComplex(*self_obj)) { 188 return thread->raiseRequiresType(self_obj, ID(complex)); 189 } 190 Complex self(&scope, complexUnderlying(*self_obj)); 191 double other_real, other_imag; 192 Object other(&scope, args.get(1)); 193 other = unpackNumber(thread, other, &other_real, &other_imag); 194 if (!other.isNoneType()) { 195 return *other; 196 } 197 198 double self_real = self.real(); 199 double self_imag = self.imag(); 200 double abs_other_real = std::abs(other_real); 201 double abs_other_imag = std::abs(other_imag); 202 203 double res_real, res_imag; 204 if (abs_other_real >= abs_other_imag) { 205 if (abs_other_real == 0.0) { 206 return thread->raiseWithFmt(LayoutId::kZeroDivisionError, 207 "complex division by zero"); 208 } 209 double ratio = other_imag / other_real; 210 double denom = other_real + other_imag * ratio; 211 212 res_real = (self_real + self_imag * ratio) / denom; 213 res_imag = (self_imag - self_real * ratio) / denom; 214 215 } else if (abs_other_real < abs_other_imag) { 216 double ratio = other_real / other_imag; 217 double denom = other_real * ratio + other_imag; 218 219 res_real = (self_real * ratio + self_imag) / denom; 220 res_imag = (self_imag * ratio - self_real) / denom; 221 222 } else { 223 res_real = kDoubleNaN; 224 res_imag = kDoubleNaN; 225 } 226 227 return runtime->newComplex(res_real, res_imag); 228} 229 230} // namespace py