PsyRational.java
package coneforest.psylla.core;
import coneforest.psylla.runtime.*;
import java.math.BigInteger;
/**
* The representation of {@code rational}.
*/
@Type("rational")
public sealed interface PsyRational
extends PsyRealNumeric
permits
PsyIntegral,
PsyFraction,
PsyBigFraction
{
/**
* Context action of the {@code denominator} operator.
*/
@OperatorType("denominator")
public static final ContextAction PSY_DENOMINATOR
=ContextAction.<PsyRational>ofFunction(PsyRational::psyDenominator);
/**
* Context action of the {@code gcd} operator.
*/
@OperatorType("gcd")
public static final ContextAction PSY_GCD
=ContextAction.<PsyRational, PsyRational>ofBiFunction(PsyRational::psyGCD);
/**
* Context action of the {@code idiv} operator.
*/
@OperatorType("idiv")
public static final ContextAction PSY_IDIV
=ContextAction.<PsyRational, PsyRational>ofBiFunction(PsyRational::psyIdiv);
/**
* Context action of the {@code lcm} operator.
*/
@OperatorType("lcm")
public static final ContextAction PSY_LCM
=ContextAction.<PsyRational, PsyRational>ofBiFunction(PsyRational::psyLCM);
/**
* Context action of the {@code mod} operator.
*/
@OperatorType("mod")
public static final ContextAction PSY_MOD
=ContextAction.<PsyRational, PsyRational>ofBiFunction(PsyRational::psyMod);
/**
* Context action of the {@code numerator} operator.
*/
@OperatorType("numerator")
public static final ContextAction PSY_NUMERATOR
=ContextAction.<PsyRational>ofFunction(PsyRational::psyNumerator);
public BigInteger bigIntegerValue();
public default PsyRational rationalValue()
{
return this;
}
/**
* {@return an {@code integral} numerator of this fraction}
*/
public PsyIntegral psyNumerator();
/**
* {@return an {@code integral} denominator of this fraction}
*/
public PsyIntegral psyDenominator();
@Override
public default PsyRational psyToRational()
{
return this;
}
@Override
public default PsyIntegral psyRound()
{
final var oIntPart=psyFloor();
final var oFractPart=psySub(oIntPart);
return PsyInteger.TWO.psyMul(oFractPart).compareTo(PsyInteger.ONE)<0?
oIntPart: (PsyIntegral)oIntPart.psyAdd(PsyInteger.ONE);
}
@Override
public default PsyIntegral psyToIntegral()
{
return psyRound();
}
@Override
public default PsyRational psyNeg()
{
return of(psyNumerator().psyNeg(), psyDenominator());
}
@Override
public default PsyRealNumeric psyAdd(final PsyRealNumeric oRealNumeric)
{
return switch(oRealNumeric)
{
case PsyIntegral oIntegral->
of((PsyIntegral)psyNumerator().psyAdd(psyDenominator().psyMul(oIntegral)),
psyDenominator());
case PsyRational oRational->
of((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator())
.psyAdd(psyDenominator().psyMul(oRational.psyNumerator())),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
case PsyReal oReal->
new PsyReal(doubleValue()+oReal.doubleValue());
};
}
@Override
public default PsyRealNumeric psySub(final PsyRealNumeric oRealNumeric)
{
return switch(oRealNumeric)
{
case PsyIntegral oIntegral->
of((PsyIntegral)psyNumerator().psySub(psyDenominator().psyMul(oIntegral)),
psyDenominator());
case PsyRational oRational->
of((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator())
.psySub(psyDenominator().psyMul(oRational.psyNumerator())),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
case PsyReal oReal->
new PsyReal(doubleValue()+oReal.doubleValue());
};
}
@Override
public default PsyRational psyReciprocal()
throws PsyUndefinedResultException
{
try
{
return of(psyDenominator(), psyNumerator());
}
catch(final IllegalArgumentException ex)
{
throw new PsyUndefinedResultException();
}
}
@Override
public default PsyRealNumeric psyMul(final PsyRealNumeric oRealNumeric)
{
return switch(oRealNumeric)
{
case PsyIntegral oIntegral->
PsyRational.of((PsyIntegral)psyNumerator().psyMul(oIntegral),
psyDenominator());
case PsyRational oRational->
PsyRational.of((PsyIntegral)psyNumerator().psyMul(oRational.psyNumerator()),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
case PsyReal oReal->
new PsyReal(doubleValue()*oReal.doubleValue());
};
}
public default PsyRealNumeric psyDiv(final PsyRealNumeric oRealNumeric)
throws PsyUndefinedResultException
{
return switch(oRealNumeric)
{
case PsyIntegral oIntegral->
PsyRational.of(psyNumerator(),
(PsyIntegral)psyDenominator().psyMul(oIntegral));
case PsyRational oRational->
PsyRational.of((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator()),
(PsyIntegral)psyDenominator().psyMul(oRational.psyNumerator()));
case PsyReal oReal->
new PsyReal(doubleValue()/oReal.doubleValue());
};
}
/**
* {@return an {@code integral} representing this object modulo given modulus}
*
* @param oRational the given modulus.
* @throws PsyRangeCheckException when the modulus is negative.
* @throws PsyUndefinedResultException when the modulus is zero.
*/
public default PsyRational psyMod(final PsyRational oRational)
throws PsyRangeCheckException, PsyUndefinedResultException
{
return of(
((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator()))
.psyMod((PsyIntegral)psyDenominator().psyMul(oRational.psyNumerator())),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
}
/**
* {@return the quotient of the integer division of this {@code rational} by the {@code
* rational} divisor}
*
* @param oRational the divisor.
* @throws PsyUndefinedResultException when the divisor is zero.
*/
public default PsyIntegral psyIdiv(final PsyRational oRational)
throws PsyUndefinedResultException
{
return ((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator()))
.psyIdiv((PsyIntegral)oRational.psyNumerator().psyMul(psyDenominator()));
}
/**
* {@return a {@code rational} representing the greatest common divisor of this object and
* given object}
*
* @param oRational the given object.
*/
public default PsyRational psyGCD(final PsyRational oRational)
{
return of((PsyIntegral)((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator()))
.psyGCD((PsyIntegral)psyDenominator().psyMul(oRational.psyNumerator())),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
}
/**
* {@return a {@code rational} representing the least common multiplier of this object and
* given object}
*
* @param oRational the given object.
*/
public default PsyRational psyLCM(final PsyRational oRational)
{
return of(((PsyIntegral)psyNumerator().psyMul(oRational.psyDenominator()))
.psyLCM((PsyIntegral)psyDenominator().psyMul(oRational.psyNumerator())),
(PsyIntegral)psyDenominator().psyMul(oRational.psyDenominator()));
}
@Override
public PsyIntegral psyCeiling();
@Override
public default PsyRational psyAbs()
{
if(compareTo(PsyInteger.ZERO)<0)
return of(psyNumerator().psyNeg(), psyDenominator());
return this;
}
@Override
public PsyIntegral psyFloor();
public static PsyRational of(final PsyIntegral oNumerator, final PsyIntegral oDenominator)
{
try
{
if(oNumerator.psyMod(oDenominator.psyAbs()).psyIsZero().booleanValue())
return oNumerator.psyIdiv(oDenominator);
}
catch(final PsyRangeCheckException|PsyUndefinedResultException e)
{
throw new IllegalArgumentException();
}
if(oNumerator instanceof PsyInteger && oDenominator instanceof PsyInteger)
return PsyFraction.of(oNumerator.longValue(), oDenominator.longValue());
else
return PsyBigFraction.of(oNumerator.bigIntegerValue(), oDenominator.bigIntegerValue());
}
@Override
public default int compareTo(final PsyRealNumeric oNumeric)
{
if(oNumeric instanceof PsyRational oRational)
return psyNumerator().psyMul(oRational.psyDenominator())
.compareTo(psyDenominator().psyMul(oRational.psyNumerator()));
// TODO
return Double.compare(doubleValue(), oNumeric.doubleValue());
}
public static PsyRational parseLiteral(final String image)
throws PsySyntaxErrorException, PsyUndefinedResultException
{
final var slashIndex=image.indexOf(':');
if(slashIndex==-1)
return PsyIntegral.parseLiteral(image);
return of(PsyIntegral.parseLiteral(image.substring(0, slashIndex)),
PsyIntegral.parseLiteral(image.substring(slashIndex+1)));
}
}