Skip to content

Commit 55f9f0a

Browse files
committed
Unify implementation of complex.__abs__ with cmath.polar
1 parent 93fde59 commit 55f9f0a

File tree

2 files changed

+29
-144
lines changed

2 files changed

+29
-144
lines changed

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

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.oracle.graal.python.builtins.Builtin;
99
import com.oracle.graal.python.builtins.CoreFunctions;
1010
import com.oracle.graal.python.builtins.PythonBuiltins;
11+
import com.oracle.graal.python.builtins.objects.complex.ComplexBuiltins;
1112
import com.oracle.graal.python.builtins.objects.complex.PComplex;
1213
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
1314
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -27,8 +28,6 @@
2728

2829
import java.util.List;
2930

30-
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
31-
3231
@CoreFunctions(defineModule = "cmath")
3332
public class CmathModuleBuiltins extends PythonBuiltins {
3433

@@ -255,30 +254,19 @@ PTuple doD(double value) {
255254
}
256255

257256
@Specialization
258-
PTuple doC(PComplex value) {
259-
// TODO: the implementation of abs(z) should be shared with ComplexBuiltins.AbsNode, but
260-
// it currently does not pass the overflow test
261-
double r;
262-
if (!Double.isFinite(value.getReal()) || !Double.isFinite(value.getImag())) {
263-
if (Double.isInfinite(value.getReal())) {
264-
r = Math.abs(value.getReal());
265-
} else if (Double.isInfinite(value.getImag())) {
266-
r = Math.abs(value.getImag());
267-
} else {
268-
r = Double.NaN;
269-
}
270-
} else {
271-
r = Math.hypot(value.getReal(), value.getImag());
272-
if (Double.isInfinite(r)) {
273-
throw raise(OverflowError, ErrorMessages.ABSOLUTE_VALUE_TOO_LARGE);
274-
}
275-
}
276-
return factory().createTuple(new Object[]{r, Math.atan2(value.getImag(), value.getReal())});
257+
PTuple doC(PComplex value, @Cached ComplexBuiltins.AbsNode absNode) {
258+
return toPolar(value, absNode);
277259
}
278260

279261
@Specialization
280-
PTuple doGeneral(VirtualFrame frame, Object value, @Cached CoerceToComplexNode coerceToComplex) {
281-
return doC(coerceToComplex.execute(frame, value));
262+
PTuple doGeneral(VirtualFrame frame, Object value, @Cached CoerceToComplexNode coerceToComplex,
263+
@Cached ComplexBuiltins.AbsNode absNode) {
264+
return toPolar(coerceToComplex.execute(frame, value), absNode);
265+
}
266+
267+
private PTuple toPolar(PComplex value, ComplexBuiltins.AbsNode absNode) {
268+
double r = absNode.executeDouble(value);
269+
return factory().createTuple(new Object[]{r, Math.atan2(value.getImag(), value.getReal())});
282270
}
283271
}
284272

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/complex/ComplexBuiltins.java

Lines changed: 18 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
6464
import static com.oracle.graal.python.nodes.SpecialMethodNames.__SUB__;
6565
import static com.oracle.graal.python.nodes.SpecialMethodNames.__TRUEDIV__;
66+
import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError;
6667

6768
import java.util.List;
6869

@@ -98,134 +99,30 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
9899

99100
@GenerateNodeFactory
100101
@Builtin(name = __ABS__, minNumOfPositionalArgs = 1)
101-
abstract static class AbsNode extends PythonBuiltinNode {
102-
@Specialization
103-
double abs(PComplex c) {
104-
double x = c.getReal();
105-
double y = c.getImag();
106-
if (Double.isInfinite(x) || Double.isInfinite(y)) {
107-
return Double.POSITIVE_INFINITY;
108-
} else if (Double.isNaN(x) || Double.isNaN(y)) {
109-
return Double.NaN;
110-
} else {
111-
112-
final int expX = getExponent(x);
113-
final int expY = getExponent(y);
114-
if (expX > expY + 27) {
115-
// y is neglectible with respect to x
116-
return abs(x);
117-
} else if (expY > expX + 27) {
118-
// x is neglectible with respect to y
119-
return abs(y);
120-
} else {
121-
122-
// find an intermediate scale to avoid both overflow and
123-
// underflow
124-
final int middleExp = (expX + expY) / 2;
125-
126-
// scale parameters without losing precision
127-
final double scaledX = scalb(x, -middleExp);
128-
final double scaledY = scalb(y, -middleExp);
102+
public abstract static class AbsNode extends PythonUnaryBuiltinNode {
129103

130-
// compute scaled hypotenuse
131-
final double scaledH = Math.sqrt(scaledX * scaledX + scaledY * scaledY);
104+
public abstract double executeDouble(Object arg);
132105

133-
// remove scaling
134-
return scalb(scaledH, middleExp);
135-
}
136-
}
106+
public static AbsNode create() {
107+
return ComplexBuiltinsFactory.AbsNodeFactory.create();
137108
}
138109

139-
private static final long MASK_NON_SIGN_LONG = 0x7fffffffffffffffL;
140-
141-
static double abs(double x) {
142-
return Double.longBitsToDouble(MASK_NON_SIGN_LONG & Double.doubleToRawLongBits(x));
143-
}
144-
145-
static double scalb(final double d, final int n) {
146-
147-
// first simple and fast handling when 2^n can be represented using
148-
// normal numbers
149-
if ((n > -1023) && (n < 1024)) {
150-
return d * Double.longBitsToDouble(((long) (n + 1023)) << 52);
151-
}
152-
153-
// handle special cases
154-
if (Double.isNaN(d) || Double.isInfinite(d) || (d == 0)) {
155-
return d;
156-
}
157-
if (n < -2098) {
158-
return (d > 0) ? 0.0 : -0.0;
159-
}
160-
if (n > 2097) {
161-
return (d > 0) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
162-
}
163-
164-
// decompose d
165-
final long bits = Double.doubleToRawLongBits(d);
166-
final long sign = bits & 0x8000000000000000L;
167-
int exponent = ((int) (bits >>> 52)) & 0x7ff;
168-
long mantissa = bits & 0x000fffffffffffffL;
169-
170-
// compute scaled exponent
171-
int scaledExponent = exponent + n;
172-
173-
if (n < 0) {
174-
// we are really in the case n <= -1023
175-
if (scaledExponent > 0) {
176-
// both the input and the result are normal numbers, we only
177-
// adjust the exponent
178-
return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa);
179-
} else if (scaledExponent > -53) {
180-
// the input is a normal number and the result is a subnormal
181-
// number
182-
183-
// recover the hidden mantissa bit
184-
mantissa = mantissa | (1L << 52);
185-
186-
// scales down complete mantissa, hence losing least significant
187-
// bits
188-
final long mostSignificantLostBit = mantissa & (1L << (-scaledExponent));
189-
mantissa = mantissa >>> (1 - scaledExponent);
190-
if (mostSignificantLostBit != 0) {
191-
// we need to add 1 bit to round up the result
192-
mantissa++;
193-
}
194-
return Double.longBitsToDouble(sign | mantissa);
195-
196-
} else {
197-
// no need to compute the mantissa, the number scales down to 0
198-
return (sign == 0L) ? 0.0 : -0.0;
199-
}
200-
} else {
201-
// we are really in the case n >= 1024
202-
if (exponent == 0) {
203-
204-
// the input number is subnormal, normalize it
205-
while ((mantissa >>> 52) != 1) {
206-
mantissa = mantissa << 1;
207-
--scaledExponent;
208-
}
209-
++scaledExponent;
210-
mantissa = mantissa & 0x000fffffffffffffL;
211-
212-
if (scaledExponent < 2047) {
213-
return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa);
214-
} else {
215-
return (sign == 0L) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
216-
}
217-
218-
} else if (scaledExponent < 2047) {
219-
return Double.longBitsToDouble(sign | (((long) scaledExponent) << 52) | mantissa);
110+
@Specialization
111+
double abs(PComplex c) {
112+
if (!Double.isFinite(c.getReal()) || !Double.isFinite(c.getImag())) {
113+
if (Double.isInfinite(c.getReal())) {
114+
return Math.abs(c.getReal());
115+
} else if (Double.isInfinite(c.getImag())) {
116+
return Math.abs(c.getImag());
220117
} else {
221-
return (sign == 0L) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
118+
return Double.NaN;
222119
}
223120
}
224-
}
225-
226-
static int getExponent(final double d) {
227-
// NaN and Infinite will return 1024 anywho so can use raw bits
228-
return (int) ((Double.doubleToRawLongBits(d) >>> 52) & 0x7ff) - 1023;
121+
double r = Math.hypot(c.getReal(), c.getImag());
122+
if (Double.isInfinite(r)) {
123+
throw raise(OverflowError, ErrorMessages.ABSOLUTE_VALUE_TOO_LARGE);
124+
}
125+
return r;
229126
}
230127
}
231128

0 commit comments

Comments
 (0)