<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def check_packed_data(self, ds):
 """ 8.1 Simple packing may be achieved through the use of the optional NUG defined attributes scale_factor and add_offset. After the data values of a variable have been read, they are to be multiplied by the scale_factor, and have add_offset added to them. The units of a variable should be representative of the unpacked data. If the scale_factor and add_offset attributes are of the same data type as the associated variable, the unpacked data is assumed to be of the same data type as the packed data. However, if the scale_factor and add_offset attributes are of a different data type from the variable (containing the packed data) then the unpacked data should match the type of these attributes, which must both be of type float or both be of type double. An additional restriction in this case is that the variable containing the packed data must be of type byte, short or int. It is not advised to unpack an int into a float as there is a potential precision loss. When data to be packed contains missing values the attributes that indicate missing values (_FillValue, valid_min, valid_max, valid_range) must be of the same data type as the packed data. :param netCDF4.Dataset ds: An open netCDF dataset :rtype: list :return: List of results """

        ret_val = []
        for name, var in ds.variables.items():

            add_offset = getattr(var, 'add_offset', None)
            scale_factor = getattr(var, 'scale_factor', None)
            if not (add_offset or scale_factor):
                continue

            valid = True
            reasoning = []

            # if only one of these attributes is defined, assume they
            # are the same type (value doesn't matter here)
            if not add_offset:
                add_offset = scale_factor
            if not scale_factor:
                scale_factor = add_offset

            if type(add_offset) != type(scale_factor):
                valid = False
                reasoning.append("Attributes add_offset and scale_factor have different data type.")
            elif type(scale_factor) != var.dtype.type:
                # Check both attributes are type float or double
                if not isinstance(scale_factor, (float, np.floating)):
                    valid = False
                    reasoning.append("Attributes add_offset and scale_factor are not of type float or double.")
                else:
                    # Check variable type is byte, short or int
                    if var.dtype.type not in [np.int, np.int8, np.int16, np.int32, np.int64]:
                        valid = False
                        reasoning.append("Variable is not of type byte, short, or int.")

            result = Result(BaseCheck.MEDIUM, valid, self.section_titles['8.1'], reasoning)
            ret_val.append(result)
            reasoning = []

            valid = True
            # test further with  _FillValue , valid_min , valid_max , valid_range
            if hasattr(var, "_FillValue"):
                if var._FillValue.dtype.type != var.dtype.type:
                    valid = False
                    reasoning.append("Type of %s:_FillValue attribute (%s) does not match variable type (%s)" %
                                     (name, var._FillValue.dtype.type, var.dtype.type))
            if hasattr(var, "valid_min"):
                if var.valid_min.dtype.type != var.dtype.type:
                    valid = False
                    reasoning.append("Type of %svalid_min attribute (%s) does not match variable type (%s)" %
                                     (name, var.valid_min.dtype.type, var.dtype.type))
            if hasattr(var, "valid_max"):
                if var.valid_max.dtype.type != var.dtype.type:
                    valid = False
                    reasoning.append("Type of %s:valid_max attribute (%s) does not match variable type (%s)" %
                                     (name, var.valid_max.dtype.type, var.dtype.type))
            if hasattr(var, "valid_range"):
                if var.valid_range.dtype.type != var.dtype.type:
                    valid = False
                    reasoning.append("Type of %s:valid_range attribute (%s) does not match variable type (%s)" %
                                     (name, var.valid_range.dtype.type, var.dtype.type))

            result = Result(BaseCheck.MEDIUM,
                            valid,
                            self.section_titles['8.1'],
                            reasoning)
            ret_val.append(result)

        return ret_val