Numworks Epsilon  1.4.1
Graphing Calculator Operating System
objcomplex.c
Go to the documentation of this file.
1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2013, 2014 Damien P. George
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <assert.h>
30 
31 #include "py/parsenum.h"
32 #include "py/runtime.h"
33 
34 #if MICROPY_PY_BUILTINS_COMPLEX
35 
36 #include <math.h>
37 #include "py/formatfloat.h"
38 
39 typedef struct _mp_obj_complex_t {
40  mp_obj_base_t base;
41  mp_float_t real;
42  mp_float_t imag;
43 } mp_obj_complex_t;
44 
45 STATIC void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
46  (void)kind;
47  mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);
48 #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
49  char buf[16];
50  #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
51  const int precision = 6;
52  #else
53  const int precision = 7;
54  #endif
55 #else
56  char buf[32];
57  const int precision = 16;
58 #endif
59  if (o->real == 0) {
60  mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0');
61  mp_printf(print, "%sj", buf);
62  } else {
63  mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0');
64  mp_printf(print, "(%s", buf);
65  if (o->imag >= 0 || isnan(o->imag)) {
66  mp_print_str(print, "+");
67  }
68  mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0');
69  mp_printf(print, "%sj)", buf);
70  }
71 }
72 
73 STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
74  (void)type_in;
75  mp_arg_check_num(n_args, n_kw, 0, 2, false);
76 
77  switch (n_args) {
78  case 0:
79  return mp_obj_new_complex(0, 0);
80 
81  case 1:
82  if (MP_OBJ_IS_STR(args[0])) {
83  // a string, parse it
84  size_t l;
85  const char *s = mp_obj_str_get_data(args[0], &l);
86  return mp_parse_num_decimal(s, l, true, true, NULL);
87  } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
88  // a complex, just return it
89  return args[0];
90  } else {
91  // something else, try to cast it to a complex
92  return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
93  }
94 
95  case 2:
96  default: {
97  mp_float_t real, imag;
99  mp_obj_complex_get(args[0], &real, &imag);
100  } else {
101  real = mp_obj_get_float(args[0]);
102  imag = 0;
103  }
104  if (MP_OBJ_IS_TYPE(args[1], &mp_type_complex)) {
105  mp_float_t real2, imag2;
106  mp_obj_complex_get(args[1], &real2, &imag2);
107  real -= imag2;
108  imag += real2;
109  } else {
110  imag += mp_obj_get_float(args[1]);
111  }
112  return mp_obj_new_complex(real, imag);
113  }
114  }
115 }
116 
117 STATIC mp_obj_t complex_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
118  mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in);
119  switch (op) {
120  case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->real != 0 || o->imag != 0);
121  case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT(mp_float_hash(o->real) ^ mp_float_hash(o->imag));
122  case MP_UNARY_OP_POSITIVE: return o_in;
123  case MP_UNARY_OP_NEGATIVE: return mp_obj_new_complex(-o->real, -o->imag);
124  case MP_UNARY_OP_ABS:
125  return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(o->real*o->real + o->imag*o->imag));
126  default: return MP_OBJ_NULL; // op not supported
127  }
128 }
129 
130 STATIC mp_obj_t complex_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
131  mp_obj_complex_t *lhs = MP_OBJ_TO_PTR(lhs_in);
132  return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in);
133 }
134 
135 STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
136  if (dest[0] != MP_OBJ_NULL) {
137  // not load attribute
138  return;
139  }
140  mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in);
141  if (attr == MP_QSTR_real) {
142  dest[0] = mp_obj_new_float(self->real);
143  } else if (attr == MP_QSTR_imag) {
144  dest[0] = mp_obj_new_float(self->imag);
145  }
146 }
147 
149  { &mp_type_type },
150  .name = MP_QSTR_complex,
151  .print = complex_print,
152  .make_new = complex_make_new,
153  .unary_op = complex_unary_op,
154  .binary_op = complex_binary_op,
155  .attr = complex_attr,
156 };
157 
158 mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) {
159  mp_obj_complex_t *o = m_new_obj(mp_obj_complex_t);
160  o->base.type = &mp_type_complex;
161  o->real = real;
162  o->imag = imag;
163  return MP_OBJ_FROM_PTR(o);
164 }
165 
166 void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag) {
168  mp_obj_complex_t *self = MP_OBJ_TO_PTR(self_in);
169  *real = self->real;
170  *imag = self->imag;
171 }
172 
173 mp_obj_t mp_obj_complex_binary_op(mp_binary_op_t op, mp_float_t lhs_real, mp_float_t lhs_imag, mp_obj_t rhs_in) {
174  mp_float_t rhs_real, rhs_imag;
175  mp_obj_get_complex(rhs_in, &rhs_real, &rhs_imag); // can be any type, this function will convert to float (if possible)
176  switch (op) {
177  case MP_BINARY_OP_ADD:
179  lhs_real += rhs_real;
180  lhs_imag += rhs_imag;
181  break;
184  lhs_real -= rhs_real;
185  lhs_imag -= rhs_imag;
186  break;
189  mp_float_t real;
190  multiply:
191  real = lhs_real * rhs_real - lhs_imag * rhs_imag;
192  lhs_imag = lhs_real * rhs_imag + lhs_imag * rhs_real;
193  lhs_real = real;
194  break;
195  }
198  mp_raise_TypeError("can't do truncated division of a complex number");
199 
202  if (rhs_imag == 0) {
203  if (rhs_real == 0) {
204  mp_raise_msg(&mp_type_ZeroDivisionError, "complex division by zero");
205  }
206  lhs_real /= rhs_real;
207  lhs_imag /= rhs_real;
208  } else if (rhs_real == 0) {
209  mp_float_t real = lhs_imag / rhs_imag;
210  lhs_imag = -lhs_real / rhs_imag;
211  lhs_real = real;
212  } else {
213  mp_float_t rhs_len_sq = rhs_real*rhs_real + rhs_imag*rhs_imag;
214  rhs_real /= rhs_len_sq;
215  rhs_imag /= -rhs_len_sq;
216  goto multiply;
217  }
218  break;
219 
220  case MP_BINARY_OP_POWER:
222  // z1**z2 = exp(z2*ln(z1))
223  // = exp(z2*(ln(|z1|)+i*arg(z1)))
224  // = exp( (x2*ln1 - y2*arg1) + i*(y2*ln1 + x2*arg1) )
225  // = exp(x3 + i*y3)
226  // = exp(x3)*(cos(y3) + i*sin(y3))
227  mp_float_t abs1 = MICROPY_FLOAT_C_FUN(sqrt)(lhs_real*lhs_real + lhs_imag*lhs_imag);
228  if (abs1 == 0) {
229  if (rhs_imag == 0 && rhs_real >= 0) {
230  lhs_real = (rhs_real == 0);
231  } else {
232  mp_raise_msg(&mp_type_ZeroDivisionError, "0.0 to a complex power");
233  }
234  } else {
235  mp_float_t ln1 = MICROPY_FLOAT_C_FUN(log)(abs1);
236  mp_float_t arg1 = MICROPY_FLOAT_C_FUN(atan2)(lhs_imag, lhs_real);
237  mp_float_t x3 = rhs_real * ln1 - rhs_imag * arg1;
238  mp_float_t y3 = rhs_imag * ln1 + rhs_real * arg1;
239  mp_float_t exp_x3 = MICROPY_FLOAT_C_FUN(exp)(x3);
240  lhs_real = exp_x3 * MICROPY_FLOAT_C_FUN(cos)(y3);
241  lhs_imag = exp_x3 * MICROPY_FLOAT_C_FUN(sin)(y3);
242  }
243  break;
244  }
245 
246  case MP_BINARY_OP_EQUAL: return mp_obj_new_bool(lhs_real == rhs_real && lhs_imag == rhs_imag);
247 
248  default:
249  return MP_OBJ_NULL; // op not supported
250  }
251  return mp_obj_new_complex(lhs_real, lhs_imag);
252 }
253 
254 #endif
#define exp(x)
Definition: math.h:176
NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, const char *msg)
Definition: runtime.c:1448
#define assert(e)
Definition: assert.h:9
const mp_obj_type_t mp_type_ZeroDivisionError
#define MP_OBJ_IS_TYPE(o, t)
Definition: obj.h:254
STATIC const uint8_t attr[]
Definition: unicode.c:51
int mp_print_str(const mp_print_t *print, const char *str)
Definition: mpprint.c:53
#define MP_OBJ_FROM_PTR(p)
Definition: obj.h:233
void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw)
Definition: argcheck.c:32
mp_unary_op_t
Definition: runtime0.h:45
#define STATIC
Definition: mpconfig.h:1178
const mp_obj_type_t mp_type_complex
#define atan2(y, x)
Definition: math.h:168
mp_print_kind_t
Definition: obj.h:412
#define MP_OBJ_NEW_SMALL_INT(small_int)
Definition: obj.h:87
#define sin(x)
Definition: math.h:194
const char * mp_obj_str_get_data(mp_obj_t self_in, size_t *len)
Definition: objstr.c:2105
#define log(x)
Definition: math.h:184
#define NULL
Definition: stddef.h:4
#define MP_OBJ_NULL
Definition: obj.h:73
size_t qstr
Definition: qstr.h:48
mp_binary_op_t
Definition: runtime0.h:67
#define cos(x)
Definition: math.h:172
args
Definition: i18n.py:175
#define isnan(x)
Definition: math.h:43
const mp_obj_type_t mp_type_type
Definition: objtype.c:969
mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex)
Definition: parsenum.c:171
#define MP_OBJ_TO_PTR(o)
Definition: obj.h:228
qstr name
Definition: obj.h:478
uint64_t mp_obj_t
Definition: obj.h:39
int mp_printf(const mp_print_t *print, const char *fmt,...)
Definition: mpprint.c:380
#define MP_OBJ_IS_STR(o)
Definition: obj.h:256
NORETURN void mp_raise_TypeError(const char *msg)
Definition: runtime.c:1460
#define m_new_obj(type)
Definition: misc.h:60
#define sqrt(x)
Definition: math.h:196