|
36 | 36 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
37 | 37 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
38 | 38 | # SOFTWARE.
|
| 39 | +import math |
| 40 | + |
| 41 | +from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, \ |
| 42 | + is_native_object |
39 | 43 |
|
40 |
| -import sys |
41 |
| -from . import CPyExtType, CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON |
42 | 44 | __dir__ = __file__.rpartition("/")[0]
|
43 | 45 |
|
44 | 46 |
|
45 | 47 | def _float_compare(x, y):
|
46 |
| - |
47 | 48 | def isNan(x):
|
48 | 49 | return isinstance(x, float) and x != x
|
49 | 50 |
|
@@ -77,6 +78,17 @@ def __float__(self):
|
77 | 78 | return 2.71828
|
78 | 79 |
|
79 | 80 |
|
| 81 | +NativeFloatSubclass = CPyExtType( |
| 82 | + 'NativeFloatSubclass', |
| 83 | + '', |
| 84 | + struct_base='PyFloatObject base', |
| 85 | + tp_base="&PyFloat_Type", |
| 86 | + tp_new='0', |
| 87 | + tp_alloc='0', |
| 88 | + tp_free='0', |
| 89 | +) |
| 90 | + |
| 91 | + |
80 | 92 | class TestPyFloat(CPyExtTestCase):
|
81 | 93 |
|
82 | 94 | def compile_module(self, name):
|
@@ -185,39 +197,107 @@ def compile_module(self, name):
|
185 | 197 | cmpfunc=unhandled_error_compare
|
186 | 198 | )
|
187 | 199 |
|
| 200 | + |
188 | 201 | class TestPyOSDouble:
|
189 | 202 | def test_PyOS_double_to_string(self):
|
190 |
| - TestPyOS_Double_To_String = CPyExtType("TestPyOS_Double_To_String", |
191 |
| - ''' |
192 |
| - static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) { |
193 |
| - double val = PyFloat_AsDouble(pyval); |
194 |
| - char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL); |
195 |
| - return PyUnicode_FromString(str); |
196 |
| - } |
197 |
| - ''', |
198 |
| - tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}', |
199 |
| - ) |
| 203 | + TestPyOS_Double_To_String = CPyExtType( |
| 204 | + "TestPyOS_Double_To_String", |
| 205 | + ''' |
| 206 | + static PyObject* testPyOS_D_to_Str(PyObject* self, PyObject *pyval) { |
| 207 | + double val = PyFloat_AsDouble(pyval); |
| 208 | + char *str = PyOS_double_to_string(val, 'f', 6, 0x2, NULL); |
| 209 | + return PyUnicode_FromString(str); |
| 210 | + } |
| 211 | + ''', |
| 212 | + tp_methods='{"PyOS_double_to_string_test", (PyCFunction)testPyOS_D_to_Str, METH_O, ""}', |
| 213 | + ) |
200 | 214 | tester = TestPyOS_Double_To_String()
|
201 | 215 | assert tester.PyOS_double_to_string_test(150.604459) == '150.604459'
|
202 | 216 | assert tester.PyOS_double_to_string_test(174.426353) == '174.426353'
|
203 | 217 | assert tester.PyOS_double_to_string_test(151.074362) == '151.074362'
|
204 | 218 | assert tester.PyOS_double_to_string_test(190.08) == '190.080000'
|
205 | 219 |
|
206 | 220 | def test_PyOS_string_to_double(self):
|
207 |
| - TestPyOS_String_To_Double = CPyExtType("TestPyOS_String_To_Double", |
208 |
| - ''' |
209 |
| - static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) { |
210 |
| - char *endptr; |
211 |
| - const char *s = (char *) PyUnicode_AsUTF8(str); |
212 |
| - double ret = PyOS_string_to_double(s, &endptr, NULL); |
213 |
| - if (PyErr_Occurred()) { |
214 |
| - return NULL; |
215 |
| - } |
216 |
| - return PyFloat_FromDouble(ret); |
217 |
| - } |
218 |
| - ''', |
219 |
| - tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}', |
220 |
| - ) |
| 221 | + TestPyOS_String_To_Double = CPyExtType( |
| 222 | + "TestPyOS_String_To_Double", |
| 223 | + ''' |
| 224 | + static PyObject* testPyOS_Str_to_D(PyObject* self, PyObject *str) { |
| 225 | + char *endptr; |
| 226 | + const char *s = (char *) PyUnicode_AsUTF8(str); |
| 227 | + double ret = PyOS_string_to_double(s, &endptr, NULL); |
| 228 | + if (PyErr_Occurred()) { |
| 229 | + return NULL; |
| 230 | + } |
| 231 | + return PyFloat_FromDouble(ret); |
| 232 | + } |
| 233 | + ''', |
| 234 | + tp_methods='{"PyOS_string_to_double_test", (PyCFunction)testPyOS_Str_to_D, METH_O, ""}', |
| 235 | + ) |
221 | 236 | tester = TestPyOS_String_To_Double()
|
222 | 237 | assert tester.PyOS_string_to_double_test('5') == float(5)
|
223 | 238 | assert tester.PyOS_string_to_double_test('150.604459') == float(150.604459)
|
| 239 | + |
| 240 | + |
| 241 | +class TestNativeFloatSubclass: |
| 242 | + def test_create(self): |
| 243 | + f = NativeFloatSubclass(1.0) |
| 244 | + assert is_native_object(f) |
| 245 | + |
| 246 | + class ManagedSubclass(NativeFloatSubclass): |
| 247 | + pass |
| 248 | + |
| 249 | + f = ManagedSubclass(1.0) |
| 250 | + assert is_native_object(f) |
| 251 | + |
| 252 | + def test_methods(self): |
| 253 | + f = NativeFloatSubclass(1.1) |
| 254 | + zero = NativeFloatSubclass(0.0) |
| 255 | + nan = NativeFloatSubclass('nan') |
| 256 | + |
| 257 | + assert bool(f) |
| 258 | + assert not bool(zero) |
| 259 | + |
| 260 | + assert f == 1.1 |
| 261 | + assert nan != nan |
| 262 | + assert f != zero |
| 263 | + assert +f == 1.1 |
| 264 | + assert -f == -1.1 |
| 265 | + assert f > 0 |
| 266 | + assert f < 2 |
| 267 | + assert f >= 1.1 |
| 268 | + assert f <= 1.1 |
| 269 | + assert str(f) == '1.1' |
| 270 | + assert repr(f) == '1.1' |
| 271 | + assert int(f) == 1 |
| 272 | + assert format(f, 'f') == '1.100000' |
| 273 | + assert abs(NativeFloatSubclass(-2.1)) == 2.1 |
| 274 | + assert round(f) == 1.0 |
| 275 | + assert f + 1.0 == 2.1 |
| 276 | + assert 1.0 + f == 2.1 |
| 277 | + assert f * 2 == 2.2 |
| 278 | + assert f - 1.6 == -0.5 |
| 279 | + assert f // 2 == 0.0 |
| 280 | + assert f % 2 == 1.1 |
| 281 | + assert f / 2.0 == 0.55 |
| 282 | + assert f ** 0 == 1.0 |
| 283 | + assert divmod(f, 2) == (0.0, 1.1) |
| 284 | + assert hash(f) == hash(1.1) |
| 285 | + assert f.hex() == (1.1).hex() |
| 286 | + assert f.real == 1.1 |
| 287 | + assert f.imag == 0.0 |
| 288 | + assert f.conjugate() == 1.1 |
| 289 | + assert not f.is_integer() |
| 290 | + assert f.as_integer_ratio() == (1.1).as_integer_ratio() |
| 291 | + assert f.__getnewargs__() == (1.1,) |
| 292 | + |
| 293 | + def test_math(self): |
| 294 | + assert math.isnan(NativeFloatSubclass('nan')) |
| 295 | + assert math.isinf(NativeFloatSubclass('inf')) |
| 296 | + assert not math.isfinite(NativeFloatSubclass('inf')) |
| 297 | + f = NativeFloatSubclass(0.9) |
| 298 | + for fn in [math.ceil, math.floor, math.sqrt, math.exp, math.expm1, math.frexp, math.modf, math.sin, math.asin, |
| 299 | + math.cos, math.acos, math.tan, math.atan, math.log2, math.log10, math.log1p, math.fabs, math.trunc, |
| 300 | + math.degrees, math.radians, math.gamma, math.lgamma, math.sqrt]: |
| 301 | + assert fn(f) == fn(0.9) |
| 302 | + |
| 303 | + assert math.log(f, 10) == math.log(0.9, 10) |
0 commit comments