Here's an approach based on my pythontex package, which provides access to SymPy. I've written some code that takes an expression written with siunitx, converts it to SymPy format (if it's not too complex and doesn't break the regular expressions), and then calculates the result. The SymPy code is accessed with a macro I've called \autocalc, which takes two arguments: an expression written with siunitx, and the desired units for the answer (also written with siunitx). This won't handle everything without some additional regex work, but it should handle most one-line unit conversions.

\documentclass{article}
\usepackage{pythontex}
\usepackage[per-mode=fraction]{siunitx}
% Define some English units
\DeclareSIUnit\inch{in}
\DeclareSIUnit\inches{in}
\DeclareSIUnit\ft{ft}
\DeclareSIUnit\foot{ft}
\DeclareSIUnit\feet{ft}
\DeclareSIUnit\mi{mi}
\DeclareSIUnit\mile{mi}
\DeclareSIUnit\miles{mi}
\begin{sympycode}
from sympy.physics.units import *
import re
def process_units(units):
''' Take units in siunitx form, and convert to SymPy format '''
# Take care of powers
units = units.replace(r'\squared', '**2')
units = re.sub(r'\\square(\\[a-z]+)', r'\1**2', units)
units = units.replace(r'\cubed', '**3')
units = re.sub(r'\\cubic(\\[a-z]+)', r'\1**3', units)
# Take care of \per
units = re.sub(r'\\per(\\[a-z]+\**\d*)', r'/(\1)', units)
# Add in multiplication as needed
units = re.sub(r'(\(*\\[a-z]+(?:\*\*\d+)*\)*)(\\[a-z]+)', r'\1*\2', units)
units = re.sub(r'(\(*\\[a-z]+(?:\*\*\d+)*\)*)(\\[a-z]+)', r'\1*\2', units)
# Finally, remove backslashes
units = units.replace('\\', '')
return units
def process_SI(matchobj):
''' Take an \SI macro, and convert it to SymPy form '''
num, units = matchobj.groups()
units = process_units(units)
result = num + '*' + units
return result
def calc_SI_expression(expr, final_units):
''' Turn a series of siunitx expressions into SymPy form, perform
the calculation, and return the answer in the desired units '''
# Get rid of spaces in code from TeX
expr = expr.replace(' ', '')
final_units = final_units.replace(' ', '')
# Start assembling the final result
result = expr + ' = '
# Take care of multiplication and \left and \right
expr = expr.replace('^', '**')
expr = expr.replace(r'\left', '').replace(r'\right', '')
expr = expr.replace('\\times', '*')
# Convert all \SI macros to SymPy form
expr = re.sub(r'\\SI\{(.+?)\}\{(.+?)\}', process_SI, expr)
expr = re.sub(r'\\frac\{(.+?)\}\{(.+?)\}', r'(\1)/(\2)', expr)
# Evaluate the string that is now in SymPy form
expr = eval(expr + '/(' + process_units(final_units) + ')')
# Round the result to a desired number of places
expr = round(float(expr), 6)
# Return original equation plus calculated result
return result + '\SI{{{0}}}{{{1}}}'.format(expr, final_units)
\end{sympycode}
% Define a shortcut for accessing the Python function
\newcommand{\autocalc}[2]{\sympy{calc_SI_expression(r"#1", r"#2")}}
\begin{document}
\[
\autocalc{
\SI{120000}{\inches}
\times
\frac{\SI{1}{\mile}}{\SI{63360}{\inches}}
}{\miles}
\]
\[
\autocalc{
\SI{2}{\square\feet\per\second}
\times
\left(
\frac{\SI{12}{\inches}}{\SI{1}{\foot}}
\right)^2
\times
\frac{\SI{3600}{\s}}{\SI{1}{\hour}}
}{\square\inches\per\hour}
\]
\end{document}
fp. I've make something like "electronic tables" with it. – Eddy_Em Jan 24 '13 at 16:54\text{}or, better yet, have a look atsiunitx. It won't do anything bad to your hard drive when you feed it miles and inches. – Christian Jan 24 '13 at 19:44\pgfmathparse,\pgfmathresult, and similars frompgfwould work well. I don't know them enough to answer. – Manuel Jan 24 '13 at 23:17