2008-03-16 03:23:43 +03:00
|
|
|
/*
|
2012-11-18 04:26:15 +04:00
|
|
|
complex.c: Coded by Tadayoshi Funaba 2008-2012
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
This implementation is based on Keiju Ishitsuka's Complex library
|
|
|
|
which is written in ruby.
|
|
|
|
*/
|
|
|
|
|
2020-05-08 12:31:09 +03:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
|
2015-02-25 05:25:22 +03:00
|
|
|
#if defined _MSC_VER
|
|
|
|
/* Microsoft Visual C does not define M_PI and others by default */
|
|
|
|
# define _USE_MATH_DEFINES 1
|
|
|
|
#endif
|
2019-12-04 11:16:30 +03:00
|
|
|
|
|
|
|
#include <ctype.h>
|
2008-03-16 03:23:43 +03:00
|
|
|
#include <math.h>
|
|
|
|
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "id.h"
|
|
|
|
#include "internal.h"
|
2020-08-14 08:45:23 +03:00
|
|
|
#include "internal/array.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
#include "internal/class.h"
|
|
|
|
#include "internal/complex.h"
|
|
|
|
#include "internal/math.h"
|
|
|
|
#include "internal/numeric.h"
|
|
|
|
#include "internal/object.h"
|
|
|
|
#include "internal/rational.h"
|
2023-12-11 09:48:51 +03:00
|
|
|
#include "internal/string.h"
|
2016-01-22 11:33:55 +03:00
|
|
|
#include "ruby_assert.h"
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
#define ZERO INT2FIX(0)
|
|
|
|
#define ONE INT2FIX(1)
|
|
|
|
#define TWO INT2FIX(2)
|
2018-06-17 05:41:26 +03:00
|
|
|
#if USE_FLONUM
|
2015-02-25 09:48:55 +03:00
|
|
|
#define RFLOAT_0 DBL2NUM(0)
|
2018-06-17 05:41:26 +03:00
|
|
|
#else
|
|
|
|
static VALUE RFLOAT_0;
|
|
|
|
#endif
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
VALUE rb_cComplex;
|
|
|
|
|
2016-11-22 07:54:57 +03:00
|
|
|
static ID id_abs, id_arg,
|
2019-08-03 02:37:08 +03:00
|
|
|
id_denominator, id_numerator,
|
2018-02-27 11:15:27 +03:00
|
|
|
id_real_p, id_i_real, id_i_imag,
|
2016-10-28 09:20:19 +03:00
|
|
|
id_finite_p, id_infinite_p, id_rationalize,
|
|
|
|
id_PI;
|
2018-01-22 16:09:37 +03:00
|
|
|
#define id_to_i idTo_i
|
|
|
|
#define id_to_r idTo_r
|
2018-02-27 04:17:46 +03:00
|
|
|
#define id_negate idUMinus
|
|
|
|
#define id_expt idPow
|
2018-02-27 11:15:27 +03:00
|
|
|
#define id_to_f idTo_f
|
2019-08-03 02:37:08 +03:00
|
|
|
#define id_quo idQuo
|
|
|
|
#define id_fdiv idFdiv
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-20 15:26:58 +03:00
|
|
|
#define fun1(n) \
|
|
|
|
inline static VALUE \
|
|
|
|
f_##n(VALUE x)\
|
|
|
|
{\
|
2008-03-31 20:42:24 +04:00
|
|
|
return rb_funcall(x, id_##n, 0);\
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-20 15:26:58 +03:00
|
|
|
#define fun2(n) \
|
|
|
|
inline static VALUE \
|
|
|
|
f_##n(VALUE x, VALUE y)\
|
|
|
|
{\
|
2008-03-31 20:42:24 +04:00
|
|
|
return rb_funcall(x, id_##n, 1, y);\
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2008-09-14 05:16:44 +04:00
|
|
|
#define PRESERVE_SIGNEDZERO
|
|
|
|
|
2008-03-20 15:26:58 +03:00
|
|
|
inline static VALUE
|
|
|
|
f_add(VALUE x, VALUE y)
|
|
|
|
{
|
2019-01-01 15:20:05 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(x) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cInteger, idPLUS))) {
|
2019-01-02 07:25:11 +03:00
|
|
|
if (FIXNUM_ZERO_P(x))
|
|
|
|
return y;
|
|
|
|
if (FIXNUM_ZERO_P(y))
|
|
|
|
return x;
|
2019-01-02 04:36:39 +03:00
|
|
|
return rb_int_plus(x, y);
|
2019-01-01 15:20:05 +03:00
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) {
|
2019-01-02 07:25:11 +03:00
|
|
|
if (FIXNUM_ZERO_P(y))
|
|
|
|
return x;
|
2019-01-02 04:36:39 +03:00
|
|
|
return rb_float_plus(x, y);
|
2019-01-01 15:20:05 +03:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cRational, idPLUS))) {
|
2019-01-02 07:25:11 +03:00
|
|
|
if (FIXNUM_ZERO_P(y))
|
|
|
|
return x;
|
2019-01-02 04:36:39 +03:00
|
|
|
return rb_rational_plus(x, y);
|
2019-01-01 15:20:05 +03:00
|
|
|
}
|
|
|
|
|
2008-06-12 16:41:17 +04:00
|
|
|
return rb_funcall(x, '+', 1, y);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
2008-03-22 20:31:08 +03:00
|
|
|
f_div(VALUE x, VALUE y)
|
2008-03-20 15:26:58 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
if (FIXNUM_P(y) && FIX2LONG(y) == 1)
|
2008-06-12 16:41:17 +04:00
|
|
|
return x;
|
|
|
|
return rb_funcall(x, '/', 1, y);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2016-11-22 08:21:12 +03:00
|
|
|
inline static int
|
2008-03-20 15:26:58 +03:00
|
|
|
f_gt_p(VALUE x, VALUE y)
|
|
|
|
{
|
2016-11-22 08:21:12 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
|
|
|
if (FIXNUM_P(x) && FIXNUM_P(y))
|
|
|
|
return (SIGNED_VALUE)x > (SIGNED_VALUE)y;
|
|
|
|
return RTEST(rb_int_gt(x, y));
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x))
|
|
|
|
return RTEST(rb_float_gt(x, y));
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
int const cmp = rb_cmpint(rb_rational_cmp(x, y), x, y);
|
|
|
|
return cmp > 0;
|
|
|
|
}
|
|
|
|
return RTEST(rb_funcall(x, '>', 1, y));
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_mul(VALUE x, VALUE y)
|
|
|
|
{
|
2019-01-02 07:25:11 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(x) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cInteger, idMULT))) {
|
2019-01-02 07:25:11 +03:00
|
|
|
if (FIXNUM_ZERO_P(y))
|
|
|
|
return ZERO;
|
|
|
|
if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y))
|
|
|
|
return ZERO;
|
|
|
|
if (x == ONE) return y;
|
|
|
|
if (y == ONE) return x;
|
2019-01-03 09:19:17 +03:00
|
|
|
return rb_int_mul(x, y);
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cFloat, idMULT))) {
|
2019-01-03 09:19:17 +03:00
|
|
|
if (y == ONE) return x;
|
|
|
|
return rb_float_mul(x, y);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(rb_cRational, idMULT))) {
|
2019-01-03 09:19:17 +03:00
|
|
|
if (y == ONE) return x;
|
|
|
|
return rb_rational_mul(x, y);
|
2019-01-02 07:25:11 +03:00
|
|
|
}
|
2019-01-08 07:53:06 +03:00
|
|
|
else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMULT))) {
|
2019-01-02 07:25:11 +03:00
|
|
|
if (y == ONE) return x;
|
|
|
|
}
|
2008-06-12 16:41:17 +04:00
|
|
|
return rb_funcall(x, '*', 1, y);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_sub(VALUE x, VALUE y)
|
|
|
|
{
|
2019-01-02 07:25:11 +03:00
|
|
|
if (FIXNUM_ZERO_P(y) &&
|
2019-01-08 07:53:06 +03:00
|
|
|
LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMINUS))) {
|
2008-09-13 05:55:56 +04:00
|
|
|
return x;
|
2019-01-02 07:25:11 +03:00
|
|
|
}
|
2008-06-12 16:41:17 +04:00
|
|
|
return rb_funcall(x, '-', 1, y);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2019-07-14 12:01:24 +03:00
|
|
|
inline static VALUE
|
|
|
|
f_abs(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
|
|
|
return rb_int_abs(x);
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return rb_float_abs(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
return rb_rational_abs(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_COMPLEX)) {
|
|
|
|
return rb_complex_abs(x);
|
|
|
|
}
|
|
|
|
return rb_funcall(x, id_abs, 0);
|
|
|
|
}
|
|
|
|
|
2019-07-14 12:02:02 +03:00
|
|
|
static VALUE numeric_arg(VALUE self);
|
|
|
|
static VALUE float_arg(VALUE self);
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_arg(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
|
|
|
return numeric_arg(x);
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return float_arg(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
return numeric_arg(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_COMPLEX)) {
|
|
|
|
return rb_complex_arg(x);
|
|
|
|
}
|
|
|
|
return rb_funcall(x, id_arg, 0);
|
|
|
|
}
|
|
|
|
|
2019-07-16 02:15:05 +03:00
|
|
|
inline static VALUE
|
|
|
|
f_numerator(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
return RRATIONAL(x)->num;
|
|
|
|
}
|
|
|
|
if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return rb_float_numerator(x);
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2019-07-16 01:58:47 +03:00
|
|
|
inline static VALUE
|
|
|
|
f_denominator(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
return RRATIONAL(x)->den;
|
|
|
|
}
|
|
|
|
if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return rb_float_denominator(x);
|
|
|
|
}
|
|
|
|
return INT2FIX(1);
|
|
|
|
}
|
2016-11-18 18:17:19 +03:00
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_negate(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
|
|
|
return rb_int_uminus(x);
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return rb_float_uminus(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
|
|
|
return rb_rational_uminus(x);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_COMPLEX)) {
|
2018-12-12 14:06:48 +03:00
|
|
|
return rb_complex_uminus(x);
|
2016-11-18 18:17:19 +03:00
|
|
|
}
|
|
|
|
return rb_funcall(x, id_negate, 0);
|
|
|
|
}
|
|
|
|
|
2019-11-25 09:05:53 +03:00
|
|
|
static bool nucomp_real_p(VALUE self);
|
2019-08-10 07:56:18 +03:00
|
|
|
|
|
|
|
static inline bool
|
|
|
|
f_real_p(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_INTEGER_TYPE_P(x)) {
|
2019-11-25 09:05:53 +03:00
|
|
|
return true;
|
2019-08-10 07:56:18 +03:00
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
2019-11-25 09:05:53 +03:00
|
|
|
return true;
|
2019-08-10 07:56:18 +03:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
2019-11-25 09:05:53 +03:00
|
|
|
return true;
|
2019-08-10 07:56:18 +03:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_COMPLEX)) {
|
|
|
|
return nucomp_real_p(x);
|
|
|
|
}
|
|
|
|
return rb_funcall(x, id_real_p, 0);
|
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
|
2011-04-24 17:24:02 +04:00
|
|
|
inline static VALUE
|
|
|
|
f_to_i(VALUE x)
|
|
|
|
{
|
2011-09-29 15:07:45 +04:00
|
|
|
if (RB_TYPE_P(x, T_STRING))
|
2011-04-24 17:24:02 +04:00
|
|
|
return rb_str_to_inum(x, 10, 0);
|
|
|
|
return rb_funcall(x, id_to_i, 0);
|
|
|
|
}
|
2019-08-10 07:56:18 +03:00
|
|
|
|
2011-04-24 17:24:02 +04:00
|
|
|
inline static VALUE
|
|
|
|
f_to_f(VALUE x)
|
|
|
|
{
|
2011-09-29 15:07:45 +04:00
|
|
|
if (RB_TYPE_P(x, T_STRING))
|
2011-04-24 17:24:02 +04:00
|
|
|
return DBL2NUM(rb_str_to_dbl(x, 0));
|
|
|
|
return rb_funcall(x, id_to_f, 0);
|
|
|
|
}
|
|
|
|
|
2008-03-20 15:26:58 +03:00
|
|
|
fun1(to_r)
|
|
|
|
|
2016-11-15 09:28:05 +03:00
|
|
|
inline static int
|
2009-07-03 16:19:54 +04:00
|
|
|
f_eqeq_p(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x) && FIXNUM_P(y))
|
2016-11-15 09:28:05 +03:00
|
|
|
return x == y;
|
|
|
|
else if (RB_FLOAT_TYPE_P(x) || RB_FLOAT_TYPE_P(y))
|
|
|
|
return NUM2DBL(x) == NUM2DBL(y);
|
|
|
|
return (int)rb_equal(x, y);
|
2009-07-03 16:19:54 +04:00
|
|
|
}
|
|
|
|
|
2008-03-20 15:26:58 +03:00
|
|
|
fun2(expt)
|
2009-06-14 02:57:02 +04:00
|
|
|
fun2(fdiv)
|
2019-08-10 08:30:34 +03:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
f_quo(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
if (RB_INTEGER_TYPE_P(x))
|
|
|
|
return rb_numeric_quo(x, y);
|
|
|
|
if (RB_FLOAT_TYPE_P(x))
|
|
|
|
return rb_float_div(x, y);
|
|
|
|
if (RB_TYPE_P(x, T_RATIONAL))
|
|
|
|
return rb_numeric_quo(x, y);
|
|
|
|
|
|
|
|
return rb_funcallv(x, id_quo, 1, &y);
|
|
|
|
}
|
2008-03-20 15:26:58 +03:00
|
|
|
|
2016-11-14 07:06:15 +03:00
|
|
|
inline static int
|
2008-03-20 15:26:58 +03:00
|
|
|
f_negative_p(VALUE x)
|
|
|
|
{
|
2016-11-16 07:25:35 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(x))
|
|
|
|
return INT_NEGATIVE_P(x);
|
|
|
|
else if (RB_FLOAT_TYPE_P(x))
|
|
|
|
return RFLOAT_VALUE(x) < 0.0;
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL))
|
|
|
|
return INT_NEGATIVE_P(RRATIONAL(x)->num);
|
2016-11-14 07:06:15 +03:00
|
|
|
return rb_num_negative_p(x);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2008-09-21 16:21:32 +04:00
|
|
|
#define f_positive_p(x) (!f_negative_p(x))
|
|
|
|
|
2022-08-31 04:59:05 +03:00
|
|
|
inline static bool
|
2008-03-20 15:26:58 +03:00
|
|
|
f_zero_p(VALUE x)
|
|
|
|
{
|
2019-01-09 10:05:37 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
return FLOAT_ZERO_P(x);
|
|
|
|
}
|
|
|
|
else if (RB_INTEGER_TYPE_P(x)) {
|
2016-11-13 19:43:43 +03:00
|
|
|
return FIXNUM_ZERO_P(x);
|
2013-09-09 09:17:13 +04:00
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(x, T_RATIONAL)) {
|
2016-11-13 19:43:43 +03:00
|
|
|
const VALUE num = RRATIONAL(x)->num;
|
|
|
|
return FIXNUM_ZERO_P(num);
|
2009-07-12 18:57:42 +04:00
|
|
|
}
|
2022-08-31 04:59:05 +03:00
|
|
|
return rb_equal(x, ZERO) != 0;
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2008-09-21 16:21:32 +04:00
|
|
|
#define f_nonzero_p(x) (!f_zero_p(x))
|
|
|
|
|
2021-09-02 15:42:47 +03:00
|
|
|
static inline bool
|
|
|
|
always_finite_type_p(VALUE x)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(x)) return true;
|
|
|
|
if (FLONUM_P(x)) return true; /* Infinity can't be a flonum */
|
|
|
|
return (RB_INTEGER_TYPE_P(x) || RB_TYPE_P(x, T_RATIONAL));
|
|
|
|
}
|
|
|
|
|
2017-09-27 05:38:51 +03:00
|
|
|
inline static int
|
|
|
|
f_finite_p(VALUE x)
|
|
|
|
{
|
2021-09-02 15:42:47 +03:00
|
|
|
if (always_finite_type_p(x)) {
|
2017-09-27 05:38:51 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
2021-09-02 15:42:47 +03:00
|
|
|
return isfinite(RFLOAT_VALUE(x));
|
2017-09-27 05:38:51 +03:00
|
|
|
}
|
|
|
|
return RTEST(rb_funcallv(x, id_finite_p, 0, 0));
|
|
|
|
}
|
|
|
|
|
2021-09-02 11:12:17 +03:00
|
|
|
inline static int
|
2017-09-27 05:55:03 +03:00
|
|
|
f_infinite_p(VALUE x)
|
|
|
|
{
|
2021-09-02 15:42:47 +03:00
|
|
|
if (always_finite_type_p(x)) {
|
2021-09-02 11:12:17 +03:00
|
|
|
return FALSE;
|
2017-09-27 05:55:03 +03:00
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
2021-09-02 15:42:47 +03:00
|
|
|
return isinf(RFLOAT_VALUE(x));
|
2017-09-27 05:55:03 +03:00
|
|
|
}
|
2021-09-02 11:12:17 +03:00
|
|
|
return RTEST(rb_funcallv(x, id_infinite_p, 0, 0));
|
2017-09-27 05:55:03 +03:00
|
|
|
}
|
|
|
|
|
2016-11-14 07:06:15 +03:00
|
|
|
inline static int
|
2008-03-20 15:26:58 +03:00
|
|
|
f_kind_of_p(VALUE x, VALUE c)
|
|
|
|
{
|
2016-11-14 07:06:15 +03:00
|
|
|
return (int)rb_obj_is_kind_of(x, c);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2016-11-14 07:06:15 +03:00
|
|
|
inline static int
|
2008-03-20 15:26:58 +03:00
|
|
|
k_numeric_p(VALUE x)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return f_kind_of_p(x, rb_cNumeric);
|
2008-03-20 15:26:58 +03:00
|
|
|
}
|
|
|
|
|
2016-11-13 19:21:54 +03:00
|
|
|
#define k_exact_p(x) (!RB_FLOAT_TYPE_P(x))
|
2008-09-19 17:55:52 +04:00
|
|
|
|
2009-07-12 16:09:21 +04:00
|
|
|
#define k_exact_zero_p(x) (k_exact_p(x) && f_zero_p(x))
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
#define get_dat1(x) \
|
2016-03-31 06:02:35 +03:00
|
|
|
struct RComplex *dat = RCOMPLEX(x)
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
#define get_dat2(x,y) \
|
2016-03-31 06:02:35 +03:00
|
|
|
struct RComplex *adat = RCOMPLEX(x), *bdat = RCOMPLEX(y)
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
inline static VALUE
|
2008-09-21 02:49:56 +04:00
|
|
|
nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2023-02-17 18:51:16 +03:00
|
|
|
NEWOBJ_OF(obj, struct RComplex, klass,
|
|
|
|
T_COMPLEX | (RGENGC_WB_PROTECTED_COMPLEX ? FL_WB_PROTECTED : 0), sizeof(struct RComplex), 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2013-05-13 19:55:09 +04:00
|
|
|
RCOMPLEX_SET_REAL(obj, real);
|
|
|
|
RCOMPLEX_SET_IMAG(obj, imag);
|
2020-04-08 07:28:13 +03:00
|
|
|
OBJ_FREEZE_RAW((VALUE)obj);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
return (VALUE)obj;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
nucomp_s_alloc(VALUE klass)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new_internal(klass, ZERO, ZERO);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_complex_new_bang1(VALUE klass, VALUE x)
|
|
|
|
{
|
2024-02-08 17:42:16 +03:00
|
|
|
RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX));
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new_internal(klass, x, ZERO);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
|
|
|
|
{
|
2024-02-08 17:42:16 +03:00
|
|
|
RUBY_ASSERT(!RB_TYPE_P(x, T_COMPLEX));
|
|
|
|
RUBY_ASSERT(!RB_TYPE_P(y, T_COMPLEX));
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new_internal(klass, x, y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2022-10-23 07:42:36 +03:00
|
|
|
WARN_UNUSED_RESULT(inline static VALUE nucomp_real_check(VALUE num));
|
|
|
|
inline static VALUE
|
2008-04-03 16:55:27 +04:00
|
|
|
nucomp_real_check(VALUE num)
|
|
|
|
{
|
2016-11-12 21:42:30 +03:00
|
|
|
if (!RB_INTEGER_TYPE_P(num) &&
|
|
|
|
!RB_FLOAT_TYPE_P(num) &&
|
2013-09-09 09:47:47 +04:00
|
|
|
!RB_TYPE_P(num, T_RATIONAL)) {
|
2022-10-23 07:42:36 +03:00
|
|
|
if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) {
|
|
|
|
VALUE real = RCOMPLEX(num)->real;
|
2024-02-08 17:42:16 +03:00
|
|
|
RUBY_ASSERT(!RB_TYPE_P(real, T_COMPLEX));
|
2022-10-23 07:42:36 +03:00
|
|
|
return real;
|
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
if (!k_numeric_p(num) || !f_real_p(num))
|
2010-03-03 17:18:26 +03:00
|
|
|
rb_raise(rb_eTypeError, "not a real");
|
2008-04-03 16:55:27 +04:00
|
|
|
}
|
2022-10-23 07:42:36 +03:00
|
|
|
return num;
|
2008-04-03 16:55:27 +04:00
|
|
|
}
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
inline static VALUE
|
2008-09-21 02:49:56 +04:00
|
|
|
nucomp_s_canonicalize_internal(VALUE klass, VALUE real, VALUE imag)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2018-03-07 14:54:07 +03:00
|
|
|
int complex_r, complex_i;
|
|
|
|
complex_r = RB_TYPE_P(real, T_COMPLEX);
|
|
|
|
complex_i = RB_TYPE_P(imag, T_COMPLEX);
|
|
|
|
if (!complex_r && !complex_i) {
|
2008-09-21 02:49:56 +04:00
|
|
|
return nucomp_s_new_internal(klass, real, imag);
|
2018-03-07 14:54:07 +03:00
|
|
|
}
|
|
|
|
else if (!complex_r) {
|
2008-09-21 02:49:56 +04:00
|
|
|
get_dat1(imag);
|
2008-03-31 20:42:24 +04:00
|
|
|
|
|
|
|
return nucomp_s_new_internal(klass,
|
2008-09-21 02:49:56 +04:00
|
|
|
f_sub(real, dat->imag),
|
2008-03-31 20:42:24 +04:00
|
|
|
f_add(ZERO, dat->real));
|
2008-04-22 17:17:04 +04:00
|
|
|
}
|
2018-03-07 14:54:07 +03:00
|
|
|
else if (!complex_i) {
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(real);
|
|
|
|
|
|
|
|
return nucomp_s_new_internal(klass,
|
|
|
|
dat->real,
|
2008-09-21 02:49:56 +04:00
|
|
|
f_add(dat->imag, imag));
|
2008-04-22 17:17:04 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-09-21 02:49:56 +04:00
|
|
|
get_dat2(real, imag);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new_internal(klass,
|
2008-09-21 02:49:56 +04:00
|
|
|
f_sub(adat->real, bdat->imag),
|
|
|
|
f_add(adat->imag, bdat->real));
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-20 15:29:21 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-08 23:02:14 +03:00
|
|
|
* Complex.rect(real, imag = 0) -> complex
|
2009-06-20 15:29:21 +04:00
|
|
|
*
|
2023-12-08 23:02:14 +03:00
|
|
|
* Returns a new \Complex object formed from the arguments,
|
|
|
|
* each of which must be an instance of Numeric,
|
|
|
|
* or an instance of one of its subclasses:
|
|
|
|
* \Complex, Float, Integer, Rational;
|
|
|
|
* see {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
|
2012-09-20 11:06:06 +04:00
|
|
|
*
|
2023-12-08 23:02:14 +03:00
|
|
|
* Complex.rect(3) # => (3+0i)
|
|
|
|
* Complex.rect(3, Math::PI) # => (3+3.141592653589793i)
|
|
|
|
* Complex.rect(-3, -Math::PI) # => (-3-3.141592653589793i)
|
|
|
|
*
|
|
|
|
* \Complex.rectangular is an alias for \Complex.rect.
|
2009-06-20 15:29:21 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_s_new(int argc, VALUE *argv, VALUE klass)
|
|
|
|
{
|
2008-09-21 02:49:56 +04:00
|
|
|
VALUE real, imag;
|
2008-03-31 20:42:24 +04:00
|
|
|
|
2008-09-21 02:49:56 +04:00
|
|
|
switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
|
2008-03-31 20:42:24 +04:00
|
|
|
case 1:
|
2022-10-23 07:42:36 +03:00
|
|
|
real = nucomp_real_check(real);
|
2008-09-21 02:49:56 +04:00
|
|
|
imag = ZERO;
|
2008-03-31 20:42:24 +04:00
|
|
|
break;
|
2008-09-14 13:35:08 +04:00
|
|
|
default:
|
2022-10-23 07:42:36 +03:00
|
|
|
real = nucomp_real_check(real);
|
|
|
|
imag = nucomp_real_check(imag);
|
2008-09-14 13:35:08 +04:00
|
|
|
break;
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
|
2022-10-23 07:42:36 +03:00
|
|
|
return nucomp_s_new_internal(klass, real, imag);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
inline static VALUE
|
|
|
|
f_complex_new2(VALUE klass, VALUE x, VALUE y)
|
|
|
|
{
|
2022-08-31 07:20:40 +03:00
|
|
|
if (RB_TYPE_P(x, T_COMPLEX)) {
|
|
|
|
get_dat1(x);
|
|
|
|
x = dat->real;
|
|
|
|
y = f_add(dat->imag, y);
|
|
|
|
}
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_canonicalize_internal(klass, x, y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2018-03-15 10:19:48 +03:00
|
|
|
static VALUE nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise);
|
2016-11-22 07:54:57 +03:00
|
|
|
static VALUE nucomp_s_convert(int argc, VALUE *argv, VALUE klass);
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-11 23:38:16 +03:00
|
|
|
* Complex(real, imag = 0, exception: true) -> complex or nil
|
2023-12-10 18:22:22 +03:00
|
|
|
* Complex(s, exception: true) -> complex or nil
|
|
|
|
*
|
|
|
|
* Returns a new \Complex object if the arguments are valid;
|
|
|
|
* otherwise raises an exception if +exception+ is +true+;
|
|
|
|
* otherwise returns +nil+.
|
|
|
|
*
|
2023-12-11 23:38:16 +03:00
|
|
|
* With Numeric arguments +real+ and +imag+,
|
|
|
|
* returns <tt>Complex.rect(real, imag)</tt> if the arguments are valid.
|
2023-12-10 18:22:22 +03:00
|
|
|
*
|
|
|
|
* With string argument +s+, returns a new \Complex object if the argument is valid;
|
|
|
|
* the string may have:
|
|
|
|
*
|
|
|
|
* - One or two numeric substrings,
|
|
|
|
* each of which specifies a Complex, Float, Integer, Numeric, or Rational value,
|
|
|
|
* specifying {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates]:
|
|
|
|
*
|
|
|
|
* - Sign-separated real and imaginary numeric substrings
|
|
|
|
* (with trailing character <tt>'i'</tt>):
|
|
|
|
*
|
|
|
|
* Complex('1+2i') # => (1+2i)
|
|
|
|
* Complex('+1+2i') # => (1+2i)
|
|
|
|
* Complex('+1-2i') # => (1-2i)
|
|
|
|
* Complex('-1+2i') # => (-1+2i)
|
|
|
|
* Complex('-1-2i') # => (-1-2i)
|
|
|
|
*
|
|
|
|
* - Real-only numeric string (without trailing character <tt>'i'</tt>):
|
|
|
|
*
|
|
|
|
* Complex('1') # => (1+0i)
|
|
|
|
* Complex('+1') # => (1+0i)
|
|
|
|
* Complex('-1') # => (-1+0i)
|
|
|
|
*
|
|
|
|
* - Imaginary-only numeric string (with trailing character <tt>'i'</tt>):
|
|
|
|
*
|
|
|
|
* Complex('1i') # => (0+1i)
|
|
|
|
* Complex('+1i') # => (0+1i)
|
|
|
|
* Complex('-1i') # => (0-1i)
|
|
|
|
*
|
|
|
|
* - At-sign separated real and imaginary rational substrings,
|
|
|
|
* each of which specifies a Rational value,
|
|
|
|
* specifying {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
|
|
|
|
*
|
|
|
|
* Complex('1/2@3/4') # => (0.36584443443691045+0.34081938001166706i)
|
|
|
|
* Complex('+1/2@+3/4') # => (0.36584443443691045+0.34081938001166706i)
|
|
|
|
* Complex('+1/2@-3/4') # => (0.36584443443691045-0.34081938001166706i)
|
|
|
|
* Complex('-1/2@+3/4') # => (-0.36584443443691045-0.34081938001166706i)
|
|
|
|
* Complex('-1/2@-3/4') # => (-0.36584443443691045+0.34081938001166706i)
|
|
|
|
*
|
2009-06-27 11:46:57 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_f_complex(int argc, VALUE *argv, VALUE klass)
|
|
|
|
{
|
2018-03-15 10:19:48 +03:00
|
|
|
VALUE a1, a2, opts = Qnil;
|
|
|
|
int raise = TRUE;
|
|
|
|
|
|
|
|
if (rb_scan_args(argc, argv, "11:", &a1, &a2, &opts) == 1) {
|
|
|
|
a2 = Qundef;
|
|
|
|
}
|
|
|
|
if (!NIL_P(opts)) {
|
2019-07-11 13:20:53 +03:00
|
|
|
raise = rb_opts_exception_p(opts, raise);
|
2018-03-15 10:19:48 +03:00
|
|
|
}
|
2022-11-15 07:24:08 +03:00
|
|
|
if (argc > 0 && CLASS_OF(a1) == rb_cComplex && UNDEF_P(a2)) {
|
Make Kernel#{Pathname,BigDecimal,Complex} return argument if given correct type
This is how Kernel#{Array,String,Float,Integer,Hash,Rational} work.
BigDecimal and Complex instances are always frozen, so this should
not cause backwards compatibility issues for those. Pathname
instances are not frozen, so potentially this could cause backwards
compatibility issues by not returning a new object.
Based on a patch from Joshua Ballanco, some minor changes by me.
Fixes [Bug #7522]
2019-08-07 19:01:33 +03:00
|
|
|
return a1;
|
|
|
|
}
|
2018-03-15 10:19:48 +03:00
|
|
|
return nucomp_convert(rb_cComplex, a1, a2, raise);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2008-10-28 18:45:29 +03:00
|
|
|
#define imp1(n) \
|
|
|
|
inline static VALUE \
|
2008-10-29 09:45:26 +03:00
|
|
|
m_##n##_bang(VALUE x)\
|
2008-10-28 18:45:29 +03:00
|
|
|
{\
|
|
|
|
return rb_math_##n(x);\
|
|
|
|
}
|
2008-10-28 18:10:40 +03:00
|
|
|
|
2008-10-28 18:45:29 +03:00
|
|
|
imp1(cos)
|
|
|
|
imp1(cosh)
|
|
|
|
imp1(exp)
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
2008-04-05 18:25:40 +04:00
|
|
|
m_log_bang(VALUE x)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-10-28 18:10:40 +03:00
|
|
|
return rb_math_log(1, &x);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2008-10-28 18:45:29 +03:00
|
|
|
imp1(sin)
|
|
|
|
imp1(sinh)
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
static VALUE
|
|
|
|
m_cos(VALUE x)
|
|
|
|
{
|
2018-03-07 15:04:43 +03:00
|
|
|
if (!RB_TYPE_P(x, T_COMPLEX))
|
2008-03-31 20:42:24 +04:00
|
|
|
return m_cos_bang(x);
|
2008-09-21 08:59:53 +04:00
|
|
|
{
|
|
|
|
get_dat1(x);
|
|
|
|
return f_complex_new2(rb_cComplex,
|
|
|
|
f_mul(m_cos_bang(dat->real),
|
|
|
|
m_cosh_bang(dat->imag)),
|
|
|
|
f_mul(f_negate(m_sin_bang(dat->real)),
|
|
|
|
m_sinh_bang(dat->imag)));
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
m_sin(VALUE x)
|
|
|
|
{
|
2018-03-07 15:04:43 +03:00
|
|
|
if (!RB_TYPE_P(x, T_COMPLEX))
|
2008-03-31 20:42:24 +04:00
|
|
|
return m_sin_bang(x);
|
2008-09-21 08:59:53 +04:00
|
|
|
{
|
|
|
|
get_dat1(x);
|
|
|
|
return f_complex_new2(rb_cComplex,
|
|
|
|
f_mul(m_sin_bang(dat->real),
|
|
|
|
m_cosh_bang(dat->imag)),
|
|
|
|
f_mul(m_cos_bang(dat->real),
|
|
|
|
m_sinh_bang(dat->imag)));
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2015-02-25 09:48:55 +03:00
|
|
|
static VALUE
|
2022-10-23 07:42:36 +03:00
|
|
|
f_complex_polar_real(VALUE klass, VALUE x, VALUE y)
|
2008-08-22 16:27:54 +04:00
|
|
|
{
|
2015-02-25 09:48:55 +03:00
|
|
|
if (f_zero_p(x) || f_zero_p(y)) {
|
|
|
|
return nucomp_s_new_internal(klass, x, RFLOAT_0);
|
|
|
|
}
|
|
|
|
if (RB_FLOAT_TYPE_P(y)) {
|
|
|
|
const double arg = RFLOAT_VALUE(y);
|
|
|
|
if (arg == M_PI) {
|
|
|
|
x = f_negate(x);
|
|
|
|
y = RFLOAT_0;
|
|
|
|
}
|
|
|
|
else if (arg == M_PI_2) {
|
|
|
|
y = x;
|
|
|
|
x = RFLOAT_0;
|
|
|
|
}
|
|
|
|
else if (arg == M_PI_2+M_PI) {
|
|
|
|
y = f_negate(x);
|
|
|
|
x = RFLOAT_0;
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(x)) {
|
|
|
|
const double abs = RFLOAT_VALUE(x);
|
|
|
|
const double real = abs * cos(arg), imag = abs * sin(arg);
|
|
|
|
x = DBL2NUM(real);
|
|
|
|
y = DBL2NUM(imag);
|
|
|
|
}
|
|
|
|
else {
|
2020-05-03 08:38:19 +03:00
|
|
|
const double ax = sin(arg), ay = cos(arg);
|
|
|
|
y = f_mul(x, DBL2NUM(ax));
|
|
|
|
x = f_mul(x, DBL2NUM(ay));
|
2015-02-25 09:48:55 +03:00
|
|
|
}
|
|
|
|
return nucomp_s_new_internal(klass, x, y);
|
|
|
|
}
|
2008-08-22 16:27:54 +04:00
|
|
|
return nucomp_s_canonicalize_internal(klass,
|
|
|
|
f_mul(x, m_cos(y)),
|
|
|
|
f_mul(x, m_sin(y)));
|
|
|
|
}
|
|
|
|
|
2022-10-23 07:42:36 +03:00
|
|
|
static VALUE
|
|
|
|
f_complex_polar(VALUE klass, VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
x = nucomp_real_check(x);
|
|
|
|
y = nucomp_real_check(y);
|
|
|
|
return f_complex_polar_real(klass, x, y);
|
|
|
|
}
|
|
|
|
|
2020-05-03 08:38:19 +03:00
|
|
|
#ifdef HAVE___COSPI
|
|
|
|
# define cospi(x) __cospi(x)
|
|
|
|
#else
|
|
|
|
# define cospi(x) cos((x) * M_PI)
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE___SINPI
|
|
|
|
# define sinpi(x) __sinpi(x)
|
|
|
|
#else
|
|
|
|
# define sinpi(x) sin((x) * M_PI)
|
|
|
|
#endif
|
2018-06-17 05:37:32 +03:00
|
|
|
/* returns a Complex or Float of ang*PI-rotated abs */
|
|
|
|
VALUE
|
2018-12-12 14:06:47 +03:00
|
|
|
rb_dbl_complex_new_polar_pi(double abs, double ang)
|
2018-06-17 05:37:32 +03:00
|
|
|
{
|
|
|
|
double fi;
|
|
|
|
const double fr = modf(ang, &fi);
|
|
|
|
int pos = fr == +0.5;
|
|
|
|
|
|
|
|
if (pos || fr == -0.5) {
|
|
|
|
if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs;
|
|
|
|
return rb_complex_new(RFLOAT_0, DBL2NUM(abs));
|
|
|
|
}
|
|
|
|
else if (fr == 0.0) {
|
|
|
|
if (modf(fi / 2.0, &fi) != 0.0) abs = -abs;
|
|
|
|
return DBL2NUM(abs);
|
|
|
|
}
|
|
|
|
else {
|
2020-05-03 08:38:19 +03:00
|
|
|
const double real = abs * cospi(ang), imag = abs * sinpi(ang);
|
|
|
|
return rb_complex_new(DBL2NUM(real), DBL2NUM(imag));
|
2018-06-17 05:37:32 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-20 15:29:21 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-08 23:02:14 +03:00
|
|
|
* Complex.polar(abs, arg = 0) -> complex
|
|
|
|
*
|
|
|
|
* Returns a new \Complex object formed from the arguments,
|
|
|
|
* each of which must be an instance of Numeric,
|
|
|
|
* or an instance of one of its subclasses:
|
2023-12-15 17:39:12 +03:00
|
|
|
* \Complex, Float, Integer, Rational.
|
|
|
|
* Argument +arg+ is given in radians;
|
2023-12-08 23:02:14 +03:00
|
|
|
* see {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
|
2009-06-20 15:29:21 +04:00
|
|
|
*
|
2023-12-08 23:02:14 +03:00
|
|
|
* Complex.polar(3) # => (3+0i)
|
|
|
|
* Complex.polar(3, 2.0) # => (-1.2484405096414273+2.727892280477045i)
|
|
|
|
* Complex.polar(-3, -2.0) # => (1.2484405096414273+2.727892280477045i)
|
2011-01-08 13:51:14 +03:00
|
|
|
*
|
2009-06-20 15:29:21 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
2009-07-05 17:46:10 +04:00
|
|
|
nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2009-07-05 17:46:10 +04:00
|
|
|
VALUE abs, arg;
|
|
|
|
|
2022-10-23 06:59:06 +03:00
|
|
|
argc = rb_scan_args(argc, argv, "11", &abs, &arg);
|
2022-10-23 07:42:36 +03:00
|
|
|
abs = nucomp_real_check(abs);
|
2022-10-23 06:59:06 +03:00
|
|
|
if (argc == 2) {
|
2022-10-23 07:42:36 +03:00
|
|
|
arg = nucomp_real_check(arg);
|
2022-10-23 06:59:06 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
arg = ZERO;
|
2009-07-05 17:46:10 +04:00
|
|
|
}
|
2022-10-23 07:42:36 +03:00
|
|
|
return f_complex_polar_real(klass, abs, arg);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-11 23:38:16 +03:00
|
|
|
* real -> numeric
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-11 23:38:16 +03:00
|
|
|
* Returns the real value for +self+:
|
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* Complex.rect(7).real # => 7
|
|
|
|
* Complex.rect(9, -4).real # => 9
|
2023-12-11 23:38:16 +03:00
|
|
|
*
|
|
|
|
* If +self+ was created with
|
|
|
|
* {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
|
|
|
*
|
|
|
|
* Complex.polar(1, Math::PI/4).real # => 0.7071067811865476 # Square root of 2.
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_real(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
|
|
|
return dat->real;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-11 23:38:16 +03:00
|
|
|
* imag -> numeric
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-11 23:38:16 +03:00
|
|
|
* Returns the imaginary value for +self+:
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* Complex.rect(7).imag # => 0
|
|
|
|
* Complex.rect(9, -4).imag # => -4
|
2023-12-11 23:38:16 +03:00
|
|
|
*
|
|
|
|
* If +self+ was created with
|
|
|
|
* {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
|
|
|
*
|
|
|
|
* Complex.polar(1, Math::PI/4).imag # => 0.7071067811865476 # Square root of 2.
|
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_imag(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-09-21 02:49:56 +04:00
|
|
|
return dat->imag;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
2009-06-27 11:46:57 +04:00
|
|
|
* call-seq:
|
2023-12-13 00:05:19 +03:00
|
|
|
* -complex -> new_complex
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-13 00:05:19 +03:00
|
|
|
* Returns the negation of +self+, which is the negation of each of its parts:
|
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* -Complex.rect(1, 2) # => (-1-2i)
|
|
|
|
* -Complex.rect(-1, -2) # => (1+2i)
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_uminus(VALUE self)
|
2008-09-14 05:16:44 +04:00
|
|
|
{
|
2018-03-07 14:49:23 +03:00
|
|
|
get_dat1(self);
|
|
|
|
return f_complex_new2(CLASS_OF(self),
|
|
|
|
f_negate(dat->real), f_negate(dat->imag));
|
2008-09-14 05:16:44 +04:00
|
|
|
}
|
|
|
|
|
2009-06-27 14:12:04 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-13 00:05:19 +03:00
|
|
|
* complex + numeric -> new_complex
|
|
|
|
*
|
|
|
|
* Returns the sum of +self+ and +numeric+:
|
2009-06-27 14:12:04 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2, 3) + Complex.rect(2, 3) # => (4+6i)
|
|
|
|
* Complex.rect(900) + Complex.rect(1) # => (901+0i)
|
|
|
|
* Complex.rect(-2, 9) + Complex.rect(-9, 2) # => (-11+11i)
|
|
|
|
* Complex.rect(9, 8) + 4 # => (13+8i)
|
|
|
|
* Complex.rect(20, 9) + 9.8 # => (29.8+9i)
|
2012-09-20 02:23:15 +04:00
|
|
|
*
|
2009-06-27 14:12:04 +04:00
|
|
|
*/
|
2015-02-24 16:59:06 +03:00
|
|
|
VALUE
|
2016-07-12 16:17:04 +03:00
|
|
|
rb_complex_plus(VALUE self, VALUE other)
|
2009-06-27 14:12:04 +04:00
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
|
|
|
VALUE real, imag;
|
|
|
|
|
|
|
|
get_dat2(self, other);
|
|
|
|
|
|
|
|
real = f_add(adat->real, bdat->real);
|
|
|
|
imag = f_add(adat->imag, bdat->imag);
|
|
|
|
|
|
|
|
return f_complex_new2(CLASS_OF(self), real, imag);
|
|
|
|
}
|
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
|
|
|
get_dat1(self);
|
|
|
|
|
|
|
|
return f_complex_new2(CLASS_OF(self),
|
|
|
|
f_add(dat->real, other), dat->imag);
|
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(self, other, '+');
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-13 00:05:19 +03:00
|
|
|
* complex - numeric -> new_complex
|
|
|
|
*
|
|
|
|
* Returns the difference of +self+ and +numeric+:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2, 3) - Complex.rect(2, 3) # => (0+0i)
|
|
|
|
* Complex.rect(900) - Complex.rect(1) # => (899+0i)
|
|
|
|
* Complex.rect(-2, 9) - Complex.rect(-9, 2) # => (7+7i)
|
|
|
|
* Complex.rect(9, 8) - 4 # => (5+8i)
|
|
|
|
* Complex.rect(20, 9) - 9.8 # => (10.2+9i)
|
2012-09-20 02:23:15 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_minus(VALUE self, VALUE other)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
|
|
|
VALUE real, imag;
|
|
|
|
|
|
|
|
get_dat2(self, other);
|
|
|
|
|
|
|
|
real = f_sub(adat->real, bdat->real);
|
|
|
|
imag = f_sub(adat->imag, bdat->imag);
|
|
|
|
|
|
|
|
return f_complex_new2(CLASS_OF(self), real, imag);
|
|
|
|
}
|
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
|
|
|
get_dat1(self);
|
|
|
|
|
|
|
|
return f_complex_new2(CLASS_OF(self),
|
|
|
|
f_sub(dat->real, other), dat->imag);
|
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(self, other, '-');
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2015-02-25 20:05:26 +03:00
|
|
|
static VALUE
|
2022-08-31 04:59:05 +03:00
|
|
|
safe_mul(VALUE a, VALUE b, bool az, bool bz)
|
2015-02-25 20:05:26 +03:00
|
|
|
{
|
|
|
|
double v;
|
2015-03-09 08:48:09 +03:00
|
|
|
if (!az && bz && RB_FLOAT_TYPE_P(a) && (v = RFLOAT_VALUE(a), !isnan(v))) {
|
2015-02-25 20:05:26 +03:00
|
|
|
a = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
|
|
|
|
}
|
2015-03-09 08:48:09 +03:00
|
|
|
if (!bz && az && RB_FLOAT_TYPE_P(b) && (v = RFLOAT_VALUE(b), !isnan(v))) {
|
2015-02-25 20:05:26 +03:00
|
|
|
b = signbit(v) ? DBL2NUM(-1.0) : DBL2NUM(1.0);
|
|
|
|
}
|
|
|
|
return f_mul(a, b);
|
|
|
|
}
|
|
|
|
|
2018-10-20 05:49:18 +03:00
|
|
|
static void
|
|
|
|
comp_mul(VALUE areal, VALUE aimag, VALUE breal, VALUE bimag, VALUE *real, VALUE *imag)
|
|
|
|
{
|
2022-08-31 04:59:05 +03:00
|
|
|
bool arzero = f_zero_p(areal);
|
|
|
|
bool aizero = f_zero_p(aimag);
|
|
|
|
bool brzero = f_zero_p(breal);
|
|
|
|
bool bizero = f_zero_p(bimag);
|
2018-10-20 05:49:18 +03:00
|
|
|
*real = f_sub(safe_mul(areal, breal, arzero, brzero),
|
|
|
|
safe_mul(aimag, bimag, aizero, bizero));
|
|
|
|
*imag = f_add(safe_mul(areal, bimag, arzero, bizero),
|
|
|
|
safe_mul(aimag, breal, aizero, brzero));
|
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-13 00:05:19 +03:00
|
|
|
* complex * numeric -> new_complex
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-13 00:05:19 +03:00
|
|
|
* Returns the product of +self+ and +numeric+:
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2, 3) * Complex.rect(2, 3) # => (-5+12i)
|
|
|
|
* Complex.rect(900) * Complex.rect(1) # => (900+0i)
|
|
|
|
* Complex.rect(-2, 9) * Complex.rect(-9, 2) # => (0-85i)
|
|
|
|
* Complex.rect(9, 8) * 4 # => (36+32i)
|
|
|
|
* Complex.rect(20, 9) * 9.8 # => (196.0+88.2i)
|
2012-09-20 02:23:15 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2015-02-24 16:59:06 +03:00
|
|
|
VALUE
|
2016-07-12 16:17:04 +03:00
|
|
|
rb_complex_mul(VALUE self, VALUE other)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2008-09-21 02:49:56 +04:00
|
|
|
VALUE real, imag;
|
2008-08-22 16:27:54 +04:00
|
|
|
get_dat2(self, other);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2018-10-20 05:49:18 +03:00
|
|
|
comp_mul(adat->real, adat->imag, bdat->real, bdat->imag, &real, &imag);
|
2015-02-24 16:58:52 +03:00
|
|
|
|
2008-09-21 02:49:56 +04:00
|
|
|
return f_complex_new2(CLASS_OF(self), real, imag);
|
2008-08-22 16:27:54 +04:00
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
2008-08-22 16:27:54 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-08-22 16:27:54 +04:00
|
|
|
return f_complex_new2(CLASS_OF(self),
|
|
|
|
f_mul(dat->real, other),
|
2008-09-21 02:49:56 +04:00
|
|
|
f_mul(dat->imag, other));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
2008-08-22 16:27:54 +04:00
|
|
|
return rb_num_coerce_bin(self, other, '*');
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-28 04:22:07 +04:00
|
|
|
inline static VALUE
|
|
|
|
f_divide(VALUE self, VALUE other,
|
|
|
|
VALUE (*func)(VALUE, VALUE), ID id)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2018-09-01 10:34:31 +03:00
|
|
|
VALUE r, n, x, y;
|
2009-06-27 14:12:04 +04:00
|
|
|
int flo;
|
2008-08-22 16:27:54 +04:00
|
|
|
get_dat2(self, other);
|
|
|
|
|
2016-11-13 19:21:54 +03:00
|
|
|
flo = (RB_FLOAT_TYPE_P(adat->real) || RB_FLOAT_TYPE_P(adat->imag) ||
|
|
|
|
RB_FLOAT_TYPE_P(bdat->real) || RB_FLOAT_TYPE_P(bdat->imag));
|
2009-06-27 14:12:04 +04:00
|
|
|
|
|
|
|
if (f_gt_p(f_abs(bdat->real), f_abs(bdat->imag))) {
|
|
|
|
r = (*func)(bdat->imag, bdat->real);
|
|
|
|
n = f_mul(bdat->real, f_add(ONE, f_mul(r, r)));
|
2018-09-01 10:34:31 +03:00
|
|
|
x = (*func)(f_add(adat->real, f_mul(adat->imag, r)), n);
|
|
|
|
y = (*func)(f_sub(adat->imag, f_mul(adat->real, r)), n);
|
2009-06-27 14:12:04 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
r = (*func)(bdat->real, bdat->imag);
|
|
|
|
n = f_mul(bdat->imag, f_add(ONE, f_mul(r, r)));
|
2018-09-01 10:34:31 +03:00
|
|
|
x = (*func)(f_add(f_mul(adat->real, r), adat->imag), n);
|
|
|
|
y = (*func)(f_sub(f_mul(adat->imag, r), adat->real), n);
|
2008-04-22 17:17:04 +04:00
|
|
|
}
|
2019-07-14 10:31:36 +03:00
|
|
|
if (!flo) {
|
|
|
|
x = rb_rational_canonicalize(x);
|
|
|
|
y = rb_rational_canonicalize(y);
|
|
|
|
}
|
2018-09-01 10:34:31 +03:00
|
|
|
return f_complex_new2(CLASS_OF(self), x, y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
2019-01-07 05:03:41 +03:00
|
|
|
VALUE x, y;
|
2008-08-22 16:27:54 +04:00
|
|
|
get_dat1(self);
|
2019-01-07 05:03:41 +03:00
|
|
|
x = rb_rational_canonicalize((*func)(dat->real, other));
|
|
|
|
y = rb_rational_canonicalize((*func)(dat->imag, other));
|
|
|
|
return f_complex_new2(CLASS_OF(self), x, y);
|
2008-08-22 16:27:54 +04:00
|
|
|
}
|
2009-06-14 02:57:02 +04:00
|
|
|
return rb_num_coerce_bin(self, other, id);
|
|
|
|
}
|
|
|
|
|
2009-06-28 18:39:31 +04:00
|
|
|
#define rb_raise_zerodiv() rb_raise(rb_eZeroDivError, "divided by 0")
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-13 00:05:19 +03:00
|
|
|
* complex / numeric -> new_complex
|
|
|
|
*
|
|
|
|
* Returns the quotient of +self+ and +numeric+:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2, 3) / Complex.rect(2, 3) # => (1+0i)
|
|
|
|
* Complex.rect(900) / Complex.rect(1) # => (900+0i)
|
|
|
|
* Complex.rect(-2, 9) / Complex.rect(-9, 2) # => ((36/85)-(77/85)*i)
|
|
|
|
* Complex.rect(9, 8) / 4 # => ((9/4)+2i)
|
|
|
|
* Complex.rect(20, 9) / 9.8 # => (2.0408163265306123+0.9183673469387754i)
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_div(VALUE self, VALUE other)
|
2009-06-14 02:57:02 +04:00
|
|
|
{
|
2009-06-28 04:22:07 +04:00
|
|
|
return f_divide(self, other, f_quo, id_quo);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2018-12-12 14:06:48 +03:00
|
|
|
#define nucomp_quo rb_complex_div
|
2008-08-22 16:27:54 +04:00
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-14 19:09:17 +03:00
|
|
|
* fdiv(numeric) -> new_complex
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>:
|
2023-12-14 19:09:17 +03:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(11, 22).fdiv(3) # => (3.6666666666666665+7.333333333333333i)
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_fdiv(VALUE self, VALUE other)
|
|
|
|
{
|
2009-06-28 04:22:07 +04:00
|
|
|
return f_divide(self, other, f_fdiv, id_fdiv);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-07-12 15:46:40 +04:00
|
|
|
inline static VALUE
|
|
|
|
f_reciprocal(VALUE x)
|
|
|
|
{
|
|
|
|
return f_quo(ONE, x);
|
|
|
|
}
|
|
|
|
|
2023-11-16 14:32:53 +03:00
|
|
|
static VALUE
|
|
|
|
zero_for(VALUE x)
|
|
|
|
{
|
|
|
|
if (RB_FLOAT_TYPE_P(x))
|
|
|
|
return DBL2NUM(0);
|
|
|
|
if (RB_TYPE_P(x, T_RATIONAL))
|
|
|
|
return rb_rational_new(INT2FIX(0), INT2FIX(1));
|
|
|
|
|
|
|
|
return INT2FIX(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
complex_pow_for_special_angle(VALUE self, VALUE other)
|
|
|
|
{
|
|
|
|
if (!rb_integer_type_p(other)) {
|
|
|
|
return Qundef;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_dat1(self);
|
|
|
|
VALUE x = Qundef;
|
|
|
|
int dir;
|
|
|
|
if (f_zero_p(dat->imag)) {
|
|
|
|
x = dat->real;
|
|
|
|
dir = 0;
|
|
|
|
}
|
|
|
|
else if (f_zero_p(dat->real)) {
|
|
|
|
x = dat->imag;
|
|
|
|
dir = 2;
|
|
|
|
}
|
|
|
|
else if (f_eqeq_p(dat->real, dat->imag)) {
|
|
|
|
x = dat->real;
|
|
|
|
dir = 1;
|
|
|
|
}
|
|
|
|
else if (f_eqeq_p(dat->real, f_negate(dat->imag))) {
|
|
|
|
x = dat->imag;
|
|
|
|
dir = 3;
|
|
|
|
}
|
|
|
|
|
2024-01-30 08:48:59 +03:00
|
|
|
if (UNDEF_P(x)) return x;
|
2023-11-16 14:32:53 +03:00
|
|
|
|
|
|
|
if (f_negative_p(x)) {
|
|
|
|
x = f_negate(x);
|
|
|
|
dir += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE zx;
|
|
|
|
if (dir % 2 == 0) {
|
|
|
|
zx = rb_num_pow(x, other);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
zx = rb_num_pow(
|
|
|
|
rb_funcall(rb_int_mul(TWO, x), '*', 1, x),
|
|
|
|
rb_int_div(other, TWO)
|
|
|
|
);
|
|
|
|
if (rb_int_odd_p(other)) {
|
|
|
|
zx = rb_funcall(zx, '*', 1, x);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static const int dirs[][2] = {
|
|
|
|
{1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}
|
|
|
|
};
|
|
|
|
int z_dir = FIX2INT(rb_int_modulo(rb_int_mul(INT2FIX(dir), other), INT2FIX(8)));
|
|
|
|
|
2023-11-22 07:07:44 +03:00
|
|
|
VALUE zr = Qfalse, zi = Qfalse;
|
2023-11-16 14:32:53 +03:00
|
|
|
switch (dirs[z_dir][0]) {
|
|
|
|
case 0: zr = zero_for(zx); break;
|
|
|
|
case 1: zr = zx; break;
|
|
|
|
case -1: zr = f_negate(zx); break;
|
|
|
|
}
|
|
|
|
switch (dirs[z_dir][1]) {
|
|
|
|
case 0: zi = zero_for(zx); break;
|
|
|
|
case 1: zi = zx; break;
|
|
|
|
case -1: zi = f_negate(zx); break;
|
|
|
|
}
|
|
|
|
return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 17:39:12 +03:00
|
|
|
* complex ** numeric -> new_complex
|
2023-12-14 19:09:17 +03:00
|
|
|
*
|
|
|
|
* Returns +self+ raised to power +numeric+:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* Complex.rect(0, 1) ** 2 # => (-1+0i)
|
|
|
|
* Complex.rect(-8) ** Rational(1, 3) # => (1.0000000000000002+1.7320508075688772i)
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
|
|
|
*/
|
2018-10-20 05:49:18 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_pow(VALUE self, VALUE other)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2010-11-23 01:31:55 +03:00
|
|
|
if (k_numeric_p(other) && k_exact_zero_p(other))
|
2008-03-31 20:42:24 +04:00
|
|
|
return f_complex_new_bang1(CLASS_OF(self), ONE);
|
|
|
|
|
2016-11-13 19:22:08 +03:00
|
|
|
if (RB_TYPE_P(other, T_RATIONAL) && RRATIONAL(other)->den == LONG2FIX(1))
|
|
|
|
other = RRATIONAL(other)->num; /* c14n */
|
2009-06-28 14:50:39 +04:00
|
|
|
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2009-06-28 14:50:39 +04:00
|
|
|
get_dat1(other);
|
|
|
|
|
2009-07-12 16:09:21 +04:00
|
|
|
if (k_exact_zero_p(dat->imag))
|
2009-06-28 14:50:39 +04:00
|
|
|
other = dat->real; /* c14n */
|
|
|
|
}
|
|
|
|
|
2023-11-16 14:32:53 +03:00
|
|
|
if (other == ONE) {
|
|
|
|
get_dat1(self);
|
|
|
|
return nucomp_s_new_internal(CLASS_OF(self), dat->real, dat->imag);
|
|
|
|
}
|
|
|
|
|
|
|
|
VALUE result = complex_pow_for_special_angle(self, other);
|
2024-01-30 08:48:59 +03:00
|
|
|
if (!UNDEF_P(result)) return result;
|
2023-11-16 14:32:53 +03:00
|
|
|
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2009-06-14 02:57:02 +04:00
|
|
|
VALUE r, theta, nr, ntheta;
|
2008-08-22 16:27:54 +04:00
|
|
|
|
|
|
|
get_dat1(other);
|
|
|
|
|
2009-06-14 02:57:02 +04:00
|
|
|
r = f_abs(self);
|
|
|
|
theta = f_arg(self);
|
2008-08-22 16:27:54 +04:00
|
|
|
|
2009-06-14 02:57:02 +04:00
|
|
|
nr = m_exp_bang(f_sub(f_mul(dat->real, m_log_bang(r)),
|
|
|
|
f_mul(dat->imag, theta)));
|
|
|
|
ntheta = f_add(f_mul(theta, dat->real),
|
|
|
|
f_mul(dat->imag, m_log_bang(r)));
|
2008-08-22 16:27:54 +04:00
|
|
|
return f_complex_polar(CLASS_OF(self), nr, ntheta);
|
|
|
|
}
|
2016-11-12 21:42:30 +03:00
|
|
|
if (FIXNUM_P(other)) {
|
2018-10-20 05:49:18 +03:00
|
|
|
long n = FIX2LONG(other);
|
|
|
|
if (n == 0) {
|
2018-10-20 05:49:23 +03:00
|
|
|
return nucomp_s_new_internal(CLASS_OF(self), ONE, ZERO);
|
2018-10-20 05:49:18 +03:00
|
|
|
}
|
|
|
|
if (n < 0) {
|
|
|
|
self = f_reciprocal(self);
|
|
|
|
other = rb_int_uminus(other);
|
|
|
|
n = -n;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
get_dat1(self);
|
|
|
|
VALUE xr = dat->real, xi = dat->imag, zr = xr, zi = xi;
|
|
|
|
|
|
|
|
if (f_zero_p(xi)) {
|
|
|
|
zr = rb_num_pow(zr, other);
|
|
|
|
}
|
|
|
|
else if (f_zero_p(xr)) {
|
|
|
|
zi = rb_num_pow(zi, other);
|
|
|
|
if (n & 2) zi = f_negate(zi);
|
|
|
|
if (!(n & 1)) {
|
|
|
|
VALUE tmp = zr;
|
|
|
|
zr = zi;
|
|
|
|
zi = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
while (--n) {
|
|
|
|
long q, r;
|
|
|
|
|
|
|
|
for (; q = n / 2, r = n % 2, r == 0; n = q) {
|
|
|
|
VALUE tmp = f_sub(f_mul(xr, xr), f_mul(xi, xi));
|
|
|
|
xi = f_mul(f_mul(TWO, xr), xi);
|
|
|
|
xr = tmp;
|
|
|
|
}
|
|
|
|
comp_mul(zr, zi, xr, xi, &zr, &zi);
|
|
|
|
}
|
|
|
|
}
|
2018-10-20 05:49:23 +03:00
|
|
|
return nucomp_s_new_internal(CLASS_OF(self), zr, zi);
|
2008-04-22 17:17:04 +04:00
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
2009-06-14 02:57:02 +04:00
|
|
|
VALUE r, theta;
|
2008-08-22 16:27:54 +04:00
|
|
|
|
2021-09-03 14:50:12 +03:00
|
|
|
if (RB_BIGNUM_TYPE_P(other))
|
2009-06-28 17:27:48 +04:00
|
|
|
rb_warn("in a**b, b may be too big");
|
|
|
|
|
2009-06-14 02:57:02 +04:00
|
|
|
r = f_abs(self);
|
|
|
|
theta = f_arg(self);
|
2009-06-29 20:20:32 +04:00
|
|
|
|
|
|
|
return f_complex_polar(CLASS_OF(self), f_expt(r, other),
|
2009-06-14 02:57:02 +04:00
|
|
|
f_mul(theta, other));
|
2008-08-22 16:27:54 +04:00
|
|
|
}
|
|
|
|
return rb_num_coerce_bin(self, other, id_expt);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-07-03 16:19:54 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-14 19:09:17 +03:00
|
|
|
* complex == object -> true or false
|
2009-07-03 16:19:54 +04:00
|
|
|
*
|
2023-12-14 19:09:17 +03:00
|
|
|
* Returns +true+ if <tt>self.real == object.real</tt>
|
|
|
|
* and <tt>self.imag == object.imag</tt>:
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2, 3) == Complex.rect(2.0, 3.0) # => true
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-07-03 16:19:54 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
nucomp_eqeq_p(VALUE self, VALUE other)
|
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2009-07-03 16:19:54 +04:00
|
|
|
get_dat2(self, other);
|
|
|
|
|
2021-08-17 20:25:19 +03:00
|
|
|
return RBOOL(f_eqeq_p(adat->real, bdat->real) &&
|
2009-07-03 16:19:54 +04:00
|
|
|
f_eqeq_p(adat->imag, bdat->imag));
|
|
|
|
}
|
2008-09-06 02:55:35 +04:00
|
|
|
if (k_numeric_p(other) && f_real_p(other)) {
|
2008-08-22 16:27:54 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2021-08-17 20:25:19 +03:00
|
|
|
return RBOOL(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
2021-08-17 20:25:19 +03:00
|
|
|
return RBOOL(f_eqeq_p(other, self));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2019-11-25 09:05:53 +03:00
|
|
|
static bool
|
2019-06-05 07:41:02 +03:00
|
|
|
nucomp_real_p(VALUE self)
|
|
|
|
{
|
|
|
|
get_dat1(self);
|
2022-08-31 04:59:05 +03:00
|
|
|
return f_zero_p(dat->imag);
|
2019-06-05 07:41:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-14 19:09:17 +03:00
|
|
|
* complex <=> object -> -1, 0, 1, or nil
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
*
|
|
|
|
* - <tt>self.real <=> object.real</tt> if both of the following are true:
|
|
|
|
*
|
|
|
|
* - <tt>self.imag == 0</tt>.
|
|
|
|
* - <tt>object.imag == 0</tt>. # Always true if object is numeric but not complex.
|
|
|
|
*
|
|
|
|
* - +nil+ otherwise.
|
|
|
|
*
|
|
|
|
* Examples:
|
2019-06-05 07:41:02 +03:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(2) <=> 3 # => -1
|
|
|
|
* Complex.rect(2) <=> 2 # => 0
|
|
|
|
* Complex.rect(2) <=> 1 # => 1
|
|
|
|
* Complex.rect(2, 1) <=> 1 # => nil # self.imag not zero.
|
|
|
|
* Complex.rect(1) <=> Complex.rect(1, 1) # => nil # object.imag not zero.
|
|
|
|
* Complex.rect(1) <=> 'Foo' # => nil # object.imag not defined.
|
2019-06-05 07:41:02 +03:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
nucomp_cmp(VALUE self, VALUE other)
|
|
|
|
{
|
2022-08-22 06:21:47 +03:00
|
|
|
if (!k_numeric_p(other)) {
|
|
|
|
return rb_num_coerce_cmp(self, other, idCmp);
|
|
|
|
}
|
2022-08-31 05:01:59 +03:00
|
|
|
if (!nucomp_real_p(self)) {
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
|
|
|
if (nucomp_real_p(other)) {
|
2019-06-05 07:41:02 +03:00
|
|
|
get_dat2(self, other);
|
|
|
|
return rb_funcall(adat->real, idCmp, 1, bdat->real);
|
2019-08-10 07:56:18 +03:00
|
|
|
}
|
2022-08-31 05:01:59 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
get_dat1(self);
|
|
|
|
if (f_real_p(other)) {
|
2019-06-05 07:41:02 +03:00
|
|
|
return rb_funcall(dat->real, idCmp, 1, other);
|
|
|
|
}
|
2022-08-31 05:01:59 +03:00
|
|
|
else {
|
|
|
|
return rb_num_coerce_cmp(dat->real, other, idCmp);
|
|
|
|
}
|
2019-06-05 07:41:02 +03:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/* :nodoc: */
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_coerce(VALUE self, VALUE other)
|
|
|
|
{
|
2011-09-29 15:07:45 +04:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX))
|
2009-06-17 03:17:17 +04:00
|
|
|
return rb_assoc_new(other, self);
|
2019-06-05 07:41:02 +03:00
|
|
|
if (k_numeric_p(other) && f_real_p(other))
|
2019-06-19 22:07:31 +03:00
|
|
|
return rb_assoc_new(f_complex_new_bang1(CLASS_OF(self), other), self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2015-09-28 05:40:46 +03:00
|
|
|
rb_raise(rb_eTypeError, "%"PRIsVALUE" can't be coerced into %"PRIsVALUE,
|
|
|
|
rb_obj_class(other), rb_obj_class(self));
|
2008-03-31 20:42:24 +04:00
|
|
|
return Qnil;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 17:39:12 +03:00
|
|
|
* abs -> float
|
|
|
|
*
|
|
|
|
* Returns the absolute value (magnitude) for +self+;
|
|
|
|
* see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
|
|
|
|
*
|
|
|
|
* Complex.polar(-1, 0).abs # => 1.0
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* If +self+ was created with
|
|
|
|
* {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* Complex.rectangular(1, 1).abs # => 1.4142135623730951 # The square root of 2.
|
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_abs(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2009-06-27 14:12:04 +04:00
|
|
|
|
|
|
|
if (f_zero_p(dat->real)) {
|
|
|
|
VALUE a = f_abs(dat->imag);
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(dat->real) && !RB_FLOAT_TYPE_P(dat->imag))
|
2009-06-27 14:12:04 +04:00
|
|
|
a = f_to_f(a);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
if (f_zero_p(dat->imag)) {
|
|
|
|
VALUE a = f_abs(dat->real);
|
2016-11-13 19:21:54 +03:00
|
|
|
if (!RB_FLOAT_TYPE_P(dat->real) && RB_FLOAT_TYPE_P(dat->imag))
|
2009-06-27 14:12:04 +04:00
|
|
|
a = f_to_f(a);
|
|
|
|
return a;
|
|
|
|
}
|
2016-11-18 17:24:15 +03:00
|
|
|
return rb_math_hypot(dat->real, dat->imag);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 17:39:12 +03:00
|
|
|
* abs2 -> float
|
|
|
|
*
|
|
|
|
* Returns square of the absolute value (magnitude) for +self+;
|
|
|
|
* see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* Complex.polar(2, 2).abs2 # => 4.0
|
|
|
|
*
|
|
|
|
* If +self+ was created with
|
|
|
|
* {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
|
|
|
*
|
|
|
|
* Complex.rectangular(1.0/3, 1.0/3).abs2 # => 0.2222222222222222
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_abs2(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
|
|
|
return f_add(f_mul(dat->real, dat->real),
|
2008-09-21 02:49:56 +04:00
|
|
|
f_mul(dat->imag, dat->imag));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 17:39:12 +03:00
|
|
|
* arg -> float
|
|
|
|
*
|
|
|
|
* Returns the argument (angle) for +self+ in radians;
|
|
|
|
* see {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates]:
|
|
|
|
*
|
|
|
|
* Complex.polar(3, Math::PI/2).arg # => 1.57079632679489660
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* If +self+ was created with
|
|
|
|
* {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
2011-01-08 13:51:14 +03:00
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* Complex.polar(1, 1.0/3).arg # => 0.33333333333333326
|
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_arg(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2016-11-18 17:24:15 +03:00
|
|
|
return rb_math_atan2(dat->imag, dat->real);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 21:32:32 +03:00
|
|
|
* rect -> array
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 21:32:32 +03:00
|
|
|
* Returns the array <tt>[self.real, self.imag]</tt>:
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-15 21:32:32 +03:00
|
|
|
* Complex.rect(1, 2).rect # => [1, 2]
|
|
|
|
*
|
|
|
|
* See {Rectangular Coordinates}[rdoc-ref:Complex@Rectangular+Coordinates].
|
|
|
|
*
|
|
|
|
* If +self+ was created with
|
|
|
|
* {polar coordinates}[rdoc-ref:Complex@Polar+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
|
|
|
*
|
|
|
|
* Complex.polar(1.0, 1.0).rect # => [0.5403023058681398, 0.8414709848078965]
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Complex#rectangular is an alias for Complex#rect.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-08-29 17:41:41 +04:00
|
|
|
static VALUE
|
|
|
|
nucomp_rect(VALUE self)
|
|
|
|
{
|
|
|
|
get_dat1(self);
|
2008-09-21 02:49:56 +04:00
|
|
|
return rb_assoc_new(dat->real, dat->imag);
|
2008-08-29 17:41:41 +04:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 21:32:32 +03:00
|
|
|
* polar -> array
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 21:32:32 +03:00
|
|
|
* Returns the array <tt>[self.abs, self.arg]</tt>:
|
|
|
|
*
|
|
|
|
* Complex.polar(1, 2).polar # => [1.0, 2.0]
|
|
|
|
*
|
|
|
|
* See {Polar Coordinates}[rdoc-ref:Complex@Polar+Coordinates].
|
|
|
|
*
|
|
|
|
* If +self+ was created with
|
|
|
|
* {rectangular coordinates}[rdoc-ref:Complex@Rectangular+Coordinates], the returned value
|
|
|
|
* is computed, and may be inexact:
|
|
|
|
*
|
|
|
|
* Complex.rect(1, 1).polar # => [1.4142135623730951, 0.7853981633974483]
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_polar(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return rb_assoc_new(f_abs(self), f_arg(self));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 21:32:32 +03:00
|
|
|
* conj -> complex
|
|
|
|
*
|
|
|
|
* Returns the conjugate of +self+, <tt>Complex.rect(self.imag, self.real)</tt>:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 21:32:32 +03:00
|
|
|
* Complex.rect(1, 2).conj # => (1-2i)
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2018-12-12 14:06:48 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_conjugate(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-09-21 02:49:56 +04:00
|
|
|
return f_complex_new2(CLASS_OF(self), dat->real, f_negate(dat->imag));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-15 21:32:32 +03:00
|
|
|
* real? -> false
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-15 21:32:32 +03:00
|
|
|
* Returns +false+; for compatibility with Numeric#real?.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
2021-05-20 08:31:49 +03:00
|
|
|
nucomp_real_p_m(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2008-09-13 05:55:56 +04:00
|
|
|
return Qfalse;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 05:40:58 +03:00
|
|
|
* denominator -> integer
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-19 05:40:58 +03:00
|
|
|
* Returns the denominator of +self+, which is
|
|
|
|
* the {least common multiple}[https://en.wikipedia.org/wiki/Least_common_multiple]
|
|
|
|
* of <tt>self.real.denominator</tt> and <tt>self.imag.denominator</tt>:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-19 05:40:58 +03:00
|
|
|
* Complex.rect(Rational(1, 2), Rational(2, 3)).denominator # => 6
|
|
|
|
*
|
|
|
|
* Note that <tt>n.denominator</tt> of a non-rational numeric is +1+.
|
|
|
|
*
|
|
|
|
* Related: Complex#numerator.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_denominator(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-09-21 02:49:56 +04:00
|
|
|
return rb_lcm(f_denominator(dat->real), f_denominator(dat->imag));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 05:40:58 +03:00
|
|
|
* numerator -> new_complex
|
|
|
|
*
|
|
|
|
* Returns the \Complex object created from the numerators
|
|
|
|
* of the real and imaginary parts of +self+,
|
|
|
|
* after converting each part to the
|
|
|
|
* {lowest common denominator}[https://en.wikipedia.org/wiki/Lowest_common_denominator]
|
|
|
|
* of the two:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* c = Complex.rect(Rational(2, 3), Rational(3, 4)) # => ((2/3)+(3/4)*i)
|
|
|
|
* c.numerator # => (8+9i)
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-19 05:40:58 +03:00
|
|
|
* In this example, the lowest common denominator of the two parts is 12;
|
2023-12-19 18:19:00 +03:00
|
|
|
* the two converted parts may be thought of as \Rational(8, 12) and \Rational(9, 12),
|
2023-12-19 05:40:58 +03:00
|
|
|
* whose numerators, respectively, are 8 and 9;
|
2023-12-26 19:00:04 +03:00
|
|
|
* so the returned value of <tt>c.numerator</tt> is <tt>Complex.rect(8, 9)</tt>.
|
2009-06-27 11:46:57 +04:00
|
|
|
*
|
2023-12-19 05:40:58 +03:00
|
|
|
* Related: Complex#denominator.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_numerator(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
VALUE cd;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2019-07-16 01:58:47 +03:00
|
|
|
cd = nucomp_denominator(self);
|
2008-03-31 20:42:24 +04:00
|
|
|
return f_complex_new2(CLASS_OF(self),
|
|
|
|
f_mul(f_numerator(dat->real),
|
|
|
|
f_div(cd, f_denominator(dat->real))),
|
2008-09-21 02:49:56 +04:00
|
|
|
f_mul(f_numerator(dat->imag),
|
|
|
|
f_div(cd, f_denominator(dat->imag))));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/* :nodoc: */
|
2021-05-07 06:49:32 +03:00
|
|
|
st_index_t
|
|
|
|
rb_complex_hash(VALUE self)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2009-09-08 17:10:04 +04:00
|
|
|
st_index_t v, h[2];
|
* string.c (rb_hash_uint32, rb_hash_uint, rb_hash_start, rb_hash_end),
include/ruby/intern.h: add Murmurhash API. [ruby-dev:37784]
* complex.c (nucomp_hash), array.c (rb_ary_hash), time.c (time_hash),
string.c (rb_str_hsah), object.c (rb_obj_hash), range.c
(range_hash), struct.c (rb_struct_hash), hash.c (rb_any_hash),
rational.c (nurat_hash): use Murmurhash. [ruby-dev:37784]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22317 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-02-14 22:55:34 +03:00
|
|
|
VALUE n;
|
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
* string.c (rb_hash_uint32, rb_hash_uint, rb_hash_start, rb_hash_end),
include/ruby/intern.h: add Murmurhash API. [ruby-dev:37784]
* complex.c (nucomp_hash), array.c (rb_ary_hash), time.c (time_hash),
string.c (rb_str_hsah), object.c (rb_obj_hash), range.c
(range_hash), struct.c (rb_struct_hash), hash.c (rb_any_hash),
rational.c (nurat_hash): use Murmurhash. [ruby-dev:37784]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22317 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-02-14 22:55:34 +03:00
|
|
|
n = rb_hash(dat->real);
|
2009-07-25 08:44:36 +04:00
|
|
|
h[0] = NUM2LONG(n);
|
* string.c (rb_hash_uint32, rb_hash_uint, rb_hash_start, rb_hash_end),
include/ruby/intern.h: add Murmurhash API. [ruby-dev:37784]
* complex.c (nucomp_hash), array.c (rb_ary_hash), time.c (time_hash),
string.c (rb_str_hsah), object.c (rb_obj_hash), range.c
(range_hash), struct.c (rb_struct_hash), hash.c (rb_any_hash),
rational.c (nurat_hash): use Murmurhash. [ruby-dev:37784]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22317 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-02-14 22:55:34 +03:00
|
|
|
n = rb_hash(dat->imag);
|
2009-07-25 08:44:36 +04:00
|
|
|
h[1] = NUM2LONG(n);
|
* string.c (rb_hash_uint32, rb_hash_uint, rb_hash_start, rb_hash_end),
include/ruby/intern.h: add Murmurhash API. [ruby-dev:37784]
* complex.c (nucomp_hash), array.c (rb_ary_hash), time.c (time_hash),
string.c (rb_str_hsah), object.c (rb_obj_hash), range.c
(range_hash), struct.c (rb_struct_hash), hash.c (rb_any_hash),
rational.c (nurat_hash): use Murmurhash. [ruby-dev:37784]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22317 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2009-02-14 22:55:34 +03:00
|
|
|
v = rb_memhash(h, sizeof(h));
|
2021-05-07 06:49:32 +03:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2023-12-24 18:26:20 +03:00
|
|
|
/*
|
|
|
|
* :call-seq:
|
|
|
|
* hash -> integer
|
|
|
|
*
|
|
|
|
* Returns the integer hash value for +self+.
|
|
|
|
*
|
|
|
|
* Two \Complex objects created from the same values will have the same hash value
|
|
|
|
* (and will compare using #eql?):
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 2).hash == Complex.rect(1, 2).hash # => true
|
2023-12-24 18:26:20 +03:00
|
|
|
*
|
|
|
|
*/
|
2021-05-07 06:49:32 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_hash(VALUE self)
|
|
|
|
{
|
|
|
|
return ST2FIX(rb_complex_hash(self));
|
2008-09-15 08:20:46 +04:00
|
|
|
}
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/* :nodoc: */
|
2008-09-15 08:20:46 +04:00
|
|
|
static VALUE
|
|
|
|
nucomp_eql_p(VALUE self, VALUE other)
|
|
|
|
{
|
2016-11-13 19:21:54 +03:00
|
|
|
if (RB_TYPE_P(other, T_COMPLEX)) {
|
2008-09-15 08:20:46 +04:00
|
|
|
get_dat2(self, other);
|
|
|
|
|
2021-08-17 20:25:19 +03:00
|
|
|
return RBOOL((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
|
2008-09-21 02:49:56 +04:00
|
|
|
(CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
|
2009-07-03 16:19:54 +04:00
|
|
|
f_eqeq_p(self, other));
|
2008-09-15 08:20:46 +04:00
|
|
|
|
|
|
|
}
|
|
|
|
return Qfalse;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2016-11-14 07:06:15 +03:00
|
|
|
inline static int
|
2008-03-16 03:23:43 +03:00
|
|
|
f_signbit(VALUE x)
|
|
|
|
{
|
2016-11-12 21:42:30 +03:00
|
|
|
if (RB_FLOAT_TYPE_P(x)) {
|
2009-02-15 20:39:38 +03:00
|
|
|
double f = RFLOAT_VALUE(x);
|
2016-11-14 07:06:15 +03:00
|
|
|
return !isnan(f) && signbit(f);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
return f_negative_p(x);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2016-11-14 07:06:15 +03:00
|
|
|
inline static int
|
2008-03-16 03:23:43 +03:00
|
|
|
f_tpositive_p(VALUE x)
|
|
|
|
{
|
2016-11-14 07:06:15 +03:00
|
|
|
return !f_signbit(x);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2009-06-28 04:22:07 +04:00
|
|
|
f_format(VALUE self, VALUE (*func)(VALUE))
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2016-11-14 07:06:15 +03:00
|
|
|
VALUE s;
|
|
|
|
int impos;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-09-21 02:49:56 +04:00
|
|
|
impos = f_tpositive_p(dat->imag);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-12-05 15:44:06 +03:00
|
|
|
s = (*func)(dat->real);
|
2008-08-22 16:27:54 +04:00
|
|
|
rb_str_cat2(s, !impos ? "-" : "+");
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-12-05 15:44:06 +03:00
|
|
|
rb_str_concat(s, (*func)(f_abs(dat->imag)));
|
2008-12-03 19:43:01 +03:00
|
|
|
if (!rb_isdigit(RSTRING_PTR(s)[RSTRING_LEN(s) - 1]))
|
|
|
|
rb_str_cat2(s, "*");
|
2008-08-22 16:27:54 +04:00
|
|
|
rb_str_cat2(s, "i");
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
return s;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 18:19:00 +03:00
|
|
|
* to_s -> string
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-19 18:19:00 +03:00
|
|
|
* Returns a string representation of +self+:
|
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* Complex.rect(2).to_s # => "2+0i"
|
|
|
|
* Complex.rect(-8, 6).to_s # => "-8+6i"
|
|
|
|
* Complex.rect(0, Rational(1, 2)).to_s # => "0+1/2i"
|
|
|
|
* Complex.rect(0, Float::INFINITY).to_s # => "0+Infinity*i"
|
|
|
|
* Complex.rect(Float::NAN, Float::NAN).to_s # => "NaN+NaN*i"
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-12-05 15:44:06 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_to_s(VALUE self)
|
|
|
|
{
|
2014-03-17 08:57:17 +04:00
|
|
|
return f_format(self, rb_String);
|
2008-12-05 15:44:06 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 18:19:00 +03:00
|
|
|
* inspect -> string
|
|
|
|
*
|
|
|
|
* Returns a string representation of +self+:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-25 20:13:44 +03:00
|
|
|
* Complex.rect(2).inspect # => "(2+0i)"
|
|
|
|
* Complex.rect(-8, 6).inspect # => "(-8+6i)"
|
|
|
|
* Complex.rect(0, Rational(1, 2)).inspect # => "(0+(1/2)*i)"
|
|
|
|
* Complex.rect(0, Float::INFINITY).inspect # => "(0+Infinity*i)"
|
|
|
|
* Complex.rect(Float::NAN, Float::NAN).inspect # => "(NaN+NaN*i)"
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_inspect(VALUE self)
|
|
|
|
{
|
2008-12-03 19:43:01 +03:00
|
|
|
VALUE s;
|
2008-08-22 16:27:54 +04:00
|
|
|
|
2008-12-13 07:05:25 +03:00
|
|
|
s = rb_usascii_str_new2("(");
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_str_concat(s, f_format(self, rb_inspect));
|
2008-12-03 19:43:01 +03:00
|
|
|
rb_str_cat2(s, ")");
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
return s;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2016-10-28 09:19:00 +03:00
|
|
|
#define FINITE_TYPE_P(v) (RB_INTEGER_TYPE_P(v) || RB_TYPE_P(v, T_RATIONAL))
|
|
|
|
|
2016-07-17 17:53:00 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 23:32:54 +03:00
|
|
|
* finite? -> true or false
|
2016-07-17 17:53:00 +03:00
|
|
|
*
|
2023-12-19 23:32:54 +03:00
|
|
|
* Returns +true+ if both <tt>self.real.finite?</tt> and <tt>self.imag.finite?</tt>
|
|
|
|
* are true, +false+ otherwise:
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 1).finite? # => true
|
|
|
|
* Complex.rect(Float::INFINITY, 0).finite? # => false
|
2023-12-19 23:32:54 +03:00
|
|
|
*
|
|
|
|
* Related: Numeric#finite?, Float#finite?.
|
2016-07-17 17:53:00 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
rb_complex_finite_p(VALUE self)
|
|
|
|
{
|
2017-09-27 05:38:51 +03:00
|
|
|
get_dat1(self);
|
2016-07-17 17:53:00 +03:00
|
|
|
|
2021-09-15 02:11:05 +03:00
|
|
|
return RBOOL(f_finite_p(dat->real) && f_finite_p(dat->imag));
|
2016-07-17 17:53:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-19 23:32:54 +03:00
|
|
|
* infinite? -> 1 or nil
|
2016-07-17 17:53:00 +03:00
|
|
|
*
|
2023-12-19 23:32:54 +03:00
|
|
|
* Returns +1+ if either <tt>self.real.infinite?</tt> or <tt>self.imag.infinite?</tt>
|
|
|
|
* is true, +nil+ otherwise:
|
2016-07-17 17:53:00 +03:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(Float::INFINITY, 0).infinite? # => 1
|
|
|
|
* Complex.rect(1, 1).infinite? # => nil
|
2016-07-17 17:53:00 +03:00
|
|
|
*
|
2023-12-19 23:32:54 +03:00
|
|
|
* Related: Numeric#infinite?, Float#infinite?.
|
2016-07-17 17:53:00 +03:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
rb_complex_infinite_p(VALUE self)
|
|
|
|
{
|
2017-09-27 05:55:03 +03:00
|
|
|
get_dat1(self);
|
2016-07-17 17:53:00 +03:00
|
|
|
|
2021-09-02 11:12:17 +03:00
|
|
|
if (!f_infinite_p(dat->real) && !f_infinite_p(dat->imag)) {
|
2016-07-17 17:53:00 +03:00
|
|
|
return Qnil;
|
2016-10-28 09:19:00 +03:00
|
|
|
}
|
2017-09-27 05:55:03 +03:00
|
|
|
return ONE;
|
2016-07-17 17:53:00 +03:00
|
|
|
}
|
|
|
|
|
2012-07-25 12:41:07 +04:00
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
nucomp_dumper(VALUE self)
|
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
nucomp_loader(VALUE self, VALUE a)
|
|
|
|
{
|
|
|
|
get_dat1(self);
|
|
|
|
|
2013-05-13 19:55:09 +04:00
|
|
|
RCOMPLEX_SET_REAL(dat, rb_ivar_get(a, id_i_real));
|
|
|
|
RCOMPLEX_SET_IMAG(dat, rb_ivar_get(a, id_i_imag));
|
2017-10-19 13:58:08 +03:00
|
|
|
OBJ_FREEZE_RAW(self);
|
2012-07-25 12:41:07 +04:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/* :nodoc: */
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_marshal_dump(VALUE self)
|
|
|
|
{
|
2008-09-16 14:21:23 +04:00
|
|
|
VALUE a;
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-09-16 14:21:23 +04:00
|
|
|
|
2008-09-21 02:49:56 +04:00
|
|
|
a = rb_assoc_new(dat->real, dat->imag);
|
2013-01-26 17:39:15 +04:00
|
|
|
rb_copy_generic_ivar(a, self);
|
2008-09-16 14:21:23 +04:00
|
|
|
return a;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-27 11:46:57 +04:00
|
|
|
/* :nodoc: */
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_marshal_load(VALUE self, VALUE a)
|
|
|
|
{
|
2010-08-05 13:36:16 +04:00
|
|
|
Check_Type(a, T_ARRAY);
|
2012-02-25 11:20:00 +04:00
|
|
|
if (RARRAY_LEN(a) != 2)
|
|
|
|
rb_raise(rb_eArgError, "marshaled complex must have an array whose length is 2 but %ld", RARRAY_LEN(a));
|
2013-05-13 13:56:22 +04:00
|
|
|
rb_ivar_set(self, id_i_real, RARRAY_AREF(a, 0));
|
|
|
|
rb_ivar_set(self, id_i_imag, RARRAY_AREF(a, 1));
|
2008-03-31 20:42:24 +04:00
|
|
|
return self;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_complex_raw(VALUE x, VALUE y)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new_internal(rb_cComplex, x, y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
|
|
|
rb_complex_new(VALUE x, VALUE y)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_canonicalize_internal(rb_cComplex, x, y);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2008-08-22 16:27:54 +04:00
|
|
|
VALUE
|
2018-12-12 14:06:47 +03:00
|
|
|
rb_complex_new_polar(VALUE x, VALUE y)
|
2008-08-22 16:27:54 +04:00
|
|
|
{
|
2009-07-05 17:46:10 +04:00
|
|
|
return f_complex_polar(rb_cComplex, x, y);
|
2008-08-22 16:27:54 +04:00
|
|
|
}
|
|
|
|
|
2018-12-12 14:06:47 +03:00
|
|
|
VALUE
|
|
|
|
rb_complex_polar(VALUE x, VALUE y)
|
|
|
|
{
|
|
|
|
return rb_complex_new_polar(x, y);
|
|
|
|
}
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
VALUE
|
|
|
|
rb_Complex(VALUE x, VALUE y)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
VALUE a[2];
|
|
|
|
a[0] = x;
|
|
|
|
a[1] = y;
|
|
|
|
return nucomp_s_convert(2, a, rb_cComplex);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2016-07-12 17:13:46 +03:00
|
|
|
VALUE
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_dbl_complex_new(double real, double imag)
|
2016-07-12 17:13:46 +03:00
|
|
|
{
|
2018-12-12 14:06:48 +03:00
|
|
|
return rb_complex_raw(DBL2NUM(real), DBL2NUM(imag));
|
2016-07-12 17:13:46 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-23 06:31:18 +03:00
|
|
|
* to_i -> integer
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-23 06:31:18 +03:00
|
|
|
* Returns the value of <tt>self.real</tt> as an Integer, if possible:
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 0).to_i # => 1
|
|
|
|
* Complex.rect(1, Rational(0, 1)).to_i # => 1
|
2023-12-23 06:31:18 +03:00
|
|
|
*
|
|
|
|
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
|
|
|
|
* (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_to_i(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2015-03-25 00:59:36 +03:00
|
|
|
if (!k_exact_zero_p(dat->imag)) {
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Integer",
|
|
|
|
self);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
return f_to_i(dat->real);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-23 06:31:18 +03:00
|
|
|
* to_f -> float
|
|
|
|
*
|
|
|
|
* Returns the value of <tt>self.real</tt> as a Float, if possible:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 0).to_f # => 1.0
|
|
|
|
* Complex.rect(1, Rational(0, 1)).to_f # => 1.0
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-23 06:31:18 +03:00
|
|
|
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
|
|
|
|
* (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_to_f(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2015-03-25 00:59:36 +03:00
|
|
|
if (!k_exact_zero_p(dat->imag)) {
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Float",
|
|
|
|
self);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
return f_to_f(dat->real);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-23 06:31:18 +03:00
|
|
|
* to_r -> rational
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-23 06:31:18 +03:00
|
|
|
* Returns the value of <tt>self.real</tt> as a Rational, if possible:
|
2012-11-03 18:39:50 +04:00
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 0).to_r # => (1/1)
|
|
|
|
* Complex.rect(1, Rational(0, 1)).to_r # => (1/1)
|
2012-11-10 14:29:13 +04:00
|
|
|
*
|
2023-12-23 06:31:18 +03:00
|
|
|
* Raises RangeError if <tt>self.imag</tt> is not exactly zero
|
|
|
|
* (either <tt>Integer(0)</tt> or <tt>Rational(0, _n_)</tt>).
|
|
|
|
*
|
|
|
|
* Related: Complex#rationalize.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_to_r(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
get_dat1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2015-03-25 00:59:36 +03:00
|
|
|
if (!k_exact_zero_p(dat->imag)) {
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
|
|
|
|
self);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
return f_to_r(dat->real);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2010-04-26 15:14:40 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-23 06:31:18 +03:00
|
|
|
* rationalize(epsilon = nil) -> rational
|
|
|
|
*
|
|
|
|
* Returns a Rational object whose value is exactly or approximately
|
|
|
|
* equivalent to that of <tt>self.real</tt>.
|
|
|
|
*
|
|
|
|
* With no argument +epsilon+ given, returns a \Rational object
|
|
|
|
* whose value is exactly equal to that of <tt>self.real.rationalize</tt>:
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(1, 0).rationalize # => (1/1)
|
|
|
|
* Complex.rect(1, Rational(0, 1)).rationalize # => (1/1)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize # => (314159/100000)
|
2023-12-23 06:31:18 +03:00
|
|
|
*
|
|
|
|
* With argument +epsilon+ given, returns a \Rational object
|
|
|
|
* whose value is exactly or approximately equal to that of <tt>self.real</tt>
|
|
|
|
* to the given precision:
|
|
|
|
*
|
2023-12-26 19:00:04 +03:00
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.1) # => (16/5)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.01) # => (22/7)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.001) # => (201/64)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.0001) # => (333/106)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.00001) # => (355/113)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.000001) # => (7433/2366)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.0000001) # => (9208/2931)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.00000001) # => (47460/15107)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.000000001) # => (76149/24239)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.0000000001) # => (314159/100000)
|
|
|
|
* Complex.rect(3.14159, 0).rationalize(0.0) # => (3537115888337719/1125899906842624)
|
2023-12-23 06:31:18 +03:00
|
|
|
*
|
|
|
|
* Related: Complex#to_r.
|
2010-04-26 15:14:40 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
nucomp_rationalize(int argc, VALUE *argv, VALUE self)
|
|
|
|
{
|
2011-08-10 14:35:08 +04:00
|
|
|
get_dat1(self);
|
|
|
|
|
2018-12-04 05:24:15 +03:00
|
|
|
rb_check_arity(argc, 0, 1);
|
2011-08-10 14:35:08 +04:00
|
|
|
|
2015-03-25 00:59:36 +03:00
|
|
|
if (!k_exact_zero_p(dat->imag)) {
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_raise(rb_eRangeError, "can't convert %"PRIsVALUE" into Rational",
|
|
|
|
self);
|
2011-08-10 14:35:08 +04:00
|
|
|
}
|
2016-10-28 09:20:19 +03:00
|
|
|
return rb_funcallv(dat->real, id_rationalize, argc, argv);
|
2010-04-26 15:14:40 +04:00
|
|
|
}
|
|
|
|
|
2012-11-21 16:54:06 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-23 06:31:18 +03:00
|
|
|
* to_c -> self
|
2012-11-21 16:54:06 +04:00
|
|
|
*
|
2023-12-23 06:31:18 +03:00
|
|
|
* Returns +self+.
|
2012-11-21 16:54:06 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
nucomp_to_c(VALUE self)
|
|
|
|
{
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-03-13 19:55:59 +03:00
|
|
|
* to_c -> (0+0i)
|
|
|
|
*
|
|
|
|
* Returns zero as a Complex:
|
|
|
|
*
|
|
|
|
* nil.to_c # => (0+0i)
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
nilclass_to_c(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return rb_complex_new1(INT2FIX(0));
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* to_c -> complex
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns +self+ as a Complex object.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
numeric_to_c(VALUE self)
|
|
|
|
{
|
2008-03-31 20:42:24 +04:00
|
|
|
return rb_complex_new1(self);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static int
|
|
|
|
issign(int c)
|
|
|
|
{
|
|
|
|
return (c == '-' || c == '+');
|
|
|
|
}
|
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_sign(const char **s,
|
|
|
|
char **b)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2012-11-17 19:19:55 +04:00
|
|
|
int sign = '?';
|
2008-06-09 09:42:04 +04:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
if (issign(**s)) {
|
2012-11-17 19:19:55 +04:00
|
|
|
sign = **b = **s;
|
|
|
|
(*s)++;
|
|
|
|
(*b)++;
|
|
|
|
}
|
|
|
|
return sign;
|
|
|
|
}
|
2008-08-22 16:27:54 +04:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static int
|
|
|
|
isdecimal(int c)
|
|
|
|
{
|
|
|
|
return isdigit((unsigned char)c);
|
|
|
|
}
|
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_digits(const char **s, int strict,
|
|
|
|
char **b)
|
|
|
|
{
|
|
|
|
int us = 1;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
if (!isdecimal(**s))
|
2012-11-17 19:19:55 +04:00
|
|
|
return 0;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
while (isdecimal(**s) || **s == '_') {
|
2012-11-17 19:19:55 +04:00
|
|
|
if (**s == '_') {
|
2022-10-28 13:28:17 +03:00
|
|
|
if (us) {
|
|
|
|
if (strict) return 0;
|
|
|
|
break;
|
2012-11-17 19:19:55 +04:00
|
|
|
}
|
|
|
|
us = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
**b = **s;
|
|
|
|
(*b)++;
|
|
|
|
us = 0;
|
|
|
|
}
|
|
|
|
(*s)++;
|
|
|
|
}
|
|
|
|
if (us)
|
|
|
|
do {
|
|
|
|
(*s)--;
|
|
|
|
} while (**s == '_');
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static int
|
|
|
|
islettere(int c)
|
|
|
|
{
|
|
|
|
return (c == 'e' || c == 'E');
|
|
|
|
}
|
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_num(const char **s, int strict,
|
|
|
|
char **b)
|
|
|
|
{
|
|
|
|
if (**s != '.') {
|
|
|
|
if (!read_digits(s, strict, b))
|
|
|
|
return 0;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
if (**s == '.') {
|
|
|
|
**b = **s;
|
|
|
|
(*s)++;
|
|
|
|
(*b)++;
|
|
|
|
if (!read_digits(s, strict, b)) {
|
|
|
|
(*b)--;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
if (islettere(**s)) {
|
2012-11-17 19:19:55 +04:00
|
|
|
**b = **s;
|
|
|
|
(*s)++;
|
|
|
|
(*b)++;
|
|
|
|
read_sign(s, b);
|
|
|
|
if (!read_digits(s, strict, b)) {
|
|
|
|
(*b)--;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static int
|
2012-11-17 19:19:55 +04:00
|
|
|
read_den(const char **s, int strict,
|
|
|
|
char **b)
|
|
|
|
{
|
|
|
|
if (!read_digits(s, strict, b))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_rat_nos(const char **s, int strict,
|
|
|
|
char **b)
|
|
|
|
{
|
|
|
|
if (!read_num(s, strict, b))
|
|
|
|
return 0;
|
|
|
|
if (**s == '/') {
|
|
|
|
**b = **s;
|
|
|
|
(*s)++;
|
|
|
|
(*b)++;
|
|
|
|
if (!read_den(s, strict, b)) {
|
|
|
|
(*b)--;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2008-03-19 12:37:39 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_rat(const char **s, int strict,
|
|
|
|
char **b)
|
|
|
|
{
|
|
|
|
read_sign(s, b);
|
|
|
|
if (!read_rat_nos(s, strict, b))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static int
|
2012-11-17 19:19:55 +04:00
|
|
|
isimagunit(int c)
|
|
|
|
{
|
|
|
|
return (c == 'i' || c == 'I' ||
|
|
|
|
c == 'j' || c == 'J');
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
|
|
|
static VALUE
|
2012-11-17 19:19:55 +04:00
|
|
|
str2num(char *s)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2012-11-17 19:19:55 +04:00
|
|
|
if (strchr(s, '/'))
|
|
|
|
return rb_cstr_to_rat(s, 0);
|
2012-11-18 04:26:15 +04:00
|
|
|
if (strpbrk(s, ".eE"))
|
|
|
|
return DBL2NUM(rb_cstr_to_dbl(s, 0));
|
2012-11-17 19:19:55 +04:00
|
|
|
return rb_cstr_to_inum(s, 10, 0);
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
|
|
|
read_comp(const char **s, int strict,
|
|
|
|
VALUE *ret, char **b)
|
|
|
|
{
|
|
|
|
char *bb;
|
|
|
|
int sign;
|
|
|
|
VALUE num, num2;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
bb = *b;
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
sign = read_sign(s, b);
|
|
|
|
|
|
|
|
if (isimagunit(**s)) {
|
|
|
|
(*s)++;
|
|
|
|
num = INT2FIX((sign == '-') ? -1 : + 1);
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(ZERO, num);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 1; /* e.g. "i" */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!read_rat_nos(s, strict, b)) {
|
|
|
|
**b = '\0';
|
|
|
|
num = str2num(bb);
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, ZERO);
|
2012-11-20 16:10:08 +04:00
|
|
|
return 0; /* e.g. "-" */
|
2012-11-17 19:19:55 +04:00
|
|
|
}
|
|
|
|
**b = '\0';
|
|
|
|
num = str2num(bb);
|
|
|
|
|
|
|
|
if (isimagunit(**s)) {
|
|
|
|
(*s)++;
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(ZERO, num);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 1; /* e.g. "3i" */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (**s == '@') {
|
2012-11-17 19:51:55 +04:00
|
|
|
int st;
|
2022-07-21 19:23:58 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
(*s)++;
|
|
|
|
bb = *b;
|
2012-11-17 21:03:52 +04:00
|
|
|
st = read_rat(s, strict, b);
|
|
|
|
**b = '\0';
|
|
|
|
if (strlen(bb) < 1 ||
|
2012-11-20 16:10:08 +04:00
|
|
|
!isdecimal(*(bb + strlen(bb) - 1))) {
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, ZERO);
|
2012-11-20 16:10:08 +04:00
|
|
|
return 0; /* e.g. "1@-" */
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
2012-11-17 19:19:55 +04:00
|
|
|
num2 = str2num(bb);
|
2018-12-12 14:06:47 +03:00
|
|
|
*ret = rb_complex_new_polar(num, num2);
|
2012-11-17 19:51:55 +04:00
|
|
|
if (!st)
|
|
|
|
return 0; /* e.g. "1@2." */
|
|
|
|
else
|
|
|
|
return 1; /* e.g. "1@2" */
|
2012-11-17 19:19:55 +04:00
|
|
|
}
|
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
if (issign(**s)) {
|
2012-11-17 19:19:55 +04:00
|
|
|
bb = *b;
|
|
|
|
sign = read_sign(s, b);
|
|
|
|
if (isimagunit(**s))
|
|
|
|
num2 = INT2FIX((sign == '-') ? -1 : + 1);
|
|
|
|
else {
|
|
|
|
if (!read_rat_nos(s, strict, b)) {
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, ZERO);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 0; /* e.g. "1+xi" */
|
2008-06-09 16:02:29 +04:00
|
|
|
}
|
2012-11-17 19:19:55 +04:00
|
|
|
**b = '\0';
|
|
|
|
num2 = str2num(bb);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
2012-11-17 19:19:55 +04:00
|
|
|
if (!isimagunit(**s)) {
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, ZERO);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 0; /* e.g. "1+3x" */
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
2012-11-17 19:19:55 +04:00
|
|
|
(*s)++;
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, num2);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 1; /* e.g. "1+2i" */
|
|
|
|
}
|
|
|
|
/* !(@, - or +) */
|
|
|
|
{
|
2012-11-18 04:35:06 +04:00
|
|
|
*ret = rb_complex_new2(num, ZERO);
|
2012-11-17 19:19:55 +04:00
|
|
|
return 1; /* e.g. "3" */
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-20 16:10:08 +04:00
|
|
|
inline static void
|
2012-11-18 04:26:15 +04:00
|
|
|
skip_ws(const char **s)
|
|
|
|
{
|
|
|
|
while (isspace((unsigned char)**s))
|
|
|
|
(*s)++;
|
|
|
|
}
|
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
static int
|
2018-03-15 10:19:48 +03:00
|
|
|
parse_comp(const char *s, int strict, VALUE *num)
|
2012-11-17 19:19:55 +04:00
|
|
|
{
|
|
|
|
char *buf, *b;
|
2014-05-02 23:21:18 +04:00
|
|
|
VALUE tmp;
|
|
|
|
int ret = 1;
|
2012-11-17 19:19:55 +04:00
|
|
|
|
2014-05-02 23:21:18 +04:00
|
|
|
buf = ALLOCV_N(char, tmp, strlen(s) + 1);
|
2012-11-17 19:19:55 +04:00
|
|
|
b = buf;
|
|
|
|
|
2012-11-18 04:26:15 +04:00
|
|
|
skip_ws(&s);
|
2014-05-02 23:21:18 +04:00
|
|
|
if (!read_comp(&s, strict, num, &b)) {
|
2018-03-15 10:19:48 +03:00
|
|
|
ret = 0;
|
2014-05-02 23:21:18 +04:00
|
|
|
}
|
|
|
|
else {
|
2018-03-15 10:19:48 +03:00
|
|
|
skip_ws(&s);
|
2012-11-17 19:19:55 +04:00
|
|
|
|
2018-03-15 10:19:48 +03:00
|
|
|
if (strict)
|
|
|
|
if (*s != '\0')
|
|
|
|
ret = 0;
|
2014-05-02 23:21:18 +04:00
|
|
|
}
|
|
|
|
ALLOCV_END(tmp);
|
|
|
|
|
|
|
|
return ret;
|
2012-11-17 19:19:55 +04:00
|
|
|
}
|
|
|
|
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
2018-03-15 10:19:48 +03:00
|
|
|
string_to_c_strict(VALUE self, int raise)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2012-11-22 15:32:52 +04:00
|
|
|
char *s;
|
2012-11-17 19:19:55 +04:00
|
|
|
VALUE num;
|
|
|
|
|
|
|
|
rb_must_asciicompat(self);
|
|
|
|
|
2023-12-11 09:48:51 +03:00
|
|
|
if (raise) {
|
|
|
|
s = StringValueCStr(self);
|
2018-03-15 10:19:48 +03:00
|
|
|
}
|
2023-12-11 09:48:51 +03:00
|
|
|
else if (!(s = rb_str_to_cstr(self))) {
|
|
|
|
return Qnil;
|
2012-11-22 15:32:52 +04:00
|
|
|
}
|
|
|
|
|
2023-12-11 09:48:51 +03:00
|
|
|
if (!parse_comp(s, TRUE, &num)) {
|
2018-03-15 10:19:48 +03:00
|
|
|
if (!raise) return Qnil;
|
2014-03-17 08:57:17 +04:00
|
|
|
rb_raise(rb_eArgError, "invalid value for convert(): %+"PRIsVALUE,
|
|
|
|
self);
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
return num;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2009-06-20 01:57:51 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* to_c -> complex
|
|
|
|
*
|
|
|
|
* Returns +self+ interpreted as a Complex object;
|
|
|
|
* leading whitespace and trailing garbage are ignored:
|
|
|
|
*
|
|
|
|
* '9'.to_c # => (9+0i)
|
|
|
|
* '2.5'.to_c # => (2.5+0i)
|
|
|
|
* '2.5/1'.to_c # => ((5/2)+0i)
|
|
|
|
* '-3/2'.to_c # => ((-3/2)+0i)
|
|
|
|
* '-i'.to_c # => (0-1i)
|
|
|
|
* '45i'.to_c # => (0+45i)
|
|
|
|
* '3-4i'.to_c # => (3-4i)
|
|
|
|
* '-4e2-4e-2i'.to_c # => (-400.0-0.04i)
|
|
|
|
* '-0.0-0.0i'.to_c # => (-0.0-0.0i)
|
|
|
|
* '1/2+3/4i'.to_c # => ((1/2)+(3/4)*i)
|
|
|
|
* '1.0@0'.to_c # => (1+0.0i)
|
|
|
|
* "1.0@#{Math::PI/2}".to_c # => (0.0+1i)
|
|
|
|
* "1.0@#{Math::PI}".to_c # => (-1+0.0i)
|
|
|
|
*
|
|
|
|
* Returns \Complex zero if the string cannot be converted:
|
|
|
|
*
|
|
|
|
* 'ruby'.to_c # => (0+0i)
|
|
|
|
*
|
|
|
|
* See Kernel#Complex.
|
2009-06-20 01:57:51 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
string_to_c(VALUE self)
|
|
|
|
{
|
2012-11-17 19:19:55 +04:00
|
|
|
VALUE num;
|
2008-06-13 16:29:50 +04:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
rb_must_asciicompat(self);
|
2008-06-13 16:29:50 +04:00
|
|
|
|
2023-12-11 09:48:51 +03:00
|
|
|
(void)parse_comp(rb_str_fill_terminator(self, 1), FALSE, &num);
|
2008-06-13 16:29:50 +04:00
|
|
|
|
2012-11-17 19:19:55 +04:00
|
|
|
return num;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2018-03-15 10:19:48 +03:00
|
|
|
to_complex(VALUE val)
|
2008-03-16 03:23:43 +03:00
|
|
|
{
|
2018-03-15 10:19:48 +03:00
|
|
|
return rb_convert_type(val, T_COMPLEX, "Complex", "to_c");
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2018-03-15 10:19:48 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_convert(VALUE klass, VALUE a1, VALUE a2, int raise)
|
|
|
|
{
|
2019-01-12 08:02:58 +03:00
|
|
|
if (NIL_P(a1) || NIL_P(a2)) {
|
|
|
|
if (!raise) return Qnil;
|
2009-06-18 17:41:44 +04:00
|
|
|
rb_raise(rb_eTypeError, "can't convert nil into Complex");
|
2019-01-12 08:02:58 +03:00
|
|
|
}
|
2009-06-18 17:41:44 +04:00
|
|
|
|
2013-09-09 09:17:13 +04:00
|
|
|
if (RB_TYPE_P(a1, T_STRING)) {
|
2018-03-15 10:19:48 +03:00
|
|
|
a1 = string_to_c_strict(a1, raise);
|
|
|
|
if (NIL_P(a1)) return Qnil;
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2013-09-09 09:17:13 +04:00
|
|
|
if (RB_TYPE_P(a2, T_STRING)) {
|
2018-03-15 10:19:48 +03:00
|
|
|
a2 = string_to_c_strict(a2, raise);
|
|
|
|
if (NIL_P(a2)) return Qnil;
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
|
2013-09-09 09:17:13 +04:00
|
|
|
if (RB_TYPE_P(a1, T_COMPLEX)) {
|
2008-04-22 17:17:04 +04:00
|
|
|
{
|
|
|
|
get_dat1(a1);
|
2008-03-31 20:42:24 +04:00
|
|
|
|
2009-07-12 16:09:21 +04:00
|
|
|
if (k_exact_zero_p(dat->imag))
|
2008-04-22 17:17:04 +04:00
|
|
|
a1 = dat->real;
|
|
|
|
}
|
2008-03-31 20:42:24 +04:00
|
|
|
}
|
|
|
|
|
2013-09-09 09:17:13 +04:00
|
|
|
if (RB_TYPE_P(a2, T_COMPLEX)) {
|
2008-04-22 17:17:04 +04:00
|
|
|
{
|
|
|
|
get_dat1(a2);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2009-07-12 16:09:21 +04:00
|
|
|
if (k_exact_zero_p(dat->imag))
|
2008-04-22 17:17:04 +04:00
|
|
|
a2 = dat->real;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2013-09-09 09:17:13 +04:00
|
|
|
if (RB_TYPE_P(a1, T_COMPLEX)) {
|
2022-11-15 07:24:08 +03:00
|
|
|
if (UNDEF_P(a2) || (k_exact_zero_p(a2)))
|
2008-03-31 20:42:24 +04:00
|
|
|
return a1;
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2022-11-15 07:24:08 +03:00
|
|
|
if (UNDEF_P(a2)) {
|
2008-09-21 05:30:25 +04:00
|
|
|
if (k_numeric_p(a1) && !f_real_p(a1))
|
|
|
|
return a1;
|
2010-11-23 17:28:55 +03:00
|
|
|
/* should raise exception for consistency */
|
2018-03-15 10:19:48 +03:00
|
|
|
if (!k_numeric_p(a1)) {
|
|
|
|
if (!raise)
|
|
|
|
return rb_protect(to_complex, a1, NULL);
|
|
|
|
return to_complex(a1);
|
|
|
|
}
|
2008-09-21 05:30:25 +04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((k_numeric_p(a1) && k_numeric_p(a2)) &&
|
|
|
|
(!f_real_p(a1) || !f_real_p(a2)))
|
|
|
|
return f_add(a1,
|
|
|
|
f_mul(a2,
|
|
|
|
f_complex_new_bang2(rb_cComplex, ZERO, ONE)));
|
|
|
|
}
|
2008-09-17 15:00:09 +04:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
{
|
2018-03-15 10:19:48 +03:00
|
|
|
int argc;
|
2008-03-31 20:42:24 +04:00
|
|
|
VALUE argv2[2];
|
|
|
|
argv2[0] = a1;
|
2022-11-15 07:24:08 +03:00
|
|
|
if (UNDEF_P(a2)) {
|
2018-03-15 10:19:48 +03:00
|
|
|
argv2[1] = Qnil;
|
|
|
|
argc = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!raise && !RB_INTEGER_TYPE_P(a2) && !RB_FLOAT_TYPE_P(a2) && !RB_TYPE_P(a2, T_RATIONAL))
|
|
|
|
return Qnil;
|
|
|
|
argv2[1] = a2;
|
|
|
|
argc = 2;
|
|
|
|
}
|
2008-03-31 20:42:24 +04:00
|
|
|
return nucomp_s_new(argc, argv2, klass);
|
|
|
|
}
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2018-03-15 10:19:48 +03:00
|
|
|
static VALUE
|
|
|
|
nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
|
|
|
|
{
|
|
|
|
VALUE a1, a2;
|
|
|
|
|
|
|
|
if (rb_scan_args(argc, argv, "11", &a1, &a2) == 1) {
|
|
|
|
a2 = Qundef;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nucomp_convert(klass, a1, a2, TRUE);
|
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* abs2 -> real
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns the square of +self+.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-08-31 15:51:04 +04:00
|
|
|
static VALUE
|
|
|
|
numeric_abs2(VALUE self)
|
|
|
|
{
|
|
|
|
return f_mul(self, self);
|
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* arg -> 0 or Math::PI
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns zero if +self+ is positive, Math::PI otherwise.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
numeric_arg(VALUE self)
|
|
|
|
{
|
2008-09-21 16:21:32 +04:00
|
|
|
if (f_positive_p(self))
|
2016-11-16 07:25:35 +03:00
|
|
|
return INT2FIX(0);
|
|
|
|
return DBL2NUM(M_PI);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* rect -> array
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns array <tt>[self, 0]</tt>.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-08-29 17:41:41 +04:00
|
|
|
static VALUE
|
|
|
|
numeric_rect(VALUE self)
|
|
|
|
{
|
2008-09-19 17:55:52 +04:00
|
|
|
return rb_assoc_new(self, INT2FIX(0));
|
2008-08-29 17:41:41 +04:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* polar -> array
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns array <tt>[self.abs, self.arg]</tt>.
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
static VALUE
|
|
|
|
numeric_polar(VALUE self)
|
|
|
|
{
|
2016-11-16 07:25:35 +03:00
|
|
|
VALUE abs, arg;
|
|
|
|
|
|
|
|
if (RB_INTEGER_TYPE_P(self)) {
|
|
|
|
abs = rb_int_abs(self);
|
|
|
|
arg = numeric_arg(self);
|
|
|
|
}
|
|
|
|
else if (RB_FLOAT_TYPE_P(self)) {
|
|
|
|
abs = rb_float_abs(self);
|
|
|
|
arg = float_arg(self);
|
|
|
|
}
|
|
|
|
else if (RB_TYPE_P(self, T_RATIONAL)) {
|
|
|
|
abs = rb_rational_abs(self);
|
|
|
|
arg = numeric_arg(self);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
abs = f_abs(self);
|
|
|
|
arg = f_arg(self);
|
|
|
|
}
|
|
|
|
return rb_assoc_new(abs, arg);
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|
|
|
|
|
2009-07-03 14:50:17 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2023-12-24 22:26:07 +03:00
|
|
|
* arg -> 0 or Math::PI
|
2009-07-03 14:50:17 +04:00
|
|
|
*
|
2023-12-24 22:26:07 +03:00
|
|
|
* Returns 0 if +self+ is positive, Math::PI otherwise.
|
2009-07-03 14:50:17 +04:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
float_arg(VALUE self)
|
|
|
|
{
|
|
|
|
if (isnan(RFLOAT_VALUE(self)))
|
|
|
|
return self;
|
2009-07-05 15:44:34 +04:00
|
|
|
if (f_tpositive_p(self))
|
|
|
|
return INT2FIX(0);
|
|
|
|
return rb_const_get(rb_mMath, id_PI);
|
2009-07-03 14:50:17 +04:00
|
|
|
}
|
|
|
|
|
2009-06-19 22:35:39 +04:00
|
|
|
/*
|
2023-12-10 18:22:22 +03:00
|
|
|
* A \Complex object houses a pair of values,
|
|
|
|
* given when the object is created as either <i>rectangular coordinates</i>
|
|
|
|
* or <i>polar coordinates</i>.
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* == Rectangular Coordinates
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* The rectangular coordinates of a complex number
|
|
|
|
* are called the _real_ and _imaginary_ parts;
|
|
|
|
* see {Complex number definition}[https://en.wikipedia.org/wiki/Complex_number#Definition].
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* You can create a \Complex object from rectangular coordinates with:
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* - A {complex literal}[rdoc-ref:doc/syntax/literals.rdoc@Complex+Literals].
|
|
|
|
* - \Method Complex.rect.
|
|
|
|
* - \Method Kernel#Complex, either with numeric arguments or with certain string arguments.
|
|
|
|
* - \Method String#to_c, for certain strings.
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* Note that each of the stored parts may be a an instance one of the classes
|
|
|
|
* Complex, Float, Integer, or Rational;
|
|
|
|
* they may be retrieved:
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
|
|
|
* - Separately, with methods Complex#real and Complex#imaginary.
|
|
|
|
* - Together, with method Complex#rect.
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* The corresponding (computed) polar values may be retrieved:
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* - Separately, with methods Complex#abs and Complex#arg.
|
|
|
|
* - Together, with method Complex#polar.
|
2021-12-03 16:12:28 +03:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* == Polar Coordinates
|
2009-06-27 11:46:57 +04:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* The polar coordinates of a complex number
|
|
|
|
* are called the _absolute_ and _argument_ parts;
|
|
|
|
* see {Complex polar plane}[https://en.wikipedia.org/wiki/Complex_number#Polar_complex_plane].
|
|
|
|
*
|
2023-12-15 17:39:12 +03:00
|
|
|
* In this class, the argument part
|
|
|
|
* in expressed {radians}[https://en.wikipedia.org/wiki/Radian]
|
|
|
|
* (not {degrees}[https://en.wikipedia.org/wiki/Degree_(angle)]).
|
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* You can create a \Complex object from polar coordinates with:
|
|
|
|
*
|
|
|
|
* - \Method Complex.polar.
|
|
|
|
* - \Method Kernel#Complex, with certain string arguments.
|
|
|
|
* - \Method String#to_c, for certain strings.
|
2009-06-27 11:46:57 +04:00
|
|
|
*
|
2023-12-10 18:22:22 +03:00
|
|
|
* Note that each of the stored parts may be a an instance one of the classes
|
|
|
|
* Complex, Float, Integer, or Rational;
|
|
|
|
* they may be retrieved:
|
2009-06-27 11:46:57 +04:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* - Separately, with methods Complex#abs and Complex#arg.
|
|
|
|
* - Together, with method Complex#polar.
|
2009-06-27 11:46:57 +04:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* The corresponding (computed) rectangular values may be retrieved:
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-07 23:36:37 +03:00
|
|
|
* - Separately, with methods Complex#real and Complex#imag.
|
|
|
|
* - Together, with method Complex#rect.
|
2009-06-19 22:35:39 +04:00
|
|
|
*
|
2023-12-28 17:33:06 +03:00
|
|
|
* == What's Here
|
|
|
|
*
|
|
|
|
* First, what's elsewhere:
|
|
|
|
*
|
|
|
|
* - \Class \Complex inherits (directly or indirectly)
|
|
|
|
* from classes {Numeric}[rdoc-ref:Numeric@What-27s+Here]
|
|
|
|
* and {Object}[rdoc-ref:Object@What-27s+Here].
|
|
|
|
* - Includes (indirectly) module {Comparable}[rdoc-ref:Comparable@What-27s+Here].
|
|
|
|
*
|
|
|
|
* Here, class \Complex has methods for:
|
|
|
|
*
|
|
|
|
* === Creating \Complex Objects
|
|
|
|
*
|
|
|
|
* - ::polar: Returns a new \Complex object based on given polar coordinates.
|
|
|
|
* - ::rect (and its alias ::rectangular):
|
|
|
|
* Returns a new \Complex object based on given rectangular coordinates.
|
|
|
|
*
|
|
|
|
* === Querying
|
|
|
|
*
|
|
|
|
* - #abs (and its alias #magnitude): Returns the absolute value for +self+.
|
|
|
|
* - #arg (and its aliases #angle and #phase):
|
|
|
|
* Returns the argument (angle) for +self+ in radians.
|
|
|
|
* - #denominator: Returns the denominator of +self+.
|
|
|
|
* - #finite?: Returns whether both +self.real+ and +self.image+ are finite.
|
|
|
|
* - #hash: Returns the integer hash value for +self+.
|
|
|
|
* - #imag (and its alias #imaginary): Returns the imaginary value for +self+.
|
|
|
|
* - #infinite?: Returns whether +self.real+ or +self.image+ is infinite.
|
|
|
|
* - #numerator: Returns the numerator of +self+.
|
|
|
|
* - #polar: Returns the array <tt>[self.abs, self.arg]</tt>.
|
|
|
|
* - #inspect: Returns a string representation of +self+.
|
|
|
|
* - #real: Returns the real value for +self+.
|
|
|
|
* - #real?: Returns +false+; for compatibility with Numeric#real?.
|
|
|
|
* - #rect (and its alias #rectangular):
|
|
|
|
* Returns the array <tt>[self.real, self.imag]</tt>.
|
|
|
|
*
|
|
|
|
* === Comparing
|
|
|
|
*
|
|
|
|
* - #<=>: Returns whether +self+ is less than, equal to, or greater than the given argument.
|
|
|
|
* - #==: Returns whether +self+ is equal to the given argument.
|
|
|
|
*
|
|
|
|
* === Converting
|
|
|
|
*
|
|
|
|
* - #rationalize: Returns a Rational object whose value is exactly
|
|
|
|
* or approximately equivalent to that of <tt>self.real</tt>.
|
|
|
|
* - #to_c: Returns +self+.
|
|
|
|
* - #to_d: Returns the value as a BigDecimal object.
|
|
|
|
* - #to_f: Returns the value of <tt>self.real</tt> as a Float, if possible.
|
|
|
|
* - #to_i: Returns the value of <tt>self.real</tt> as an Integer, if possible.
|
|
|
|
* - #to_r: Returns the value of <tt>self.real</tt> as a Rational, if possible.
|
|
|
|
* - #to_s: Returns a string representation of +self+.
|
|
|
|
*
|
|
|
|
* === Performing Complex Arithmetic
|
|
|
|
*
|
|
|
|
* - #*: Returns the product of +self+ and the given numeric.
|
|
|
|
* - #**: Returns +self+ raised to power of the given numeric.
|
|
|
|
* - #+: Returns the sum of +self+ and the given numeric.
|
|
|
|
* - #-: Returns the difference of +self+ and the given numeric.
|
|
|
|
* - #-@: Returns the negation of +self+.
|
|
|
|
* - #/: Returns the quotient of +self+ and the given numeric.
|
|
|
|
* - #abs2: Returns square of the absolute value (magnitude) for +self+.
|
|
|
|
* - #conj (and its alias #conjugate): Returns the conjugate of +self+.
|
|
|
|
* - #fdiv: Returns <tt>Complex.rect(self.real/numeric, self.imag/numeric)</tt>.
|
|
|
|
*
|
|
|
|
* === Working with JSON
|
|
|
|
*
|
|
|
|
* - ::json_create: Returns a new \Complex object,
|
|
|
|
* deserialized from the given serialized hash.
|
|
|
|
* - #as_json: Returns a serialized hash constructed from +self+.
|
|
|
|
* - #to_json: Returns a JSON string representing +self+.
|
|
|
|
*
|
|
|
|
* These methods are provided by the {JSON gem}[https://github.com/flori/json]. To make these methods available:
|
|
|
|
*
|
|
|
|
* require 'json/add/complex'
|
|
|
|
*
|
2009-06-19 22:35:39 +04:00
|
|
|
*/
|
2008-03-16 03:23:43 +03:00
|
|
|
void
|
|
|
|
Init_Complex(void)
|
|
|
|
{
|
2012-07-25 12:41:07 +04:00
|
|
|
VALUE compat;
|
2020-09-25 20:56:30 +03:00
|
|
|
id_abs = rb_intern_const("abs");
|
|
|
|
id_arg = rb_intern_const("arg");
|
|
|
|
id_denominator = rb_intern_const("denominator");
|
|
|
|
id_numerator = rb_intern_const("numerator");
|
|
|
|
id_real_p = rb_intern_const("real?");
|
|
|
|
id_i_real = rb_intern_const("@real");
|
|
|
|
id_i_imag = rb_intern_const("@image"); /* @image, not @imag */
|
|
|
|
id_finite_p = rb_intern_const("finite?");
|
|
|
|
id_infinite_p = rb_intern_const("infinite?");
|
|
|
|
id_rationalize = rb_intern_const("rationalize");
|
|
|
|
id_PI = rb_intern_const("PI");
|
2008-03-31 20:42:24 +04:00
|
|
|
|
2009-06-19 15:47:53 +04:00
|
|
|
rb_cComplex = rb_define_class("Complex", rb_cNumeric);
|
2008-03-31 20:42:24 +04:00
|
|
|
|
|
|
|
rb_define_alloc_func(rb_cComplex, nucomp_s_alloc);
|
2008-09-24 12:44:47 +04:00
|
|
|
rb_undef_method(CLASS_OF(rb_cComplex), "allocate");
|
2008-03-31 20:42:24 +04:00
|
|
|
|
2008-09-23 14:33:27 +04:00
|
|
|
rb_undef_method(CLASS_OF(rb_cComplex), "new");
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_singleton_method(rb_cComplex, "rectangular", nucomp_s_new, -1);
|
2008-08-29 17:41:41 +04:00
|
|
|
rb_define_singleton_method(rb_cComplex, "rect", nucomp_s_new, -1);
|
2009-07-05 17:46:10 +04:00
|
|
|
rb_define_singleton_method(rb_cComplex, "polar", nucomp_s_polar, -1);
|
2008-03-31 20:42:24 +04:00
|
|
|
|
2009-06-19 15:47:53 +04:00
|
|
|
rb_define_global_function("Complex", nucomp_f_complex, -1);
|
2008-03-31 20:42:24 +04:00
|
|
|
|
Ensure origins for all included, prepended, and refined modules
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
2020-05-24 06:16:27 +03:00
|
|
|
rb_undef_methods_from(rb_cComplex, RCLASS_ORIGIN(rb_mComparable));
|
2009-07-03 14:50:17 +04:00
|
|
|
rb_undef_method(rb_cComplex, "%");
|
|
|
|
rb_undef_method(rb_cComplex, "div");
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_undef_method(rb_cComplex, "divmod");
|
|
|
|
rb_undef_method(rb_cComplex, "floor");
|
|
|
|
rb_undef_method(rb_cComplex, "ceil");
|
|
|
|
rb_undef_method(rb_cComplex, "modulo");
|
2009-07-03 14:50:17 +04:00
|
|
|
rb_undef_method(rb_cComplex, "remainder");
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_undef_method(rb_cComplex, "round");
|
|
|
|
rb_undef_method(rb_cComplex, "step");
|
|
|
|
rb_undef_method(rb_cComplex, "truncate");
|
2009-08-17 02:28:48 +04:00
|
|
|
rb_undef_method(rb_cComplex, "i");
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "real", rb_complex_real, 0);
|
|
|
|
rb_define_method(rb_cComplex, "imaginary", rb_complex_imag, 0);
|
|
|
|
rb_define_method(rb_cComplex, "imag", rb_complex_imag, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "-@", rb_complex_uminus, 0);
|
2016-11-13 19:21:54 +03:00
|
|
|
rb_define_method(rb_cComplex, "+", rb_complex_plus, 1);
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "-", rb_complex_minus, 1);
|
|
|
|
rb_define_method(rb_cComplex, "*", rb_complex_mul, 1);
|
|
|
|
rb_define_method(rb_cComplex, "/", rb_complex_div, 1);
|
2008-04-03 20:01:16 +04:00
|
|
|
rb_define_method(rb_cComplex, "quo", nucomp_quo, 1);
|
|
|
|
rb_define_method(rb_cComplex, "fdiv", nucomp_fdiv, 1);
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "**", rb_complex_pow, 1);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2009-07-03 16:19:54 +04:00
|
|
|
rb_define_method(rb_cComplex, "==", nucomp_eqeq_p, 1);
|
2019-06-05 07:41:02 +03:00
|
|
|
rb_define_method(rb_cComplex, "<=>", nucomp_cmp, 1);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "coerce", nucomp_coerce, 1);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "abs", rb_complex_abs, 0);
|
|
|
|
rb_define_method(rb_cComplex, "magnitude", rb_complex_abs, 0);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "abs2", nucomp_abs2, 0);
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "arg", rb_complex_arg, 0);
|
|
|
|
rb_define_method(rb_cComplex, "angle", rb_complex_arg, 0);
|
|
|
|
rb_define_method(rb_cComplex, "phase", rb_complex_arg, 0);
|
2008-08-29 17:41:41 +04:00
|
|
|
rb_define_method(rb_cComplex, "rectangular", nucomp_rect, 0);
|
|
|
|
rb_define_method(rb_cComplex, "rect", nucomp_rect, 0);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "polar", nucomp_polar, 0);
|
2018-12-12 14:06:48 +03:00
|
|
|
rb_define_method(rb_cComplex, "conjugate", rb_complex_conjugate, 0);
|
|
|
|
rb_define_method(rb_cComplex, "conj", rb_complex_conjugate, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2021-05-20 08:31:49 +03:00
|
|
|
rb_define_method(rb_cComplex, "real?", nucomp_real_p_m, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "numerator", nucomp_numerator, 0);
|
|
|
|
rb_define_method(rb_cComplex, "denominator", nucomp_denominator, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "hash", nucomp_hash, 0);
|
2008-09-15 08:20:46 +04:00
|
|
|
rb_define_method(rb_cComplex, "eql?", nucomp_eql_p, 1);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "to_s", nucomp_to_s, 0);
|
|
|
|
rb_define_method(rb_cComplex, "inspect", nucomp_inspect, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2015-05-17 09:01:47 +03:00
|
|
|
rb_undef_method(rb_cComplex, "positive?");
|
|
|
|
rb_undef_method(rb_cComplex, "negative?");
|
|
|
|
|
2016-07-17 17:53:00 +03:00
|
|
|
rb_define_method(rb_cComplex, "finite?", rb_complex_finite_p, 0);
|
|
|
|
rb_define_method(rb_cComplex, "infinite?", rb_complex_infinite_p, 0);
|
|
|
|
|
2012-12-01 13:17:02 +04:00
|
|
|
rb_define_private_method(rb_cComplex, "marshal_dump", nucomp_marshal_dump, 0);
|
2018-02-23 05:16:42 +03:00
|
|
|
/* :nodoc: */
|
|
|
|
compat = rb_define_class_under(rb_cComplex, "compatible", rb_cObject);
|
2012-12-01 13:17:02 +04:00
|
|
|
rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
|
2012-07-25 12:41:07 +04:00
|
|
|
rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
|
|
|
|
rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
|
|
|
|
rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
|
2010-04-26 15:14:40 +04:00
|
|
|
rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
|
2012-11-21 16:54:06 +04:00
|
|
|
rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cString, "to_c", string_to_c, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-09-24 12:02:17 +04:00
|
|
|
rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2008-08-31 15:51:04 +04:00
|
|
|
rb_define_method(rb_cNumeric, "abs2", numeric_abs2, 0);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cNumeric, "arg", numeric_arg, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "angle", numeric_arg, 0);
|
2008-08-29 17:41:41 +04:00
|
|
|
rb_define_method(rb_cNumeric, "phase", numeric_arg, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "rectangular", numeric_rect, 0);
|
|
|
|
rb_define_method(rb_cNumeric, "rect", numeric_rect, 0);
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_method(rb_cNumeric, "polar", numeric_polar, 0);
|
2008-03-16 03:23:43 +03:00
|
|
|
|
2009-07-03 14:50:17 +04:00
|
|
|
rb_define_method(rb_cFloat, "arg", float_arg, 0);
|
|
|
|
rb_define_method(rb_cFloat, "angle", float_arg, 0);
|
|
|
|
rb_define_method(rb_cFloat, "phase", float_arg, 0);
|
|
|
|
|
2012-02-24 04:10:53 +04:00
|
|
|
/*
|
2023-12-07 23:36:37 +03:00
|
|
|
* Equivalent
|
2023-12-26 19:00:04 +03:00
|
|
|
* to <tt>Complex.rect(0, 1)</tt>:
|
2023-12-07 23:36:37 +03:00
|
|
|
*
|
|
|
|
* Complex::I # => (0+1i)
|
|
|
|
*
|
2012-02-24 04:10:53 +04:00
|
|
|
*/
|
2008-03-31 20:42:24 +04:00
|
|
|
rb_define_const(rb_cComplex, "I",
|
|
|
|
f_complex_new_bang2(rb_cComplex, ZERO, ONE));
|
2014-08-22 12:01:42 +04:00
|
|
|
|
2018-06-17 05:41:26 +03:00
|
|
|
#if !USE_FLONUM
|
|
|
|
rb_gc_register_mark_object(RFLOAT_0 = DBL2NUM(0.0));
|
|
|
|
#endif
|
|
|
|
|
2014-08-22 12:01:42 +04:00
|
|
|
rb_provide("complex.so"); /* for backward compatibility */
|
2008-03-16 03:23:43 +03:00
|
|
|
}
|