|
63 | 63 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__STR__;
|
64 | 64 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__SUB__;
|
65 | 65 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__TRUEDIV__;
|
| 66 | +import static com.oracle.graal.python.runtime.exception.PythonErrorType.OverflowError; |
66 | 67 |
|
67 | 68 | import java.util.List;
|
68 | 69 |
|
@@ -98,134 +99,30 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
|
98 | 99 |
|
99 | 100 | @GenerateNodeFactory
|
100 | 101 | @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 { |
129 | 103 |
|
130 |
| - // compute scaled hypotenuse |
131 |
| - final double scaledH = Math.sqrt(scaledX * scaledX + scaledY * scaledY); |
| 104 | + public abstract double executeDouble(Object arg); |
132 | 105 |
|
133 |
| - // remove scaling |
134 |
| - return scalb(scaledH, middleExp); |
135 |
| - } |
136 |
| - } |
| 106 | + public static AbsNode create() { |
| 107 | + return ComplexBuiltinsFactory.AbsNodeFactory.create(); |
137 | 108 | }
|
138 | 109 |
|
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()); |
220 | 117 | } else {
|
221 |
| - return (sign == 0L) ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY; |
| 118 | + return Double.NaN; |
222 | 119 | }
|
223 | 120 | }
|
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; |
229 | 126 | }
|
230 | 127 | }
|
231 | 128 |
|
|
0 commit comments