diff --git a/data_specification/enums/data_type.py b/data_specification/enums/data_type.py index 6f08c24..839dfe3 100644 --- a/data_specification/enums/data_type.py +++ b/data_specification/enums/data_type.py @@ -18,6 +18,17 @@ import numpy as np +def _round_to_int(value): + """ Rounds a number to the closest integer + + :param float value: The value to round + :rtype: int + """ + if isinstance(value, int): + return value + return int(round(value)) + + class DataType(Enum): """ Supported data types. @@ -49,7 +60,7 @@ class DataType(Enum): decimal.Decimal("1"), "B", False, - int, + _round_to_int, np.uint8, "8-bit unsigned integer") #: 16-bit unsigned integer @@ -60,7 +71,7 @@ class DataType(Enum): decimal.Decimal("1"), "H", False, - int, + _round_to_int, np.uint16, "16-bit unsigned integer") #: 32-bit unsigned integer @@ -71,7 +82,7 @@ class DataType(Enum): decimal.Decimal("1"), "I", False, - int, + _round_to_int, np.uint32, "32-bit unsigned integer") #: 64-bit unsigned integer @@ -82,7 +93,7 @@ class DataType(Enum): decimal.Decimal("1"), "Q", False, - int, + _round_to_int, np.uint64, "64-bit unsigned integer") #: 8-bit signed integer @@ -93,7 +104,7 @@ class DataType(Enum): decimal.Decimal("1"), "b", False, - int, + _round_to_int, np.int8, "8-bit signed integer") #: 16-bit signed integer @@ -104,7 +115,7 @@ class DataType(Enum): decimal.Decimal("1"), "h", False, - int, + _round_to_int, np.int16, "16-bit signed integer") #: 32-bit signed integer @@ -115,7 +126,7 @@ class DataType(Enum): decimal.Decimal("1"), "i", False, - int, + _round_to_int, np.int32, "32-bit signed integer") #: 64-bit signed integer @@ -126,7 +137,7 @@ class DataType(Enum): decimal.Decimal("1"), "q", False, - int, + _round_to_int, np.int64, "64-bit signed integer") #: 8.8 unsigned fixed point number @@ -386,6 +397,29 @@ def numpy_typename(self): """ return self._numpy_typename + def closest_representable_value(self, value): + """ Returns the closest value to the given value that can be + represented by this type + + :param value: + :type value: float or in + :rtype: float + """ + return self.decode_from_int(self.encode_as_int(value)) + + def closest_representable_value_above(self, value): + """ Returns the closest value above the given value that can be + represented by this type + + :param value: + :type value: float or in + :rtype: float + """ + closest_value = self.decode_from_int(self.encode_as_int(value)) + if closest_value >= value: + return closest_value + return self.decode_from_int(self.encode_as_int(value)+1) + def encode_as_int(self, value): """ Returns the value as an integer, according to this type. @@ -462,6 +496,14 @@ def decode_numpy_array(self, array): """ return array / float(self._scale) + def decode_from_int(self, value): + """ Decode a single value represented as an int according to this type. + + :param int array: + :rtype: float or int + """ + return value / float(self._scale) + def decode_array(self, values): """ Decodes a byte array into iterable of this type. diff --git a/unittests/test_enums.py b/unittests/test_enums.py index c0e37be..79a1aa5 100644 --- a/unittests/test_enums.py +++ b/unittests/test_enums.py @@ -169,6 +169,11 @@ def test_data_type_enum(self): self.assertEqual( DataType.S1615.max, decimal.Decimal("65535.999969482421875")) + self.assertEqual( + DataType.S1615.closest_representable_value(1.00001), 1.0) + self.assertEqual( + DataType.S1615.closest_representable_value_above(0.99997), 1.0) + self.assertEqual(DataType.S3231.value, 13) self.assertEqual(DataType.S3231.size, 8) self.assertEqual(DataType.S3231.min, decimal.Decimal("-4294967296"))