Commit 8b47368a authored by Travis Hance's avatar Travis Hance

Merge pull request #507 from tjhance/test_math

made the checks in CheckExact
parents 329f4095 277bac1a
......@@ -16,6 +16,7 @@
#define PYSTON_CAPI_TYPES_H
#include "runtime/capi.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
namespace pyston {
......@@ -72,8 +73,12 @@ public:
assert(varargs->size() == 0);
rtn = (Box*)self->func(self->passthrough, NULL);
} else if (self->ml_flags == METH_O) {
assert(kwargs->d.size() == 0);
assert(varargs->size() == 1);
if (kwargs->d.size() != 0) {
raiseExcHelper(TypeError, "%s() takes no keyword arguments", self->name);
}
if (varargs->size() != 1) {
raiseExcHelper(TypeError, "%s() takes exactly one argument (%d given)", self->name, varargs->size());
}
rtn = (Box*)self->func(self->passthrough, varargs->elts[0]);
} else {
RELEASE_ASSERT(0, "0x%x", self->ml_flags);
......
......@@ -15,9 +15,11 @@
#include <cfloat>
#include <cmath>
#include <cstring>
#include <gmp.h>
#include "core/types.h"
#include "runtime/inline/boxing.h"
#include "runtime/long.h"
#include "runtime/objmodel.h"
#include "runtime/types.h"
#include "runtime/util.h"
......@@ -33,12 +35,38 @@ extern "C" PyObject* PyFloat_FromString(PyObject* v, char** pend) noexcept {
}
extern "C" double PyFloat_AsDouble(PyObject* o) noexcept {
if (o->cls == float_cls)
assert(o);
if (PyFloat_CheckExact(o))
return static_cast<BoxedFloat*>(o)->d;
else if (isSubclass(o->cls, int_cls))
return static_cast<BoxedInt*>(o)->n;
Py_FatalError("unimplemented");
return 0.0;
// special case: int (avoids all the boxing below, and int_cls->tp_as_number
// isn't implemented at the time of this writing)
// This is an exact check.
if (o->cls == int_cls || o->cls == bool_cls)
return (double)static_cast<BoxedInt*>(o)->n;
// special case: long
if (o->cls == long_cls)
return mpz_get_d(static_cast<BoxedLong*>(o)->n);
// implementation from cpython:
PyNumberMethods* nb;
BoxedFloat* fo;
double val;
if ((nb = Py_TYPE(o)->tp_as_number) == NULL || nb->nb_float == NULL) {
PyErr_SetString(PyExc_TypeError, "a float is required");
return -1;
};
fo = (BoxedFloat*)(*nb->nb_float)(o);
if (fo == NULL)
return -1;
if (!PyFloat_Check(fo)) {
PyErr_SetString(PyExc_TypeError, "nb_float should return float object");
return -1;
}
return static_cast<BoxedFloat*>(fo)->d;
}
template <typename T> static inline void raiseDivZeroExcIfZero(T var) {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
======================================
Python IEEE 754 floating point support
======================================
>>> from sys import float_info as FI
>>> from math import *
>>> PI = pi
>>> E = e
You must never compare two floats with == because you are not going to get
what you expect. We treat two floats as equal if the difference between them
is small than epsilon.
>>> EPS = 1E-15
>>> def equal(x, y):
... """Almost equal helper for floats"""
... return abs(x - y) < EPS
NaNs and INFs
=============
In Python 2.6 and newer NaNs (not a number) and infinity can be constructed
from the strings 'inf' and 'nan'.
>>> INF = float('inf')
>>> NINF = float('-inf')
>>> NAN = float('nan')
>>> INF
inf
>>> NINF
-inf
>>> NAN
nan
The math module's ``isnan`` and ``isinf`` functions can be used to detect INF
and NAN:
>>> isinf(INF), isinf(NINF), isnan(NAN)
(True, True, True)
>>> INF == -NINF
True
Infinity
--------
Ambiguous operations like ``0 * inf`` or ``inf - inf`` result in NaN.
>>> INF * 0
nan
>>> INF - INF
nan
>>> INF / INF
nan
However unambigous operations with inf return inf:
>>> INF * INF
inf
>>> 1.5 * INF
inf
>>> 0.5 * INF
inf
>>> INF / 1000
inf
Not a Number
------------
NaNs are never equal to another number, even itself
>>> NAN == NAN
False
>>> NAN < 0
False
>>> NAN >= 0
False
All operations involving a NaN return a NaN except for nan**0 and 1**nan.
>>> 1 + NAN
nan
>>> 1 * NAN
nan
>>> 0 * NAN
nan
>>> 1 ** NAN
1.0
>>> NAN ** 0
1.0
>>> 0 ** NAN
nan
>>> (1.0 + FI.epsilon) * NAN
nan
Misc Functions
==============
The power of 1 raised to x is always 1.0, even for special values like 0,
infinity and NaN.
>>> pow(1, 0)
1.0
>>> pow(1, INF)
1.0
>>> pow(1, -INF)
1.0
>>> pow(1, NAN)
1.0
The power of 0 raised to x is defined as 0, if x is positive. Negative
values are a domain error or zero division error and NaN result in a
silent NaN.
>>> pow(0, 0)
1.0
>>> pow(0, INF)
0.0
>>> pow(0, -INF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> 0 ** -1
Traceback (most recent call last):
...
ZeroDivisionError: 0.0 cannot be raised to a negative power
>>> pow(0, NAN)
nan
Trigonometric Functions
=======================
>>> sin(INF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> sin(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> sin(NAN)
nan
>>> cos(INF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> cos(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> cos(NAN)
nan
>>> tan(INF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> tan(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> tan(NAN)
nan
Neither pi nor tan are exact, but you can assume that tan(pi/2) is a large value
and tan(pi) is a very small value:
>>> tan(PI/2) > 1E10
True
>>> -tan(-PI/2) > 1E10
True
>>> tan(PI) < 1E-15
True
>>> asin(NAN), acos(NAN), atan(NAN)
(nan, nan, nan)
>>> asin(INF), asin(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> acos(INF), acos(NINF)
Traceback (most recent call last):
...
ValueError: math domain error
>>> equal(atan(INF), PI/2), equal(atan(NINF), -PI/2)
(True, True)
Hyberbolic Functions
====================
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment