def getReduced( self ): debugPrint( 'getReduced 1:', self, [ ( i, self.units[ i ] ) for i in self.units ] ) if not g.unitConversionMatrix: loadUnitConversionMatrix( ) value = self.value units = RPNUnits( ) debugPrint( 'value', value ) for unit in self.units: newUnit = g.basicUnitTypes[ getUnitType( unit ) ].baseUnit debugPrint( 'unit', unit, 'newUnit', newUnit ) if unit != newUnit: value = fmul( value, power( mpf( g.unitConversionMatrix[ ( unit, newUnit ) ] ), self.units[ unit ] ) ) units.update( RPNUnits( g.unitOperators[ newUnit ].representation + "^" + str( self.units[ unit ] ) ) ) debugPrint( 'value', value ) reduced = RPNMeasurement( value, units ) debugPrint( 'getReduced 2:', reduced ) return reduced
def combineUnits( units1, units2 ): if not g.unitConversionMatrix: loadUnitConversionMatrix( ) newUnits = RPNUnits( units1 ) factor = mpmathify( 1 ) for unit2 in units2: if unit2 in newUnits: newUnits[ unit2 ] += units2[ unit2 ] else: for unit1 in units1: if unit1 == unit2: newUnits[ unit2 ] += units2[ unit2 ] break elif getUnitType( unit1 ) == getUnitType( unit2 ): factor = fdiv( factor, pow( mpmathify( g.unitConversionMatrix[ ( unit1, unit2 ) ] ), units2[ unit2 ] ) ) newUnits[ unit1 ] += units2[ unit2 ] break else: newUnits[ unit2 ] = units2[ unit2 ] return factor, newUnits
def convertValue( self, other, tryReverse=True ): if self.isEquivalent( other ): return self.getValue( ) if self.isCompatible( other ): conversions = [ ] if isinstance( other, list ): result = [ ] source = self for count, measurement in enumerate( other ): with extradps( 1 ): conversion = source.convertValue( measurement ) if count < len( other ) - 1: result.append( RPNMeasurement( floor( conversion ), measurement.getUnits( ) ) ) source = RPNMeasurement( chop( frac( conversion ) ), measurement.getUnits( ) ) else: result.append( RPNMeasurement( conversion, measurement.getUnits( ) ) ) return result units1 = self.getUnits( ) units2 = other.getUnits( ) unit1String = units1.getUnitString( ) unit2String = units2.getUnitString( ) debugPrint( 'unit1String: ', unit1String ) debugPrint( 'unit2String: ', unit2String ) if unit1String == unit2String: return fmul( self.getValue( ), other.getValue( ) ) if unit1String in g.operatorAliases: unit1String = g.operatorAliases[ unit1String ] if unit2String in g.operatorAliases: unit2String = g.operatorAliases[ unit2String ] exponents = { } if not g.unitConversionMatrix: loadUnitConversionMatrix( ) # look for a straight-up conversion unit1NoStar = unit1String.replace( '*', '-' ) unit2NoStar = unit2String.replace( '*', '-' ) debugPrint( 'unit1NoStar: ', unit1NoStar ) debugPrint( 'unit2NoStar: ', unit2NoStar ) if ( unit1NoStar, unit2NoStar ) in g.unitConversionMatrix: value = fmul( self.value, mpmathify( g.unitConversionMatrix[ ( unit1NoStar, unit2NoStar ) ] ) ) elif ( unit1NoStar, unit2NoStar ) in specialUnitConversionMatrix: value = specialUnitConversionMatrix[ ( unit1NoStar, unit2NoStar ) ]( self.value ) else: # otherwise, we need to figure out how to do the conversion conversionValue = mpmathify( 1 ) # if that isn't found, then we need to do the hard work and break the units down newUnits1 = RPNUnits( ) for unit in units1: newUnits1.update( RPNUnits( g.unitOperators[ unit ].representation + "^" + str( units1[ unit ] ) ) ) newUnits2 = RPNUnits( ) for unit in units2: newUnits2.update( RPNUnits( g.unitOperators[ unit ].representation + "^" + str( units2[ unit ] ) ) ) debugPrint( 'units1:', units1 ) debugPrint( 'units2:', units2 ) debugPrint( 'newUnits1:', newUnits1 ) debugPrint( 'newUnits2:', newUnits2 ) debugPrint( ) debugPrint( 'iterating through units:' ) for unit1 in newUnits1: foundConversion = False for unit2 in newUnits2: debugPrint( 'units 1:', unit1, newUnits1[ unit1 ], getUnitType( unit1 ) ) debugPrint( 'units 2:', unit2, newUnits2[ unit2 ], getUnitType( unit2 ) ) if getUnitType( unit1 ) == getUnitType( unit2 ): conversions.append( [ unit1, unit2 ] ) exponents[ ( unit1, unit2 ) ] = units1[ unit1 ] foundConversion = True break if not foundConversion: debugPrint( 'didn\'t find a conversion, try reducing' ) reduced = self.getReduced( ) debugPrint( 'reduced:', self.units, 'becomes', reduced.units ) reducedOther = other.getReduced( ) debugPrint( 'reduced other:', other.units, 'becomes', reducedOther.units ) # check to see if reducing did anything and bail if it didn't... bail out if ( reduced.units == self.units ) and ( reducedOther.units == other.units ): break reduced = reduced.convertValue( reducedOther ) return RPNMeasurement( fdiv( reduced, reducedOther.value ), reducedOther.getUnits( ) ).getValue( ) debugPrint( ) value = conversionValue if not foundConversion: # This is a cheat. The conversion logic has flaws, but if it's possible to do the # conversion in the opposite direction, then we can do that and return the reciprocal. # This allows more conversions without fixing the underlying problems, which will # require some redesign. if tryReverse: return fdiv( 1, other.convertValue( self, False ) ) else: raise ValueError( 'unable to convert ' + self.getUnitString( ) + ' to ' + other.getUnitString( ) ) for conversion in conversions: if conversion[ 0 ] == conversion[ 1 ]: continue # no conversion needed debugPrint( 'unit conversion:', g.unitConversionMatrix[ tuple( conversion ) ] ) debugPrint( 'exponents', exponents ) conversionValue = mpmathify( g.unitConversionMatrix[ tuple( conversion ) ] ) conversionValue = power( conversionValue, exponents[ tuple( conversion ) ] ) debugPrint( 'conversion: ', conversion, conversionValue ) value = fmul( value, conversionValue ) value = fmul( self.value, value ) return value else: if isinstance( other, list ): otherUnit = '[ ' + ', '.join( [ unit.getUnitString( ) for unit in other ] ) + ' ]' else: otherUnit = other.getUnitString( ) raise ValueError( 'incompatible units cannot be converted: ' + self.getUnitString( ) + ' and ' + otherUnit )