Skip to content

Commit f3e659f

Browse files
committed
Implementation of cmath functions exp, cos, cosh, sin, sinh, tan and tanh
1 parent 96e56c5 commit f3e659f

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/CmathModuleBuiltins.java

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
import java.util.List;
3838

39+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
3940
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
4041

4142
@CoreFunctions(defineModule = "cmath")
@@ -50,6 +51,7 @@ public class CmathModuleBuiltins extends PythonBuiltins {
5051
static final double P34 = 0.75 * Math.PI;
5152

5253
static final double LARGE_DOUBLE = Double.MAX_VALUE / 4.0; // used to avoid overflow
54+
static final double LOG_LARGE_DOUBLE = Math.log(LARGE_DOUBLE);
5355
static final double LN_2 = 0.6931471805599453094; // natural log of 2
5456
static final double LN_10 = 2.302585092994045684; // natural log of 10
5557

@@ -752,6 +754,245 @@ static AtanhNode create() {
752754
}
753755
}
754756

757+
@Builtin(name = "exp", minNumOfPositionalArgs = 1)
758+
@GenerateNodeFactory
759+
abstract static class ExpNode extends CmathComplexUnaryBuiltinNode {
760+
761+
// @formatter:off
762+
@CompilerDirectives.CompilationFinal(dimensions = 2)
763+
private static final ComplexConstant[][] SPECIAL_VALUES = {
764+
{C(0.0, 0.0), null, C(0.0, -0.0), C(0.0, 0.0), null, C(0.0, 0.0), C(0.0, 0.0)},
765+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
766+
{C(NAN, NAN), null, C(1.0, -0.0), C(1.0, 0.0), null, C(NAN, NAN), C(NAN, NAN)},
767+
{C(NAN, NAN), null, C(1.0, -0.0), C(1.0, 0.0), null, C(NAN, NAN), C(NAN, NAN)},
768+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
769+
{C(INF, NAN), null, C(INF, -0.0), C(INF, 0.0), null, C(INF, NAN), C(INF, NAN)},
770+
{C(NAN, NAN), C(NAN, NAN), C(NAN, -0.0), C(NAN, 0.0), C(NAN, NAN), C(NAN, NAN), C(NAN, NAN)},
771+
};
772+
// @formatter:on
773+
774+
@Override
775+
PComplex compute(VirtualFrame frame, double real, double imag) {
776+
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
777+
PComplex r;
778+
if (Double.isInfinite(real) && Double.isFinite(imag) && imag != 0.0) {
779+
if (real > 0) {
780+
r = factory().createComplex(Math.copySign(INF, Math.cos(imag)), Math.copySign(INF, Math.sin(imag)));
781+
} else {
782+
r = factory().createComplex(Math.copySign(0.0, Math.cos(imag)), Math.copySign(0.0, Math.sin(imag)));
783+
}
784+
} else {
785+
r = specialValue(factory(), SPECIAL_VALUES, real, imag);
786+
}
787+
if (Double.isInfinite(imag) && (Double.isFinite(real) || (Double.isInfinite(real) && real > 0))) {
788+
throw raise(ValueError, ErrorMessages.MATH_DOMAIN_ERROR);
789+
}
790+
return r;
791+
}
792+
793+
double rreal, rimag;
794+
if (real > LOG_LARGE_DOUBLE) {
795+
double l = Math.exp(real - 1.0);
796+
rreal = l * Math.cos(imag) * Math.E;
797+
rimag = l * Math.sin(imag) * Math.E;
798+
} else {
799+
double l = Math.exp(real);
800+
rreal = l * Math.cos(imag);
801+
rimag = l * Math.sin(imag);
802+
}
803+
if (Double.isInfinite(rreal) || Double.isInfinite(rimag)) {
804+
throw raise(OverflowError, ErrorMessages.MATH_RANGE_ERROR);
805+
}
806+
return factory().createComplex(rreal, rimag);
807+
}
808+
}
809+
810+
@Builtin(name = "cos", minNumOfPositionalArgs = 1)
811+
@GenerateNodeFactory
812+
abstract static class CosNode extends CmathComplexUnaryBuiltinNode {
813+
814+
@Child private CoshNode coshNode = CoshNode.create();
815+
816+
@Override
817+
PComplex compute(VirtualFrame frame, double real, double imag) {
818+
return coshNode.executeComplex(frame, factory().createComplex(-imag, real));
819+
}
820+
}
821+
822+
@Builtin(name = "cosh", minNumOfPositionalArgs = 1)
823+
@GenerateNodeFactory
824+
abstract static class CoshNode extends CmathComplexUnaryBuiltinNode {
825+
826+
// @formatter:off
827+
@CompilerDirectives.CompilationFinal(dimensions = 2)
828+
private static final ComplexConstant[][] SPECIAL_VALUES = {
829+
{C(INF, NAN), null, C(INF, 0.0), C(INF, -0.0), null, C(INF, NAN), C(INF, NAN)},
830+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
831+
{C(NAN, 0.0), null, C(1.0, 0.0), C(1.0, -0.0), null, C(NAN, 0.0), C(NAN, 0.0)},
832+
{C(NAN, 0.0), null, C(1.0, -0.0), C(1.0, 0.0), null, C(NAN, 0.0), C(NAN, 0.0)},
833+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
834+
{C(INF, NAN), null, C(INF, -0.0), C(INF, 0.0), null, C(INF, NAN), C(INF, NAN)},
835+
{C(NAN, NAN), C(NAN, NAN), C(NAN, 0.0), C(NAN, 0.0), C(NAN, NAN), C(NAN, NAN), C(NAN, NAN)},
836+
};
837+
// @formatter:on
838+
839+
@Override
840+
PComplex compute(VirtualFrame frame, double real, double imag) {
841+
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
842+
if (Double.isInfinite(imag) && !Double.isNaN(real)) {
843+
throw raise(ValueError, ErrorMessages.MATH_DOMAIN_ERROR);
844+
}
845+
if (Double.isInfinite(real) && Double.isFinite(imag) && imag != 0.0) {
846+
double r = Math.copySign(INF, Math.sin(imag));
847+
return factory().createComplex(Math.copySign(INF, Math.cos(imag)), real > 0 ? r : -r);
848+
} else {
849+
return specialValue(factory(), SPECIAL_VALUES, real, imag);
850+
}
851+
}
852+
853+
double rreal, rimag;
854+
if (Math.abs(real) > LOG_LARGE_DOUBLE) {
855+
double x_minus_one = real - Math.copySign(1.0, real);
856+
rreal = Math.cos(imag) * Math.cosh(x_minus_one) * Math.E;
857+
rimag = Math.sin(imag) * Math.sinh(x_minus_one) * Math.E;
858+
} else {
859+
rreal = Math.cos(imag) * Math.cosh(real);
860+
rimag = Math.sin(imag) * Math.sinh(real);
861+
}
862+
if (Double.isInfinite(rreal) || Double.isInfinite(rimag)) {
863+
throw raise(OverflowError, ErrorMessages.MATH_RANGE_ERROR);
864+
}
865+
return factory().createComplex(rreal, rimag);
866+
}
867+
868+
static CoshNode create() {
869+
return CmathModuleBuiltinsFactory.CoshNodeFactory.create();
870+
}
871+
}
872+
873+
@Builtin(name = "sin", minNumOfPositionalArgs = 1)
874+
@GenerateNodeFactory
875+
abstract static class SinNode extends CmathComplexUnaryBuiltinNode {
876+
877+
@Child private SinhNode sinhNode = SinhNode.create();
878+
879+
@Override
880+
PComplex compute(VirtualFrame frame, double real, double imag) {
881+
PComplex s = sinhNode.executeComplex(frame, factory().createComplex(-imag, real));
882+
return factory().createComplex(s.getImag(), -s.getReal());
883+
}
884+
}
885+
886+
@Builtin(name = "sinh", minNumOfPositionalArgs = 1)
887+
@GenerateNodeFactory
888+
abstract static class SinhNode extends CmathComplexUnaryBuiltinNode {
889+
890+
// @formatter:off
891+
@CompilerDirectives.CompilationFinal(dimensions = 2)
892+
private static final ComplexConstant[][] SPECIAL_VALUES = {
893+
{C(INF, NAN), null, C(-INF, -0.0), C(-INF, 0.0), null, C(INF, NAN), C(INF, NAN)},
894+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
895+
{C(0.0, NAN), null, C(-0.0, -0.0), C(-0.0, 0.0), null, C(0.0, NAN), C(0.0, NAN)},
896+
{C(0.0, NAN), null, C(0.0, -0.0), C(0.0, 0.0), null, C(0.0, NAN), C(0.0, NAN)},
897+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
898+
{C(INF, NAN), null, C(INF, -0.0), C(INF, 0.0), null, C(INF, NAN), C(INF, NAN)},
899+
{C(NAN, NAN), C(NAN, NAN), C(NAN, -0.0), C(NAN, 0.0), C(NAN, NAN), C(NAN, NAN), C(NAN, NAN)},
900+
};
901+
// @formatter:on
902+
903+
@Override
904+
PComplex compute(VirtualFrame frame, double real, double imag) {
905+
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
906+
if (Double.isInfinite(imag) && !Double.isNaN(real)) {
907+
throw raise(ValueError, ErrorMessages.MATH_DOMAIN_ERROR);
908+
}
909+
if (Double.isInfinite(real) && Double.isFinite(imag) && imag != 0.0) {
910+
double r = Math.copySign(INF, Math.cos(imag));
911+
return factory().createComplex(real > 0 ? r : -r, Math.copySign(INF, Math.sin(imag)));
912+
} else {
913+
return specialValue(factory(), SPECIAL_VALUES, real, imag);
914+
}
915+
}
916+
917+
double rreal, rimag;
918+
if (Math.abs(real) > LOG_LARGE_DOUBLE) {
919+
double x_minus_one = real - Math.copySign(1.0, real);
920+
rreal = Math.cos(imag) * Math.sinh(x_minus_one) * Math.E;
921+
rimag = Math.sin(imag) * Math.cosh(x_minus_one) * Math.E;
922+
} else {
923+
rreal = Math.cos(imag) * Math.sinh(real);
924+
rimag = Math.sin(imag) * Math.cosh(real);
925+
}
926+
if (Double.isInfinite(rreal) || Double.isInfinite(rimag)) {
927+
throw raise(OverflowError, ErrorMessages.MATH_RANGE_ERROR);
928+
}
929+
return factory().createComplex(rreal, rimag);
930+
}
931+
932+
static SinhNode create() {
933+
return CmathModuleBuiltinsFactory.SinhNodeFactory.create();
934+
}
935+
}
936+
937+
@Builtin(name = "tan", minNumOfPositionalArgs = 1)
938+
@GenerateNodeFactory
939+
abstract static class TanNode extends CmathComplexUnaryBuiltinNode {
940+
941+
@Child private TanhNode tanhNode = TanhNode.create();
942+
943+
@Override
944+
PComplex compute(VirtualFrame frame, double real, double imag) {
945+
PComplex s = tanhNode.executeComplex(frame, factory().createComplex(-imag, real));
946+
return factory().createComplex(s.getImag(), -s.getReal());
947+
}
948+
}
949+
950+
@Builtin(name = "tanh", minNumOfPositionalArgs = 1)
951+
@GenerateNodeFactory
952+
abstract static class TanhNode extends CmathComplexUnaryBuiltinNode {
953+
954+
// @formatter:off
955+
@CompilerDirectives.CompilationFinal(dimensions = 2)
956+
private static final ComplexConstant[][] SPECIAL_VALUES = {
957+
{C(-1.0, 0.0), null, C(-1.0, -0.0), C(-1.0, 0.0), null, C(-1.0, 0.0), C(-1.0, 0.0)},
958+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
959+
{C(NAN, NAN), null, C(-0.0, -0.0), C(-0.0, 0.0), null, C(NAN, NAN), C(NAN, NAN)},
960+
{C(NAN, NAN), null, C(0.0, -0.0), C(0.0, 0.0), null, C(NAN, NAN), C(NAN, NAN)},
961+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
962+
{C(1.0, 0.0), null, C(1.0, -0.0), C(1.0, 0.0), null, C(1.0, 0.0), C(1.0, 0.0)},
963+
{C(NAN, NAN), C(NAN, NAN), C(NAN, -0.0), C(NAN, 0.0), C(NAN, NAN), C(NAN, NAN), C(NAN, NAN)},
964+
};
965+
// @formatter:on
966+
967+
@Override
968+
PComplex compute(VirtualFrame frame, double real, double imag) {
969+
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
970+
if (Double.isInfinite(imag) && Double.isFinite(real)) {
971+
throw raise(ValueError, ErrorMessages.MATH_DOMAIN_ERROR);
972+
}
973+
if (Double.isInfinite(real) && Double.isFinite(imag) && imag != 0.0) {
974+
return factory().createComplex(real > 0 ? 1.0 : -1.0, Math.copySign(0.0, 2.0 * Math.sin(imag) * Math.cos(imag)));
975+
} else {
976+
return specialValue(factory(), SPECIAL_VALUES, real, imag);
977+
}
978+
}
979+
if (Math.abs(real) > LOG_LARGE_DOUBLE) {
980+
return factory().createComplex(Math.copySign(1.0, real),
981+
4.0 * Math.sin(imag) * Math.cos(imag) * Math.exp(-20. * Math.abs(real)));
982+
}
983+
double tx = Math.tanh(real);
984+
double ty = Math.tan(imag);
985+
double cx = 1.0 / Math.cosh(real);
986+
double txty = tx * ty;
987+
double denom = 1.0 + txty * txty;
988+
return factory().createComplex(tx * (1.0 + ty * ty) / denom, ((ty / denom) * cx) * cx);
989+
}
990+
991+
static TanhNode create() {
992+
return CmathModuleBuiltinsFactory.TanhNodeFactory.create();
993+
}
994+
}
995+
755996
@Builtin(name = "isclose", minNumOfPositionalArgs = 2, maxNumOfPositionalArgs = 2, keywordOnlyNames = {"rel_tol", "abs_tol"})
756997
@TypeSystemReference(PythonArithmeticTypes.class)
757998
@ImportStatic(MathGuards.class)

0 commit comments

Comments
 (0)