Commit d0047c43 authored by kenton@google.com's avatar kenton@google.com

In Python, avoid relying on float('inf') and float('nan') as these don't work on…

In Python, avoid relying on float('inf') and float('nan') as these don't work on Windows with Python pre-2.6.
parent eef5f839
......@@ -78,12 +78,27 @@ class GeneratorTest(unittest.TestCase):
def testExtremeDefaultValues(self):
message = unittest_pb2.TestExtremeDefaultValues()
self.assertEquals(float('inf'), message.inf_double)
self.assertEquals(float('-inf'), message.neg_inf_double)
self.assert_(message.nan_double != message.nan_double)
self.assertEquals(float('inf'), message.inf_float)
self.assertEquals(float('-inf'), message.neg_inf_float)
self.assert_(message.nan_float != message.nan_float)
# Python pre-2.6 does not have isinf() or isnan() functions, so we have
# to provide our own.
def isnan(val):
# NaN is never equal to itself.
return val != val
def isinf(val):
# Infinity times zero equals NaN.
return not isnan(val) and isnan(val * 0)
self.assertTrue(isinf(message.inf_double))
self.assertTrue(message.inf_double > 0)
self.assertTrue(isinf(message.neg_inf_double))
self.assertTrue(message.neg_inf_double < 0)
self.assertTrue(isnan(message.nan_double))
self.assertTrue(isinf(message.inf_float))
self.assertTrue(message.inf_float > 0)
self.assertTrue(isinf(message.neg_inf_float))
self.assertTrue(message.neg_inf_float < 0)
self.assertTrue(isnan(message.nan_float))
def testHasDefaultValues(self):
desc = unittest_pb2.TestAllTypes.DESCRIPTOR
......
......@@ -325,10 +325,10 @@ class TokenizerTest(unittest.TestCase):
'{',
(tokenizer.ConsumeIdentifier, 'A'),
':',
(tokenizer.ConsumeFloat, float('inf')),
(tokenizer.ConsumeFloat, text_format._INFINITY),
(tokenizer.ConsumeIdentifier, 'B'),
':',
(tokenizer.ConsumeFloat, float('-inf')),
(tokenizer.ConsumeFloat, -text_format._INFINITY),
(tokenizer.ConsumeIdentifier, 'C'),
':',
(tokenizer.ConsumeBool, True),
......@@ -413,6 +413,16 @@ class TokenizerTest(unittest.TestCase):
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
def testInfNan(self):
# Make sure our infinity and NaN definitions are sound.
self.assertEquals(float, type(text_format._INFINITY))
self.assertEquals(float, type(text_format._NAN))
self.assertTrue(text_format._NAN != text_format._NAN)
inf_times_zero = text_format._INFINITY * 0
self.assertTrue(inf_times_zero != inf_times_zero)
self.assertTrue(text_format._INFINITY > 0)
if __name__ == '__main__':
unittest.main()
......@@ -43,6 +43,12 @@ __all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
'PrintFieldValue', 'Merge' ]
# Infinity and NaN are not explicitly supported by Python pre-2.6, and
# float('inf') does not work on Windows (pre-2.6).
_INFINITY = float('1e10000')
_NAN = _INFINITY * 0
class ParseError(Exception):
"""Thrown in case of ASCII parsing error."""
......@@ -478,12 +484,12 @@ class _Tokenizer(object):
if re.match(self._FLOAT_INFINITY, text):
self.NextToken()
if text.startswith('-'):
return float('-inf')
return float('inf')
return -_INFINITY
return _INFINITY
if re.match(self._FLOAT_NAN, text):
self.NextToken()
return float('nan')
return _NAN
try:
result = float(text)
......
......@@ -168,11 +168,15 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field.default_value_double();
if (value == numeric_limits<double>::infinity()) {
return "float('inf')";
// Python pre-2.6 on Windows does not parse "inf" correctly. However,
// parsing a number that is too big for a double will return infinity.
return "float('1e10000')";
} else if (value == -numeric_limits<double>::infinity()) {
return "float('-inf')";
// See above.
return "float('-1e10000')";
} else if (value != value) {
return "float('nan')";
// infinity * 0 = nan
return "(float('1e10000') * 0)";
} else {
return SimpleDtoa(value);
}
......@@ -180,11 +184,15 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_FLOAT: {
float value = field.default_value_float();
if (value == numeric_limits<float>::infinity()) {
return "float('inf')";
// Python pre-2.6 on Windows does not parse "inf" correctly. However,
// parsing a number that is too big for a double will return infinity.
return "float('1e10000')";
} else if (value == -numeric_limits<float>::infinity()) {
return "float('-inf')";
// See above.
return "float('-1e10000')";
} else if (value != value) {
return "float('nan')";
// infinity - infinity = nan
return "(float('1e10000') - float('1e10000'))";
} else {
return SimpleFtoa(value);
}
......
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