math-php icon indicating copy to clipboard operation
math-php copied to clipboard

Add isEqual() to the ObjectArithmetic interface.

Open Beakerboy opened this issue 5 years ago • 8 comments

Currently, all the classes in the Number namespace have methods name equals(), while Matrix has isEqual(). The polynomial class has nothing. Since PHP is loosely typed, I think we should approach adding this method to the interface with a unified philosophy that takes that into consideration. PHP has == as well as === for native comparisons. Should we have methods that compare value, and one that also compares type? Maybe IsEqual() and isIdentical()?

Beakerboy avatar Oct 20 '20 17:10 Beakerboy

Are you thinking you'd want like $rational->isEqual($arbitraryInteger) to possibly be true while $rational->isIdentical($arbitraryInteger) would be false?

markrogoyski avatar Oct 20 '20 19:10 markrogoyski

I think that would require some sort of casting logic where everything would have to pass into a float.

I was thinking more like how a complex number could equal a float when the imaginary part is zero.

public function isIdentical($object): bool
{
    return get_class($this) == get_class($object) ? $this->isEqual($object) : false;
}

Beakerboy avatar Oct 20 '20 19:10 Beakerboy

Casting to float is probably doing to have erratic results. For example:

php > echo 1/3;
0.33333333333333
php > var_dump(0.33333333333333 == 1/3);
bool(false)

The ObjectArithmetic interface is really for the object orchestrating the operations, with the presumption that they are all the same kind of object that implements that interface. It gets too complicated if you try to make this work across different types.

I think isEquals is all you need for now and it should probably fail if the types are not the same.

markrogoyski avatar Oct 20 '20 22:10 markrogoyski

The ArbitraryInteger class already behaves this way though. If you say $object->equals(15) it will return true when $object = new ArbitraryInteger(15);

Beakerboy avatar Oct 20 '20 23:10 Beakerboy

It looks like it is comparing properties, after having maybe transformed a scalar into an object.

    public function equals($int): bool
    {
        $int = self::create($int);
        return $this->base256 == $int->toBinary() && $this->isPositive == $int->isPositive();
    }

markrogoyski avatar Oct 20 '20 23:10 markrogoyski

The way it’s implemented does not matter. I’m asking what standard We want for allowed inputs and expected output. In the case of the ArbitraryInteger, it’s faster to convert an int into an ArbitraryInteger than dealing with potential overflows from doing the opposite. For a Complex number, I would probably say, if the input is numeric then check if $this has a zero for the imaginary part, then check if the real part matches the provided number. Polynomial would do something similar with it’s storage array. The RationalNumber would have to cast to a float.

Beakerboy avatar Oct 21 '20 11:10 Beakerboy

I think the Complex and ArbitraryInteger and maybe even the Polynomial if they have integers will work fine comparing to scalars, but the Rational is going to be the problem.

php > $rational = new MathPHP\Number\Rational(0, 1, 3);
php >
php > echo 1/3;
0.33333333333333
php > echo $rational->toFloat();
0.33333333333333
php > var_dump(0.33333333333333 == 0.33333333333333);
bool(true)
php > var_dump($rational->toFloat() == 0.33333333333333);
bool(false)

I think it is interesting to be able to compare the object and scalar representations of these numbers so I'd want to try it. So let's give make the isEquals smart and then you do have the use case to also add isIdentical. But there will be erratic behavior whenever floats are involved. Just keep that in mind.

markrogoyski avatar Oct 21 '20 14:10 markrogoyski

When comparing floats, I would use the epsilon that is used throughout the library.

Beakerboy avatar Oct 21 '20 14:10 Beakerboy