Reduce type check of arguments at Complex creation

This commit is contained in:
Nobuyoshi Nakada 2022-10-23 13:42:36 +09:00
Родитель c8c136265c
Коммит 86450d03a8
2 изменённых файлов: 48 добавлений и 22 удалений

Просмотреть файл

@ -421,15 +421,22 @@ f_complex_new_bang2(VALUE klass, VALUE x, VALUE y)
return nucomp_s_new_internal(klass, x, y); return nucomp_s_new_internal(klass, x, y);
} }
inline static void WARN_UNUSED_RESULT(inline static VALUE nucomp_real_check(VALUE num));
inline static VALUE
nucomp_real_check(VALUE num) nucomp_real_check(VALUE num)
{ {
if (!RB_INTEGER_TYPE_P(num) && if (!RB_INTEGER_TYPE_P(num) &&
!RB_FLOAT_TYPE_P(num) && !RB_FLOAT_TYPE_P(num) &&
!RB_TYPE_P(num, T_RATIONAL)) { !RB_TYPE_P(num, T_RATIONAL)) {
if (RB_TYPE_P(num, T_COMPLEX) && nucomp_real_p(num)) {
VALUE real = RCOMPLEX(num)->real;
assert(!RB_TYPE_P(real, T_COMPLEX));
return real;
}
if (!k_numeric_p(num) || !f_real_p(num)) if (!k_numeric_p(num) || !f_real_p(num))
rb_raise(rb_eTypeError, "not a real"); rb_raise(rb_eTypeError, "not a real");
} }
return num;
} }
inline static VALUE inline static VALUE
@ -480,16 +487,16 @@ nucomp_s_new(int argc, VALUE *argv, VALUE klass)
switch (rb_scan_args(argc, argv, "11", &real, &imag)) { switch (rb_scan_args(argc, argv, "11", &real, &imag)) {
case 1: case 1:
nucomp_real_check(real); real = nucomp_real_check(real);
imag = ZERO; imag = ZERO;
break; break;
default: default:
nucomp_real_check(real); real = nucomp_real_check(real);
nucomp_real_check(imag); imag = nucomp_real_check(imag);
break; break;
} }
return nucomp_s_canonicalize_internal(klass, real, imag); return nucomp_s_new_internal(klass, real, imag);
} }
inline static VALUE inline static VALUE
@ -611,16 +618,8 @@ m_sin(VALUE x)
} }
static VALUE static VALUE
f_complex_polar(VALUE klass, VALUE x, VALUE y) f_complex_polar_real(VALUE klass, VALUE x, VALUE y)
{ {
if (RB_TYPE_P(x, T_COMPLEX)) {
get_dat1(x);
x = dat->real;
}
if (RB_TYPE_P(y, T_COMPLEX)) {
get_dat1(y);
y = dat->real;
}
if (f_zero_p(x) || f_zero_p(y)) { if (f_zero_p(x) || f_zero_p(y)) {
return nucomp_s_new_internal(klass, x, RFLOAT_0); return nucomp_s_new_internal(klass, x, RFLOAT_0);
} }
@ -656,6 +655,14 @@ f_complex_polar(VALUE klass, VALUE x, VALUE y)
f_mul(x, m_sin(y))); f_mul(x, m_sin(y)));
} }
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);
}
#ifdef HAVE___COSPI #ifdef HAVE___COSPI
# define cospi(x) __cospi(x) # define cospi(x) __cospi(x)
#else #else
@ -705,14 +712,14 @@ nucomp_s_polar(int argc, VALUE *argv, VALUE klass)
VALUE abs, arg; VALUE abs, arg;
argc = rb_scan_args(argc, argv, "11", &abs, &arg); argc = rb_scan_args(argc, argv, "11", &abs, &arg);
nucomp_real_check(abs); abs = nucomp_real_check(abs);
if (argc == 2) { if (argc == 2) {
nucomp_real_check(arg); arg = nucomp_real_check(arg);
} }
else { else {
arg = ZERO; arg = ZERO;
} }
return f_complex_polar(klass, abs, arg); return f_complex_polar_real(klass, abs, arg);
} }
/* /*

Просмотреть файл

@ -1145,15 +1145,34 @@ class Complex_Test < Test::Unit::TestCase
end end
def test_canonicalize_polar def test_canonicalize_polar
obj = Class.new(Numeric) do error = "not a real"
def initialize assert_raise_with_message(TypeError, error) do
@x = 2 Complex.polar(1i)
end
assert_raise_with_message(TypeError, error) do
Complex.polar(1i, 0)
end
assert_raise_with_message(TypeError, error) do
Complex.polar(0, 1i)
end
n = Class.new(Numeric) do
def initialize(x = 1)
@x = x
end end
def real? def real?
(@x -= 1) > 0 (@x -= 1) > 0
end end
end.new end
assert_raise(TypeError) do obj = n.new
assert_raise_with_message(TypeError, error) do
Complex.polar(obj)
end
obj = n.new
assert_raise_with_message(TypeError, error) do
Complex.polar(obj, 0)
end
obj = n.new
assert_raise_with_message(TypeError, error) do
Complex.polar(1, obj) Complex.polar(1, obj)
end end
end end