Skip to content

Commit

Permalink
Python 3 behavior: Divide by zero with no exceptions
Browse files Browse the repository at this point in the history
You can track the idea at https://discuss.python.org/t/python-3-behavior-divide-by-zero-with-no-exceptions/25615

The idea is:

 + Return inf (known as positive infinity) when the numerator is larger than 0.
+ Return -inf (known as negative infinity) when the numerator is smaller than 0.

Some problems in dividing by zero:

 + 0/0 is undefined, since it’s because the conflict in calculating of limitation of equation when x approach 0. The exception is still returned
+ i/0 (where i is the imaginary number) is undefined. The exception is still returned
Dividing a integer, no matter whether it is negative or positive, the result always returns inf. No exception is thrown.
  • Loading branch information
TheFlightSimsOfficial committed Apr 13, 2023
1 parent d034590 commit b0508f3
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 24 deletions.
8 changes: 3 additions & 5 deletions Objects/complexobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ complex_div(PyObject *v, PyObject *w)
errno = 0;
quot = _Py_c_quot(a, b);
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError, "complex division by zero");
PyErr_SetString(PyExc_ZeroDivisionError, "Imaginary numbers cannot be divided by 0");
return NULL;
}
return PyComplex_FromCComplex(quot);
Expand Down Expand Up @@ -527,13 +527,11 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z)

_Py_ADJUST_ERANGE2(p.real, p.imag);
if (errno == EDOM) {
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 to a negative or complex power");
PyErr_SetString(PyExc_ZeroDivisionError, "0 powers imaginary number is undefined");
return NULL;
}
else if (errno == ERANGE) {
PyErr_SetString(PyExc_OverflowError,
"complex exponentiation");
PyErr_SetString(PyExc_OverflowError, "complex exponentiation");
return NULL;
}
return PyComplex_FromCComplex(p);
Expand Down
30 changes: 20 additions & 10 deletions Objects/floatobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,20 @@ float_div(PyObject *v, PyObject *w)
double a,b;
CONVERT_TO_DOUBLE(v, a);
CONVERT_TO_DOUBLE(w, b);

if (b == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"float division by zero");
return NULL;
if (a > 0) {
return PyFloat_FromDouble(+INFINITY);
}
else if (a < 0) {
return PyFloat_FromDouble(-INFINITY);
}
else {
PyErr_SetString(PyExc_ZeroDivisionError, "Cannot divide 0 by 0");
return NULL;
}
}

a = a / b;
return PyFloat_FromDouble(a);
}
Expand All @@ -643,11 +652,14 @@ float_rem(PyObject *v, PyObject *w)
double mod;
CONVERT_TO_DOUBLE(v, vx);
CONVERT_TO_DOUBLE(w, wx);


//It must return NaN, but seems like the python-er don't like it >,<
if (wx == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"float modulo");
PyErr_SetString(PyExc_ZeroDivisionError, "Cannot get the remainder in the division by 0");
return NULL;
}

mod = fmod(vx, wx);
if (mod) {
/* ensure the remainder has the same sign as the denominator */
Expand Down Expand Up @@ -710,7 +722,7 @@ float_divmod(PyObject *v, PyObject *w)
CONVERT_TO_DOUBLE(v, vx);
CONVERT_TO_DOUBLE(w, wx);
if (wx == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()");
PyErr_SetString(PyExc_ZeroDivisionError, "Cannot get the float floor in the division by 0");
return NULL;
}
_float_div_mod(vx, wx, &floordiv, &mod);
Expand All @@ -725,7 +737,7 @@ float_floor_div(PyObject *v, PyObject *w)
CONVERT_TO_DOUBLE(v, vx);
CONVERT_TO_DOUBLE(w, wx);
if (wx == 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError, "float floor division by zero");
PyErr_SetString(PyExc_ZeroDivisionError, "Cannot get the floor in the division by 0");
return NULL;
}
_float_div_mod(vx, wx, &floordiv, &mod);
Expand Down Expand Up @@ -793,9 +805,7 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
if w is negative. */
int iw_is_odd = DOUBLE_IS_ODD_INTEGER(iw);
if (iw < 0.0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"0.0 cannot be raised to a "
"negative power");
PyErr_SetString(PyExc_ZeroDivisionError, "0 powers negative numbers is undefined");
return NULL;
}
/* use correct sign if iw is odd */
Expand Down
31 changes: 22 additions & 9 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2844,10 +2844,16 @@ long_divrem(PyLongObject *a, PyLongObject *b,
PyLongObject *z;

if (size_b == 0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"integer division or modulo by zero");
return -1;

/*
Reason: When dividing by 0, except the numerator equal to the zero, the division returns INFINITY.
In fact, a/b = q (reminder r), means a = bq + r
So, r = a - bq, where q is INFINIY => r = a - b * INFINITY
*/

return PyFloat_FromDouble(size_a - INFINITY * size_b);
}

if (size_a < size_b ||
(size_a == size_b &&
a->long_value.ob_digit[size_a-1] < b->long_value.ob_digit[size_b-1])) {
Expand Down Expand Up @@ -2901,15 +2907,13 @@ long_divrem(PyLongObject *a, PyLongObject *b,
}

/* Int remainder, top-level routine */

static int
long_rem(PyLongObject *a, PyLongObject *b, PyLongObject **prem)
{
Py_ssize_t size_a = _PyLong_DigitCount(a), size_b = _PyLong_DigitCount(b);

if (size_b == 0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"integer modulo by zero");
PyErr_SetString(PyExc_ZeroDivisionError, "Cannot get the remainder in the division by 0");
return -1;
}
if (size_a < size_b ||
Expand Down Expand Up @@ -4269,11 +4273,20 @@ long_true_divide(PyObject *v, PyObject *w)
a_size = _PyLong_DigitCount(a);
b_size = _PyLong_DigitCount(b);
negate = (_PyLong_IsNegative(a)) != (_PyLong_IsNegative(b));

if (b_size == 0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"division by zero");
goto error;
if (a_size > 0) {
return PyFloat_FromDouble(+INFINITY);
}
else if (a_size < 0) {
return PyFloat_FromDouble(-INFINITY);
}
else {
PyErr_SetString(PyExc_ZeroDivisionError, "0 cannot be divided by 0");
goto error;
}
}

if (a_size == 0)
goto underflow_or_zero;

Expand Down

0 comments on commit b0508f3

Please sign in to comment.