Skip to content

Commit 0783391

Browse files
committed
Implementation of cmath.rect function
1 parent 55f9f0a commit 0783391

File tree

1 file changed

+142
-66
lines changed

1 file changed

+142
-66
lines changed

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

Lines changed: 142 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
1414
import com.oracle.graal.python.nodes.ErrorMessages;
1515
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
16+
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
1617
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
1718
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
1819
import com.oracle.graal.python.nodes.util.CoerceToComplexNode;
20+
import com.oracle.graal.python.nodes.util.CoerceToDoubleNode;
1921
import com.oracle.graal.python.runtime.PythonCore;
22+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
2023
import com.oracle.truffle.api.CompilerDirectives;
2124
import com.oracle.truffle.api.dsl.Cached;
2225
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
@@ -28,9 +31,15 @@
2831

2932
import java.util.List;
3033

34+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
35+
3136
@CoreFunctions(defineModule = "cmath")
3237
public class CmathModuleBuiltins extends PythonBuiltins {
3338

39+
// Constants used for the definition of special values tables in node classes
40+
static final double INF = Double.POSITIVE_INFINITY;
41+
static final double NAN = Double.NaN;
42+
3443
@Override
3544
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
3645
return CmathModuleBuiltinsFactory.getFactories();
@@ -49,84 +58,79 @@ public void initialize(PythonCore core) {
4958
super.initialize(core);
5059
}
5160

52-
@TypeSystemReference(PythonArithmeticTypes.class)
53-
@ImportStatic(MathGuards.class)
54-
abstract static class CmathComplexUnaryBuiltinNode extends PythonUnaryBuiltinNode {
61+
static PComplex specialValue(PythonObjectFactory factory, ComplexConstant[][] table, double real, double imag) {
62+
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
63+
ComplexConstant c = table[SpecialType.ofDouble(real).ordinal()][SpecialType.ofDouble(imag).ordinal()];
64+
if (c == null) {
65+
CompilerDirectives.transferToInterpreterAndInvalidate();
66+
throw new IllegalStateException("should not be reached");
67+
}
68+
return factory.createComplex(c.real, c.imag);
69+
}
70+
return null;
71+
}
5572

56-
// Constants used for the definition of special values tables in subclassess
57-
static final double INF = Double.POSITIVE_INFINITY;
58-
static final double NAN = Double.NaN;
73+
/**
74+
* Creates an instance of ComplexConstant. The name of this factory method is intentionally
75+
* short to allow nested classess compact definition of their tables of special values.
76+
*
77+
* @param real the real part of the complex constant
78+
* @param imag the imaginary part of the complex constant
79+
* @return a new instance of ComplexConstant representing the complex number real + i * imag
80+
*/
81+
static ComplexConstant C(double real, double imag) {
82+
return new ComplexConstant(real, imag);
83+
}
5984

60-
protected static class ComplexConstant {
61-
final double real;
62-
final double imag;
85+
static class ComplexConstant {
86+
final double real;
87+
final double imag;
6388

64-
ComplexConstant(double real, double imag) {
65-
this.real = real;
66-
this.imag = imag;
67-
}
89+
ComplexConstant(double real, double imag) {
90+
this.real = real;
91+
this.imag = imag;
6892
}
93+
}
6994

70-
private enum SpecialType {
71-
NINF, // 0, negative infinity
72-
NEG, // 1, negative finite number (nonzero)
73-
NZERO, // 2, -0.0
74-
PZERO, // 3, +0.0
75-
POS, // 4, positive finite number (nonzero)
76-
PINF, // 5, positive infinity
77-
NAN; // 6, Not a Number
78-
79-
static SpecialType ofDouble(double d) {
80-
if (Double.isFinite(d)) {
81-
if (d != 0) {
82-
if (Math.copySign(1.0, d) == 1.0) {
83-
return POS;
84-
} else {
85-
return NEG;
86-
}
95+
enum SpecialType {
96+
NINF, // 0, negative infinity
97+
NEG, // 1, negative finite number (nonzero)
98+
NZERO, // 2, -0.0
99+
PZERO, // 3, +0.0
100+
POS, // 4, positive finite number (nonzero)
101+
PINF, // 5, positive infinity
102+
NAN; // 6, Not a Number
103+
104+
static SpecialType ofDouble(double d) {
105+
if (Double.isFinite(d)) {
106+
if (d != 0) {
107+
if (Math.copySign(1.0, d) == 1.0) {
108+
return POS;
87109
} else {
88-
if (Math.copySign(1.0, d) == 1.0) {
89-
return PZERO;
90-
} else {
91-
return NZERO;
92-
}
110+
return NEG;
93111
}
94-
}
95-
if (Double.isNaN(d)) {
96-
return NAN;
97-
}
98-
if (Math.copySign(1.0, d) == 1.0) {
99-
return PINF;
100112
} else {
101-
return NINF;
113+
if (Math.copySign(1.0, d) == 1.0) {
114+
return PZERO;
115+
} else {
116+
return NZERO;
117+
}
102118
}
103119
}
104-
}
105-
106-
protected PComplex specialValue(ComplexConstant[][] table, double real, double imag) {
107-
if (!Double.isFinite(real) || !Double.isFinite(imag)) {
108-
ComplexConstant c = table[SpecialType.ofDouble(real).ordinal()][SpecialType.ofDouble(imag).ordinal()];
109-
if (c == null) {
110-
CompilerDirectives.transferToInterpreterAndInvalidate();
111-
throw new IllegalStateException("should not be reached");
112-
}
113-
return factory().createComplex(c.real, c.imag);
120+
if (Double.isNaN(d)) {
121+
return NAN;
122+
}
123+
if (Math.copySign(1.0, d) == 1.0) {
124+
return PINF;
125+
} else {
126+
return NINF;
114127
}
115-
return null;
116-
}
117-
118-
/**
119-
* Creates an instance of ComplexConstant. The name of this factory method is intentionally
120-
* short to allow subclassess compact definition of their tables of special values.
121-
*
122-
* @param real the real part of the complex constant
123-
* @param imag the imaginary part of the complex constant
124-
* @return a new instance of ComplexConstant representing the complex number real + i * imag
125-
*/
126-
protected static ComplexConstant C(double real, double imag) {
127-
return new ComplexConstant(real, imag);
128128
}
129+
}
129130

131+
@TypeSystemReference(PythonArithmeticTypes.class)
132+
@ImportStatic(MathGuards.class)
133+
abstract static class CmathComplexUnaryBuiltinNode extends PythonUnaryBuiltinNode {
130134
PComplex compute(@SuppressWarnings("unused") double real, @SuppressWarnings("unused") double imag) {
131135
CompilerDirectives.transferToInterpreterAndInvalidate();
132136
throw new IllegalStateException("should not be reached");
@@ -270,6 +274,78 @@ private PTuple toPolar(PComplex value, ComplexBuiltins.AbsNode absNode) {
270274
}
271275
}
272276

277+
@Builtin(name = "rect", minNumOfPositionalArgs = 2)
278+
@TypeSystemReference(PythonArithmeticTypes.class)
279+
@ImportStatic(MathGuards.class)
280+
@GenerateNodeFactory
281+
abstract static class RectNode extends PythonBinaryBuiltinNode {
282+
283+
// @formatter:off
284+
@CompilerDirectives.CompilationFinal(dimensions = 2)
285+
private static final ComplexConstant[][] SPECIAL_VALUES = {
286+
{C(INF, NAN), null, C(-INF, 0.0), C(-INF, -0.0), null, C(INF, NAN), C(INF, NAN)},
287+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
288+
{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)},
289+
{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)},
290+
{C(NAN, NAN), null, null, null, null, C(NAN, NAN), C(NAN, NAN)},
291+
{C(INF, NAN), null, C(INF, -0.0), C(INF, 0.0), null, C(INF, NAN), C(INF, NAN)},
292+
{C(NAN, NAN), C(NAN, NAN), C(NAN, 0.0), C(NAN, 0.0), C(NAN, NAN), C(NAN, NAN), C(NAN, NAN)},
293+
};
294+
// @formatter:on
295+
296+
@Specialization
297+
PComplex doLL(long r, long phi) {
298+
return rect(r, phi);
299+
}
300+
301+
@Specialization
302+
PComplex doLD(long r, double phi) {
303+
return rect(r, phi);
304+
}
305+
306+
@Specialization
307+
PComplex doDL(double r, long phi) {
308+
return rect(r, phi);
309+
}
310+
311+
@Specialization
312+
PComplex doDD(double r, double phi) {
313+
return rect(r, phi);
314+
}
315+
316+
@Specialization
317+
PComplex doGeneral(VirtualFrame frame, Object r, Object phi,
318+
@Cached CoerceToDoubleNode coerceRToDouble,
319+
@Cached CoerceToDoubleNode coercePhiToDouble) {
320+
return rect(coerceRToDouble.execute(frame, r), coercePhiToDouble.execute(frame, phi));
321+
}
322+
323+
private PComplex rect(double r, double phi) {
324+
// deal with special values
325+
if (!Double.isFinite(r) || !Double.isFinite(phi)) {
326+
// need to raise an exception if r is a nonzero number and phi is infinite
327+
if (r != 0.0 && !Double.isNaN(r) && Double.isInfinite(phi)) {
328+
throw raise(ValueError, "math domain error");
329+
}
330+
331+
// if r is +/-infinity and phi is finite but nonzero then
332+
// result is (+-INF +-INF i), but we need to compute cos(phi)
333+
// and sin(phi) to figure out the signs.
334+
if (Double.isInfinite(r) && Double.isFinite(phi) && phi != 0.0) {
335+
double real = Math.copySign(Double.POSITIVE_INFINITY, Math.cos(phi));
336+
double imag = Math.copySign(Double.POSITIVE_INFINITY, Math.sin(phi));
337+
if (r > 0) {
338+
return factory().createComplex(real, imag);
339+
} else {
340+
return factory().createComplex(-real, -imag);
341+
}
342+
}
343+
return specialValue(factory(), SPECIAL_VALUES, r, phi);
344+
}
345+
return factory().createComplex(r * Math.cos(phi), r * Math.sin(phi));
346+
}
347+
}
348+
273349
@Builtin(name = "sqrt", minNumOfPositionalArgs = 1)
274350
@GenerateNodeFactory
275351
abstract static class SqrtNode extends CmathComplexUnaryBuiltinNode {
@@ -289,7 +365,7 @@ abstract static class SqrtNode extends CmathComplexUnaryBuiltinNode {
289365

290366
@Override
291367
PComplex compute(double real, double imag) {
292-
PComplex result = specialValue(SPECIAL_VALUES, real, imag);
368+
PComplex result = specialValue(factory(), SPECIAL_VALUES, real, imag);
293369
if (result != null) {
294370
return result;
295371
}

0 commit comments

Comments
 (0)