PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/objspace/std/complexobject.py

https://bitbucket.org/pypy/pypy/
Python | 638 lines | 555 code | 48 blank | 35 comment | 98 complexity | 4b5786e86d55c0ea30f2d499730a15bb MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import math
  2. from rpython.rlib import jit, rcomplex
  3. from rpython.rlib.rarithmetic import intmask, r_ulonglong
  4. from rpython.rlib.rbigint import rbigint
  5. from rpython.rlib.rfloat import (
  6. DTSF_STR_PRECISION, copysign, formatd, isinf, isnan, string_to_float)
  7. from rpython.rlib.rstring import ParseStringError
  8. from pypy.interpreter.baseobjspace import W_Root
  9. from pypy.interpreter.error import OperationError, oefmt
  10. from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
  11. from pypy.interpreter.typedef import GetSetProperty, TypeDef
  12. from pypy.objspace.std import newformat
  13. from pypy.objspace.std.floatobject import _hash_float
  14. def _split_complex(s):
  15. slen = len(s)
  16. if slen == 0:
  17. raise ValueError
  18. realstart = 0
  19. realstop = 0
  20. imagstart = 0
  21. imagstop = 0
  22. imagsign = ' '
  23. i = 0
  24. # ignore whitespace at beginning and end
  25. while i < slen and s[i] == ' ':
  26. i += 1
  27. while slen > 0 and s[slen-1] == ' ':
  28. slen -= 1
  29. if s[i] == '(' and s[slen-1] == ')':
  30. i += 1
  31. slen -= 1
  32. # ignore whitespace after bracket
  33. while i < slen and s[i] == ' ':
  34. i += 1
  35. while slen > 0 and s[slen-1] == ' ':
  36. slen -= 1
  37. # extract first number
  38. realstart = i
  39. pc = s[i]
  40. while i < slen and s[i] != ' ':
  41. if s[i] in ('+', '-') and pc not in ('e', 'E') and i != realstart:
  42. break
  43. pc = s[i]
  44. i += 1
  45. realstop = i
  46. # return appropriate strings is only one number is there
  47. if i >= slen:
  48. newstop = realstop - 1
  49. if newstop < 0:
  50. raise ValueError
  51. if s[newstop] in ('j', 'J'):
  52. if realstart == newstop:
  53. imagpart = '1.0'
  54. elif realstart == newstop-1 and s[realstart] == '+':
  55. imagpart = '1.0'
  56. elif realstart == newstop-1 and s[realstart] == '-':
  57. imagpart = '-1.0'
  58. else:
  59. imagpart = s[realstart:newstop]
  60. return '0.0', imagpart
  61. else:
  62. return s[realstart:realstop], '0.0'
  63. # find sign for imaginary part
  64. if s[i] == '-' or s[i] == '+':
  65. imagsign = s[i]
  66. else:
  67. raise ValueError
  68. i += 1
  69. if i >= slen:
  70. raise ValueError
  71. imagstart = i
  72. pc = s[i]
  73. while i < slen and s[i] != ' ':
  74. if s[i] in ('+', '-') and pc not in ('e', 'E'):
  75. break
  76. pc = s[i]
  77. i += 1
  78. imagstop = i - 1
  79. if imagstop < 0:
  80. raise ValueError
  81. if s[imagstop] not in ('j', 'J'):
  82. raise ValueError
  83. if imagstop < imagstart:
  84. raise ValueError
  85. if i < slen:
  86. raise ValueError
  87. realpart = s[realstart:realstop]
  88. if imagstart == imagstop:
  89. imagpart = '1.0'
  90. else:
  91. imagpart = s[imagstart:imagstop]
  92. if imagsign == '-':
  93. imagpart = imagsign + imagpart
  94. return realpart, imagpart
  95. def format_float(x, code, precision):
  96. # like float2string, except that the ".0" is not necessary
  97. if isinf(x):
  98. if x > 0.0:
  99. return "inf"
  100. else:
  101. return "-inf"
  102. elif isnan(x):
  103. return "nan"
  104. else:
  105. return formatd(x, code, precision)
  106. def repr_format(x):
  107. return format_float(x, 'r', 0)
  108. def str_format(x):
  109. return format_float(x, 'g', DTSF_STR_PRECISION)
  110. def unpackcomplex(space, w_complex, strict_typing=True):
  111. """
  112. convert w_complex into a complex and return the unwrapped (real, imag)
  113. tuple. If strict_typing==True, we also typecheck the value returned by
  114. __complex__ to actually be a complex (and not e.g. a float).
  115. See test___complex___returning_non_complex.
  116. """
  117. if type(w_complex) is W_ComplexObject:
  118. return (w_complex.realval, w_complex.imagval)
  119. #
  120. # test for a '__complex__' method, and call it if found.
  121. # special case old-style instances, like CPython does.
  122. w_z = None
  123. if space.is_oldstyle_instance(w_complex):
  124. try:
  125. w_method = space.getattr(w_complex, space.wrap('__complex__'))
  126. except OperationError as e:
  127. if not e.match(space, space.w_AttributeError):
  128. raise
  129. else:
  130. w_z = space.call_function(w_method)
  131. else:
  132. w_method = space.lookup(w_complex, '__complex__')
  133. if w_method is not None:
  134. w_z = space.get_and_call_function(w_method, w_complex)
  135. #
  136. if w_z is not None:
  137. # __complex__() must return a complex or (float,int,long) object
  138. # (XXX should not use isinstance here)
  139. if not strict_typing and (space.isinstance_w(w_z, space.w_int) or
  140. space.isinstance_w(w_z, space.w_long) or
  141. space.isinstance_w(w_z, space.w_float)):
  142. return (space.float_w(w_z), 0.0)
  143. elif isinstance(w_z, W_ComplexObject):
  144. return (w_z.realval, w_z.imagval)
  145. raise oefmt(space.w_TypeError,
  146. "__complex__() must return a complex number")
  147. #
  148. # no '__complex__' method, so we assume it is a float,
  149. # unless it is an instance of some subclass of complex.
  150. if space.isinstance_w(w_complex, space.gettypefor(W_ComplexObject)):
  151. real = space.float(space.getattr(w_complex, space.wrap("real")))
  152. imag = space.float(space.getattr(w_complex, space.wrap("imag")))
  153. return (space.float_w(real), space.float_w(imag))
  154. #
  155. # Check that it is not a string (on which space.float() would succeed).
  156. if (space.isinstance_w(w_complex, space.w_str) or
  157. space.isinstance_w(w_complex, space.w_unicode)):
  158. raise oefmt(space.w_TypeError,
  159. "complex number expected, got '%T'", w_complex)
  160. #
  161. return (space.float_w(space.float(w_complex)), 0.0)
  162. class W_ComplexObject(W_Root):
  163. _immutable_fields_ = ['realval', 'imagval']
  164. def __init__(self, realval=0.0, imgval=0.0):
  165. self.realval = float(realval)
  166. self.imagval = float(imgval)
  167. def unwrap(self, space): # for tests only
  168. return complex(self.realval, self.imagval)
  169. def __repr__(self):
  170. """ representation for debugging purposes """
  171. return "<W_ComplexObject(%f, %f)>" % (self.realval, self.imagval)
  172. def as_tuple(self):
  173. return (self.realval, self.imagval)
  174. def sub(self, other):
  175. return W_ComplexObject(self.realval - other.realval,
  176. self.imagval - other.imagval)
  177. def mul(self, other):
  178. r = self.realval * other.realval - self.imagval * other.imagval
  179. i = self.realval * other.imagval + self.imagval * other.realval
  180. return W_ComplexObject(r, i)
  181. def div(self, other):
  182. rr, ir = rcomplex.c_div(self.as_tuple(), other.as_tuple())
  183. return W_ComplexObject(rr, ir)
  184. def divmod(self, space, other):
  185. space.warn(space.wrap("complex divmod(), // and % are deprecated"),
  186. space.w_DeprecationWarning)
  187. w_div = self.div(other)
  188. div = math.floor(w_div.realval)
  189. w_mod = self.sub(
  190. W_ComplexObject(other.realval * div, other.imagval * div))
  191. return (W_ComplexObject(div, 0), w_mod)
  192. def pow(self, other):
  193. rr, ir = rcomplex.c_pow(self.as_tuple(), other.as_tuple())
  194. return W_ComplexObject(rr, ir)
  195. def pow_small_int(self, n):
  196. if n >= 0:
  197. if jit.isconstant(n) and n == 2:
  198. return self.mul(self)
  199. return self.pow_positive_int(n)
  200. else:
  201. return w_one.div(self.pow_positive_int(-n))
  202. def pow_positive_int(self, n):
  203. mask = 1
  204. w_result = w_one
  205. while mask > 0 and n >= mask:
  206. if n & mask:
  207. w_result = w_result.mul(self)
  208. mask <<= 1
  209. self = self.mul(self)
  210. return w_result
  211. def is_w(self, space, w_other):
  212. from rpython.rlib.longlong2float import float2longlong
  213. if not isinstance(w_other, W_ComplexObject):
  214. return False
  215. if self.user_overridden_class or w_other.user_overridden_class:
  216. return self is w_other
  217. real1 = space.float_w(space.getattr(self, space.wrap("real")))
  218. real2 = space.float_w(space.getattr(w_other, space.wrap("real")))
  219. imag1 = space.float_w(space.getattr(self, space.wrap("imag")))
  220. imag2 = space.float_w(space.getattr(w_other, space.wrap("imag")))
  221. real1 = float2longlong(real1)
  222. real2 = float2longlong(real2)
  223. imag1 = float2longlong(imag1)
  224. imag2 = float2longlong(imag2)
  225. return real1 == real2 and imag1 == imag2
  226. def immutable_unique_id(self, space):
  227. if self.user_overridden_class:
  228. return None
  229. from rpython.rlib.longlong2float import float2longlong
  230. from pypy.objspace.std.util import IDTAG_COMPLEX as tag
  231. from pypy.objspace.std.util import IDTAG_SHIFT
  232. real = space.float_w(space.getattr(self, space.wrap("real")))
  233. imag = space.float_w(space.getattr(self, space.wrap("imag")))
  234. real_b = rbigint.fromrarith_int(float2longlong(real))
  235. imag_b = rbigint.fromrarith_int(r_ulonglong(float2longlong(imag)))
  236. val = real_b.lshift(64).or_(imag_b).lshift(IDTAG_SHIFT).int_or_(tag)
  237. return space.newlong_from_rbigint(val)
  238. def int(self, space):
  239. raise oefmt(space.w_TypeError, "can't convert complex to int")
  240. def _to_complex(self, space, w_obj):
  241. if isinstance(w_obj, W_ComplexObject):
  242. return w_obj
  243. if space.isinstance_w(w_obj, space.w_int):
  244. return W_ComplexObject(float(space.int_w(w_obj)), 0.0)
  245. if space.isinstance_w(w_obj, space.w_long):
  246. return W_ComplexObject(space.float_w(w_obj), 0.0)
  247. if space.isinstance_w(w_obj, space.w_float):
  248. return W_ComplexObject(space.float_w(w_obj), 0.0)
  249. @staticmethod
  250. @unwrap_spec(w_real=WrappedDefault(0.0))
  251. def descr__new__(space, w_complextype, w_real, w_imag=None):
  252. # if w_real is already a complex number and there is no second
  253. # argument, return it. Note that we cannot return w_real if
  254. # it is an instance of a *subclass* of complex, or if w_complextype
  255. # is itself a subclass of complex.
  256. noarg2 = w_imag is None
  257. if (noarg2 and space.is_w(w_complextype, space.w_complex)
  258. and space.is_w(space.type(w_real), space.w_complex)):
  259. return w_real
  260. if space.isinstance_w(w_real, space.w_str) or \
  261. space.isinstance_w(w_real, space.w_unicode):
  262. # a string argument
  263. if not noarg2:
  264. raise oefmt(space.w_TypeError, "complex() can't take second"
  265. " arg if first is a string")
  266. try:
  267. realstr, imagstr = _split_complex(space.str_w(w_real))
  268. except ValueError:
  269. raise oefmt(space.w_ValueError,
  270. "complex() arg is a malformed string")
  271. try:
  272. realval = string_to_float(realstr)
  273. imagval = string_to_float(imagstr)
  274. except ParseStringError:
  275. raise oefmt(space.w_ValueError,
  276. "complex() arg is a malformed string")
  277. else:
  278. # non-string arguments
  279. realval, imagval = unpackcomplex(space, w_real,
  280. strict_typing=False)
  281. # now take w_imag into account
  282. if not noarg2:
  283. # complex(x, y) == x+y*j, even if 'y' is already a complex.
  284. realval2, imagval2 = unpackcomplex(space, w_imag,
  285. strict_typing=False)
  286. # try to preserve the signs of zeroes of realval and realval2
  287. if imagval2 != 0.0:
  288. realval -= imagval2
  289. if imagval != 0.0:
  290. imagval += realval2
  291. else:
  292. imagval = realval2
  293. # done
  294. w_obj = space.allocate_instance(W_ComplexObject, w_complextype)
  295. W_ComplexObject.__init__(w_obj, realval, imagval)
  296. return w_obj
  297. def descr___getnewargs__(self, space):
  298. return space.newtuple([space.newfloat(self.realval),
  299. space.newfloat(self.imagval)])
  300. def descr_repr(self, space):
  301. if self.realval == 0 and copysign(1., self.realval) == 1.:
  302. return space.wrap(repr_format(self.imagval) + 'j')
  303. sign = (copysign(1., self.imagval) == 1. or
  304. isnan(self.imagval)) and '+' or ''
  305. return space.wrap('(' + repr_format(self.realval)
  306. + sign + repr_format(self.imagval) + 'j)')
  307. def descr_str(self, space):
  308. if self.realval == 0 and copysign(1., self.realval) == 1.:
  309. return space.wrap(str_format(self.imagval) + 'j')
  310. sign = (copysign(1., self.imagval) == 1. or
  311. isnan(self.imagval)) and '+' or ''
  312. return space.wrap('(' + str_format(self.realval)
  313. + sign + str_format(self.imagval) + 'j)')
  314. def descr_hash(self, space):
  315. hashreal = _hash_float(space, self.realval)
  316. hashimg = _hash_float(space, self.imagval)
  317. combined = intmask(hashreal + 1000003 * hashimg)
  318. return space.newint(combined)
  319. def descr_coerce(self, space, w_other):
  320. w_other = self._to_complex(space, w_other)
  321. if w_other is None:
  322. return space.w_NotImplemented
  323. return space.newtuple([self, w_other])
  324. def descr_format(self, space, w_format_spec):
  325. return newformat.run_formatter(space, w_format_spec, "format_complex",
  326. self)
  327. def descr_nonzero(self, space):
  328. return space.newbool((self.realval != 0.0) or (self.imagval != 0.0))
  329. def descr_float(self, space):
  330. raise oefmt(space.w_TypeError, "can't convert complex to float")
  331. def descr_neg(self, space):
  332. return W_ComplexObject(-self.realval, -self.imagval)
  333. def descr_pos(self, space):
  334. return W_ComplexObject(self.realval, self.imagval)
  335. def descr_abs(self, space):
  336. try:
  337. return space.newfloat(math.hypot(self.realval, self.imagval))
  338. except OverflowError as e:
  339. raise OperationError(space.w_OverflowError, space.wrap(str(e)))
  340. def descr_eq(self, space, w_other):
  341. if isinstance(w_other, W_ComplexObject):
  342. return space.newbool((self.realval == w_other.realval) and
  343. (self.imagval == w_other.imagval))
  344. if (space.isinstance_w(w_other, space.w_int) or
  345. space.isinstance_w(w_other, space.w_long) or
  346. space.isinstance_w(w_other, space.w_float)):
  347. if self.imagval:
  348. return space.w_False
  349. return space.eq(space.newfloat(self.realval), w_other)
  350. return space.w_NotImplemented
  351. def descr_ne(self, space, w_other):
  352. if isinstance(w_other, W_ComplexObject):
  353. return space.newbool((self.realval != w_other.realval) or
  354. (self.imagval != w_other.imagval))
  355. if (space.isinstance_w(w_other, space.w_int) or
  356. space.isinstance_w(w_other, space.w_long) or
  357. space.isinstance_w(w_other, space.w_float)):
  358. if self.imagval:
  359. return space.w_True
  360. return space.ne(space.newfloat(self.realval), w_other)
  361. return space.w_NotImplemented
  362. def _fail_cmp(self, space, w_other):
  363. if (isinstance(w_other, W_ComplexObject) or
  364. space.isinstance_w(w_other, space.w_int) or
  365. space.isinstance_w(w_other, space.w_long) or
  366. space.isinstance_w(w_other, space.w_float)):
  367. raise oefmt(space.w_TypeError,
  368. "no ordering relation is defined for complex numbers")
  369. return space.w_NotImplemented
  370. def descr_add(self, space, w_rhs):
  371. w_rhs = self._to_complex(space, w_rhs)
  372. if w_rhs is None:
  373. return space.w_NotImplemented
  374. return W_ComplexObject(self.realval + w_rhs.realval,
  375. self.imagval + w_rhs.imagval)
  376. def descr_radd(self, space, w_lhs):
  377. w_lhs = self._to_complex(space, w_lhs)
  378. if w_lhs is None:
  379. return space.w_NotImplemented
  380. return W_ComplexObject(w_lhs.realval + self.realval,
  381. w_lhs.imagval + self.imagval)
  382. def descr_sub(self, space, w_rhs):
  383. w_rhs = self._to_complex(space, w_rhs)
  384. if w_rhs is None:
  385. return space.w_NotImplemented
  386. return W_ComplexObject(self.realval - w_rhs.realval,
  387. self.imagval - w_rhs.imagval)
  388. def descr_rsub(self, space, w_lhs):
  389. w_lhs = self._to_complex(space, w_lhs)
  390. if w_lhs is None:
  391. return space.w_NotImplemented
  392. return W_ComplexObject(w_lhs.realval - self.realval,
  393. w_lhs.imagval - self.imagval)
  394. def descr_mul(self, space, w_rhs):
  395. w_rhs = self._to_complex(space, w_rhs)
  396. if w_rhs is None:
  397. return space.w_NotImplemented
  398. return self.mul(w_rhs)
  399. def descr_rmul(self, space, w_lhs):
  400. w_lhs = self._to_complex(space, w_lhs)
  401. if w_lhs is None:
  402. return space.w_NotImplemented
  403. return w_lhs.mul(self)
  404. def descr_truediv(self, space, w_rhs):
  405. w_rhs = self._to_complex(space, w_rhs)
  406. if w_rhs is None:
  407. return space.w_NotImplemented
  408. try:
  409. return self.div(w_rhs)
  410. except ZeroDivisionError as e:
  411. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  412. def descr_rtruediv(self, space, w_lhs):
  413. w_lhs = self._to_complex(space, w_lhs)
  414. if w_lhs is None:
  415. return space.w_NotImplemented
  416. try:
  417. return w_lhs.div(self)
  418. except ZeroDivisionError as e:
  419. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  420. def descr_floordiv(self, space, w_rhs):
  421. w_rhs = self._to_complex(space, w_rhs)
  422. if w_rhs is None:
  423. return space.w_NotImplemented
  424. # don't care about the slight slowdown you get from using divmod
  425. try:
  426. return self.divmod(space, w_rhs)[0]
  427. except ZeroDivisionError as e:
  428. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  429. def descr_rfloordiv(self, space, w_lhs):
  430. w_lhs = self._to_complex(space, w_lhs)
  431. if w_lhs is None:
  432. return space.w_NotImplemented
  433. # don't care about the slight slowdown you get from using divmod
  434. try:
  435. return w_lhs.divmod(space, self)[0]
  436. except ZeroDivisionError as e:
  437. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  438. def descr_mod(self, space, w_rhs):
  439. w_rhs = self._to_complex(space, w_rhs)
  440. if w_rhs is None:
  441. return space.w_NotImplemented
  442. try:
  443. return self.divmod(space, w_rhs)[1]
  444. except ZeroDivisionError as e:
  445. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  446. def descr_rmod(self, space, w_lhs):
  447. w_lhs = self._to_complex(space, w_lhs)
  448. if w_lhs is None:
  449. return space.w_NotImplemented
  450. try:
  451. return w_lhs.divmod(space, self)[1]
  452. except ZeroDivisionError as e:
  453. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  454. def descr_divmod(self, space, w_rhs):
  455. w_rhs = self._to_complex(space, w_rhs)
  456. if w_rhs is None:
  457. return space.w_NotImplemented
  458. try:
  459. div, mod = self.divmod(space, w_rhs)
  460. except ZeroDivisionError as e:
  461. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  462. return space.newtuple([div, mod])
  463. def descr_rdivmod(self, space, w_lhs):
  464. w_lhs = self._to_complex(space, w_lhs)
  465. if w_lhs is None:
  466. return space.w_NotImplemented
  467. try:
  468. div, mod = w_lhs.divmod(space, self)
  469. except ZeroDivisionError as e:
  470. raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e)))
  471. return space.newtuple([div, mod])
  472. @unwrap_spec(w_third_arg=WrappedDefault(None))
  473. def descr_pow(self, space, w_exponent, w_third_arg):
  474. w_exponent = self._to_complex(space, w_exponent)
  475. if w_exponent is None:
  476. return space.w_NotImplemented
  477. if not space.is_w(w_third_arg, space.w_None):
  478. raise oefmt(space.w_ValueError, 'complex modulo')
  479. try:
  480. r = w_exponent.realval
  481. if (w_exponent.imagval == 0.0 and -100.0 <= r <= 100.0 and
  482. r == int(r)):
  483. w_p = self.pow_small_int(int(r))
  484. else:
  485. w_p = self.pow(w_exponent)
  486. except ZeroDivisionError:
  487. raise oefmt(space.w_ZeroDivisionError,
  488. "0.0 to a negative or complex power")
  489. except OverflowError:
  490. raise oefmt(space.w_OverflowError, "complex exponentiation")
  491. return w_p
  492. @unwrap_spec(w_third_arg=WrappedDefault(None))
  493. def descr_rpow(self, space, w_lhs, w_third_arg):
  494. w_lhs = self._to_complex(space, w_lhs)
  495. if w_lhs is None:
  496. return space.w_NotImplemented
  497. return w_lhs.descr_pow(space, self, w_third_arg)
  498. def descr_conjugate(self, space):
  499. """(A+Bj).conjugate() -> A-Bj"""
  500. return space.newcomplex(self.realval, -self.imagval)
  501. w_one = W_ComplexObject(1, 0)
  502. def complexwprop(name):
  503. def fget(space, w_obj):
  504. if not isinstance(w_obj, W_ComplexObject):
  505. raise oefmt(space.w_TypeError, "descriptor is for 'complex'")
  506. return space.newfloat(getattr(w_obj, name))
  507. return GetSetProperty(fget)
  508. W_ComplexObject.typedef = TypeDef("complex",
  509. __doc__ = """complex(real[, imag]) -> complex number
  510. Create a complex number from a real part and an optional imaginary part.
  511. This is equivalent to (real + imag*1j) where imag defaults to 0.""",
  512. __new__ = interp2app(W_ComplexObject.descr__new__),
  513. __getnewargs__ = interp2app(W_ComplexObject.descr___getnewargs__),
  514. real = complexwprop('realval'),
  515. imag = complexwprop('imagval'),
  516. __repr__ = interp2app(W_ComplexObject.descr_repr),
  517. __str__ = interp2app(W_ComplexObject.descr_str),
  518. __hash__ = interp2app(W_ComplexObject.descr_hash),
  519. __coerce__ = interp2app(W_ComplexObject.descr_coerce),
  520. __format__ = interp2app(W_ComplexObject.descr_format),
  521. __nonzero__ = interp2app(W_ComplexObject.descr_nonzero),
  522. __int__ = interp2app(W_ComplexObject.int),
  523. __float__ = interp2app(W_ComplexObject.descr_float),
  524. __neg__ = interp2app(W_ComplexObject.descr_neg),
  525. __pos__ = interp2app(W_ComplexObject.descr_pos),
  526. __abs__ = interp2app(W_ComplexObject.descr_abs),
  527. __eq__ = interp2app(W_ComplexObject.descr_eq),
  528. __ne__ = interp2app(W_ComplexObject.descr_ne),
  529. __lt__ = interp2app(W_ComplexObject._fail_cmp),
  530. __le__ = interp2app(W_ComplexObject._fail_cmp),
  531. __gt__ = interp2app(W_ComplexObject._fail_cmp),
  532. __ge__ = interp2app(W_ComplexObject._fail_cmp),
  533. __add__ = interp2app(W_ComplexObject.descr_add),
  534. __radd__ = interp2app(W_ComplexObject.descr_radd),
  535. __sub__ = interp2app(W_ComplexObject.descr_sub),
  536. __rsub__ = interp2app(W_ComplexObject.descr_rsub),
  537. __mul__ = interp2app(W_ComplexObject.descr_mul),
  538. __rmul__ = interp2app(W_ComplexObject.descr_rmul),
  539. __div__ = interp2app(W_ComplexObject.descr_truediv),
  540. __rdiv__ = interp2app(W_ComplexObject.descr_rtruediv),
  541. __truediv__ = interp2app(W_ComplexObject.descr_truediv),
  542. __rtruediv__ = interp2app(W_ComplexObject.descr_rtruediv),
  543. __floordiv__ = interp2app(W_ComplexObject.descr_floordiv),
  544. __rfloordiv__ = interp2app(W_ComplexObject.descr_rfloordiv),
  545. __mod__ = interp2app(W_ComplexObject.descr_mod),
  546. __rmod__ = interp2app(W_ComplexObject.descr_rmod),
  547. __divmod__ = interp2app(W_ComplexObject.descr_divmod),
  548. __rdivmod__ = interp2app(W_ComplexObject.descr_rdivmod),
  549. __pow__ = interp2app(W_ComplexObject.descr_pow),
  550. __rpow__ = interp2app(W_ComplexObject.descr_rpow),
  551. conjugate = interp2app(W_ComplexObject.descr_conjugate),
  552. )