提交 58512374 authored 作者: Olivier Delalleau's avatar Olivier Delalleau

Behavior of integer division can now be controlled with config.int_division, and…

Behavior of integer division can now be controlled with config.int_division, and the default value does not break code anymore
上级 98c0bf5f
......@@ -169,6 +169,21 @@ import theano and print the config variable, as in:
customized, see e.g. the in-code help of ``tensor.NumpyAutocaster``). The
'custom' option will be deprecated in a future release of Theano.
.. attribute:: int_division
String value: either 'int', 'floatX' or 'raise'
Default: 'int'
Specifies what to do when one tries to compute `x / y`, where both `x` and
`y` are of integer types (possibly unsigned). 'int' means an integer is
returned (as in Python 2.X), but this behavior is deprecated. 'floatX'
returns a number of type given by ``config.floatX`. 'raise' is the safest
choice (and will become default in a future release of Theano) and raises
an error when one tries to do such an operation, enforcing the use of the
integer division operator (``//``) (if a float result is intended, either
cast one of the arguments to a float, or use `x.__truediv__(y)`).
.. attribute:: mode
String value: 'Mode', 'ProfileMode', 'DebugMode', 'FAST_RUN', 'FAST_COMPILE'
......
......@@ -16,10 +16,16 @@ AddConfigVar('floatX',
)
AddConfigVar('cast_policy',
"Rules for implicit type casting.",
"Rules for implicit type casting",
EnumStr('custom', 'numpy+floatX', 'numpy'),
)
AddConfigVar('int_division',
"What to do when one computes x / y, where both x and y are of "
"integer types",
EnumStr('int', 'raise', 'floatX'),
)
#gpu mean let the driver select the gpu. Needed in case of gpu in exclusive mode.
#gpuX mean use the gpu number X.
AddConfigVar('device',
......
......@@ -12,7 +12,7 @@ If you want to use a scalar variable in a Theano graph,
you probably want to use theano.tensor.[c,z,f,d,b,w,i,l,]scalar!
"""
import math
import math, warnings
from copy import copy
from itertools import imap
......@@ -1022,26 +1022,52 @@ class Sub(BinaryScalarOp):
sub = Sub(upcast_out, name = 'sub')
def div_proxy(x, y):
def int_or_true_div(x_discrete, y_discrete):
"""
Currently used as a check to ensure we are not trying to divide integers.
Return 'int' or 'true' depending on the type of division used for x / y.
:param x_discrete: True if `x` is discrete ([unsigned] integer).
:param y_discrete: True if `x` is discrete ([unsigned] integer).
:returns: 'int' if `x / y` should be an integer division, or `true` if it
should be a true division.
Raises an IntegerDivisionError if both `x_discrete` and `y_discrete` are
True and `config.int_division` is set to 'raise'.
In 0.4 we will get rid of this function to always use true_div:
http://trac-hg.assembla.com/theano/ticket/669
This function is used by both scalar/basic.py and tensor.basic/py.
"""
if (as_scalar(x).type in discrete_types and
as_scalar(y).type in discrete_types):
# Following discussion on theano-dev ("Inconsistent behavior in integer
# division"), we will change the semantics of "/" on integer types in
# Theano 0.4. Until then, it is forbidden to use "/" on integers.
raise IntegerDivisionError(
"Dividing two integers with '/' is currently forbidden "
"to avoid confusion between integer and floating point "
"divisions. Please either use '//' for integer division, or "
"cast one of the arguments to a floating point type for float "
"division.")
if (x_discrete and y_discrete):
if config.int_division == 'raise':
raise IntegerDivisionError(
"With `config.int_division` set to 'raise', dividing two "
"integer types with '/' is forbidden to avoid confusion "
"between integer and floating point divisions. Please "
"use // for integer division, or if you want a float result "
"either cast one of the arguments to a float or directly call "
"`x.__truediv__(y)`.")
elif config.int_division == 'int':
warnings.warn(
"Division of two integer types with x / y is deprecated, "
"please use x // y for an integer division "
"(set `config.int_division = raise` to track the origin "
"of this warning)",
DeprecationWarning)
return 'int'
elif config.int_division == 'floatX':
return 'true'
else:
raise NotImplementedError(config.int_division)
else:
return true_div(x, y)
return 'true'
def div_proxy(x, y):
"""Proxy for either true_div or int_div, depending on types of x, y."""
f = eval('%s_div' % int_or_true_div(as_scalar(x).type in discrete_types,
as_scalar(y).type in discrete_types))
return f(x, y)
class TrueDiv(BinaryScalarOp):
......
......@@ -2584,19 +2584,11 @@ def minimum(x,y):
def div_proxy(x, y):
"""Proxy for either true_div or int_div, depending on types of x, y.
"""
if (as_tensor_variable(x).dtype in discrete_dtypes and
as_tensor_variable(y).dtype in discrete_dtypes):
# See the same in scalar/basic.py
raise IntegerDivisionError(
"Dividing two integer arrays with '/' is currently forbidden "
"to avoid confusion between integer and floating point "
"divisions. Please either use '//' for integer division, or "
"cast one of the arguments to a floating point type for float "
"division.")
else:
return true_div(x, y)
"""Proxy for either true_div or int_div, depending on types of x, y."""
f = eval('%s_div' % scal.int_or_true_div(
as_tensor_variable(x).dtype in discrete_dtypes,
as_tensor_variable(y).dtype in discrete_dtypes))
return f(x, y)
@_scal_elemwise_with_nfunc('add', 2, 1)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论