# Complex<MyNumeric,MyNumeric> replaced Complex<MyNumeric,Float>; How to use coerce()

A MyNumeric type object that inherits Numeric can be specified in the Ruby Complex class constructor.

However, when I specified a negative value of MyNumber type for the imaginary part, the imaginary part was replaced with a Float type.

Maybe I’m missing a usage of coerce() methods.
Please tell me how to use coerce correctly.

–(1) Example that worked as expected – “Complex<Rational,BigDecaimal.negative>>”;

``````p   Complex(Rational(1,2), Rational(-34567890123456789,5))
# =>  ((1/2)-(34567890123456789/5)*i)
``````

–(2) Example that worked as expected – “Complex<MyNumber,MyNumber.positive>>”,;

``````p  y=Complex(MyNumeric.new(1,1,5), MyNumeric.new(3,1,7))
#=> ((1 + 1/2 + 5*√(3)/2)+(3 + 1/2 + 7*√(3)/2)*i)
p y.imag.class
#=> MyNumeric
``````

– (3) Examples of unexpected behavior;

``````p  z= y.conjugate, z.imag.class
#=> -((1 + 1/2 + 5*√(3)/2)-9.56217782649107i)
#=> Float  <--- unexpected behavior;
p  z=Complex(MyNumeric.new(1,1,5), MyNumeric.new(-9,1,7)), .class
#=> ((1 + 1/2 + 5*√(3)/2)-5.901923788646684i)
#=> (-9 + 1/2 + 3*√(3)/2)
#=> MyNumeric
p 0 - z.imag
#=> 5.901923788646684   <--- Integer.coerce (MyNumeric)  -> Float ?
``````

– The definition of MyNumeric is as follows;

``````class MyNumeric < Numeric
attr_accessor :num, :rt3h,:hf
CONST_Sqrt3H = Math.sqrt(3)/2
CONST_hf = 0.5
def initialize(a,b = 0,c = 0)
if a.is_a?(MyNumeric) && (b == 0) && (c == 0)
@num, @hf = a.num + (a.hf / 2), a.hf % 2
@rt3h = a.rt3h
elsif a.is_a?(Integer) && b.is_a?(Integer) && c.is_a?(Integer)
@num, @hf = a + (b / 2), b % 2
@rt3h = c
else
\$stderr.puts("ERROR at MyNumeric")
end
end
def +(other)
if other.is_a?(MyNumeric)
return new MyNumeric(@num + other.num, @hf + other.hf, @rt3h + other.rt3 )
elsif other.is_a?(Integer)
return new MyNumeric(@num + other, @rt3h,@hf)
end
end
def -(other)
if other.is_a?(MyNumeric)
return new MyNumeric(@num - other.num, @hf - other.hf, @rt3h - other.rt3 )
elsif other.is_a?(Integer)
return new MyNumeric(@num - other, @rt3h,@hf)
end
end
def zero?()
@num.zero?() && @hf.zero?() &&  @rt3h.zero?
end
def ==(other)
if other.is_a?(MyNumeric)
return (@num ==  other.num) && (@rt3h == other.rt3h) && (@hf == other.hf )
elsif other.is_a?(Integer) && (@rt3h == 0) && (@hf == 0)
return @num == other
else
return false
end
end
def negative?()
self.to_f.negative?
end
def <=>(other)
return self.to_f() <=> other.to_f
end
def to_f()
return @num + @rt3h*CONST_Sqrt3H + @hf * CONST_hf
end
def inspect()
return "(" + [num != 0 ? num.to_s() : "0", @hf != 0 ? @hf.to_s() + "/2" : nil, @rt3h != 0 ? @rt3h.to_s() + "*√(3)/2" : nil].filter{|c| !c.nil?}.to_a.join(" + ") + ")"
end
def to_s()
return "(" + [num != 0 ? num.to_s() : "0", @hf != 0 ? @hf.to_s() + "/2" : nil, @rt3h != 0 ? @rt3h.to_s() + "*√(3)/2" : nil].filter{|c| !c.nil?}.to_a.join(" + ") + ")"
end
def coerce(other)
if other.is_a?(Numeric)
return [self.to_f, other]
else
super
end
end
end
# builtin coerce ???
def coerce(other)
if other.is_a?(Numeric)
return [self.to_f, other]
else
super
end
end
# end of builtin coerce ???
``````

Your `MyNumeric` class needs a `coerce` method to properly interact with Ruby’s built-in numeric classes. The `coerce` method is used when an arithmetic operation can’t be performed because of incompatible classes.

In your case, you need to define it like this:

``````def coerce(other)
if other.is_a?(Numeric)
return [self.to_f, other]
else
super
end
end
``````

This method attempts to convert the `other` value to a Float, which will allow arithmetic operations with your `MyNumeric` objects.

Try this and see if it works.

I added the specified piece of code,
but again I got unintended results.

see updated “The definition of MyNumeric” as above.

I could improve the code just a little bit.
But the sign is wrong when the imaginary part shows a negative value.
(a + (negative value of b) *i) displayed as (a - (negative value of b) *i).

Is there anything else missing?

I’m concerned about something not firing (coerce() and more),
for example when expressions such as (Integer(0) - MyNumeric) are computed behind Complex.conjugate() or Complex.inspect().

``````p  "z2=",z=Complex(MyNumeric.new(1,1,5), MyNumeric.new(-9,1,3)),z.imag, z.imag.class
#=> ((1 + 1/2 + 5*√(3)/2)-(-9 + 1/2 + 3*√(3)/2)*i)  <-- (a **-** (negative value of b) *i)
#=> (-9 + 1/2 + 3*√(3)/2)
#=> MyNumeric
``````
``````class MyNumeric < Numeric
attr_accessor :num, :rt3h,:hf
CONST_Sqrt3H = Math.sqrt(3)/2
CONST_hf = 0.5
def initialize(a,b = 0,c = 0)
if a.is_a?(MyNumeric) && (b == 0) && (c == 0)
@num, @hf = a.num + (a.hf / 2), a.hf % 2
@rt3h = a.rt3h
elsif a.is_a?(Integer) && b.is_a?(Integer) && c.is_a?(Integer)
@num, @hf = a + (b / 2), b % 2
@rt3h = c
else
\$stderr.puts("ERROR at MyNumeric")
end
end
def +(other)
if other.is_a?(MyNumeric)
return MyNumeric.new(@num + other.num, @hf + other.hf, @rt3h + other.rt3 )
elsif other.is_a?(Integer)
return MyNumeric.new(@num + other, @rt3h,@hf)
end
end
def -(other)
if other.is_a?(MyNumeric)
return MyNumeric.new(@num - other.num, @hf - other.hf, @rt3h - other.rt3h )
elsif other.is_a?(Integer)
return MyNumeric.new(@num - other, @hf,  @rt3h)
end
end
def zero?()
@num.zero?() && @hf.zero?() &&  @rt3h.zero?
end
def ==(other)
if other.is_a?(MyNumeric)
return (@num ==  other.num) && (@rt3h == other.rt3h) && (@hf == other.hf )
elsif other.is_a?(Integer) && (@rt3h == 0) && (@hf == 0)
return @num == other
else
return false
end
end
def negative?()
self.to_f.negative?
end
def <=>(other)
return self.to_f() <=> other.to_f
end
def to_f()
return @num + @rt3h*CONST_Sqrt3H + @hf * CONST_hf
end
def inspect()
return "(" + [num != 0 ? num.to_s() : "0", @hf != 0 ? @hf.to_s() + "/2" : nil, @rt3h != 0 ? @rt3h.to_s() + "*√(3)/2" : nil].filter{|c| !c.nil?}.to_a.join(" + ") + ")"
end
def to_s()
return "(" + [num != 0 ? num.to_s() : "0", @hf != 0 ? @hf.to_s() + "/2" : nil, @rt3h != 0 ? @rt3h.to_s() + "*√(3)/2" : nil].filter{|c| !c.nil?}.to_a.join(" + ") + ")"
end
def coerce(other)