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

**URL:** <https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131>\
**Category:** Development\
**Created:** [July 23, 2023, 1:08pm UTC](https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131 "2023-07-23T13:08:16Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![jumnichi.kose](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a698b9/32.png) [@jumnichi.kose](https://www.ruby-forum.com/u/jumnichi.kose)\
**Post date:** [July 23, 2023, 1:08pm UTC](https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131/1 "2023-07-23T13:08:16Z")

</div>

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\>\>”;

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

```

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

```auto
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;

```auto
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;

```auto
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 ???

```

---

<div class="post-metadata">

**Author:** ![robert-b](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/54ee81/32.png) [@robert-b](https://www.ruby-forum.com/u/robert-b)\
**Post date:** [July 23, 2023, 1:08pm UTC](https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131/2 "2023-07-23T13:08:23Z")

</div>

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:

```ruby
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.

---

<div class="post-metadata">

**Author:** ![jumnichi.kose](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a698b9/32.png) [@jumnichi.kose](https://www.ruby-forum.com/u/jumnichi.kose)\
**Post date:** [July 23, 2023, 1:25pm UTC](https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131/3 "2023-07-23T13:25:00Z")

</div>

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

see updated “The definition of MyNumeric” as above.

---

<div class="post-metadata">

**Author:** ![jumnichi.kose](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/a698b9/32.png) [@jumnichi.kose](https://www.ruby-forum.com/u/jumnichi.kose)\
**Post date:** [July 23, 2023, 1:36pm UTC](https://www.ruby-forum.com/t/complex-mynumeric-mynumeric-replaced-complex-mynumeric-float-how-to-use-coerce/264131/4 "2023-07-23T13:36:30Z")

</div>

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().**

```auto
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

```

```auto
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)
        if other.is_a?(MyNumeric) ## add this
            super
        elsif other.is_a?(Numeric)
            return [self, MyNumeric.new(other)] ## change this
        else
          super
        end
    end
end

```
