Is it possible in Latex to convert all numbers between imperial and metric?
Implementing your hack is quite easy:
\newif\ifMetric\Metrictrue% metric by default
\newcommand\MyUnit[2]{\ifMetric #1\else #2\fi}% \MyUnits{metric}{imperial}
Then you can simply use \MyUnit{191cm}{6'3''}
in your document and change between metric and imperial at any point using \Metrictrue
and \Metricfalse
.
Here's a full example (with a crude use of SIunits as requested in the comments):
\documentclass{article}
\usepackage{SIunits}
\newif\ifMetric\Metrictrue% metric by default
\newcommand\MyUnit[2]{\ifMetric #1\else #2\fi}% \MyUnits{metric}{imperial}
\begin{document}
Metric: \MyUnit{191 \centi\meter}{$6'3''$}
\Metricfalse Imperial: \MyUnit{191 \centi\meter}{$6'3''$}
\Metrictrue Metric: \MyUnit{191 \centi\meter}{$6'3''$}
\end{document}
and the output:
Edit: the smartunits package
When I first wrote this post I said that it ought to be possible to do this properly using pgfkeys. Partly as a proof-of-concept, and partly as an exercise to learn how to use pgfkeys
, there is now a smartunits package for converting between metric and Imperial units.
Here is a MWE:
\documentclass{article}
\usepackage{smartunits}
\usepackage{xcolor}
\usepackage{listings}\lstset{language=[LaTeX]TeX}
\lstset{language=[LaTeX]TeX,
texcsstyle=*\bfseries\color{blue},
keywordstyle=\color{blue},
commentstyle=\color{brown},
morekeywords={SmartUnit,SmartUnitSettings,sisetup},
}
\begin{document}
\begin{lstlisting}[texcl]
\SmartUnitSettings{metric imperial, places=1}
\SmartUnit{km=100.0,figures=1} % \SmartUnit{km=100.0,figures=1}
\SmartUnit{miles=62.15,places=1} % \SmartUnit{miles=62.15,places=1}
\SmartUnit{cm=10} % \SmartUnit{cm=10}
\SmartUnit{celsius=20} % \SmartUnit{celsius=20}
\SmartUnit{miles=5.0, figures=1} % \SmartUnit{miles=5.0, figures=1}
\SmartUnit{miles=5.0,places=2} % \SmartUnit{miles=5.0, places=2}
\SmartUnit{hours=0, minutes=59} % \SmartUnit{hours=0, minutes=59}
\SmartUnit{hours=12, minutes=12} % \SmartUnit{hours=12, minutes=12}
\SmartUnit{kg=10.0, places=1} % \SmartUnit{kg=10.0, places=1}
\SmartUnit{pound=10.0,figures=1} % \SmartUnit{pound=10.0,figures=1}
\SmartUnit{l=10.0, places=1} % \SmartUnit{l=10.0, places=1}
\SmartUnit{L=10.0, places=1,uk} % \SmartUnit{L=10.0, places=1,uk}
\end{lstlisting}
\end{document}
and here is the output this produces:
(There is some trickery using the listings package to have LateX typeset the commands after the %
's on each line.)
For the sake of completeness, one option is to just do the unit conversions in LaTeX, using something like pgf/tikz or fp. I am personally of the opinion that this isn't an ideal solution, since there are a lot of edge cases (like, for instance, when to convert between meters and kilometers, or how much to round). It may be sufficient for a nonscientific use, though. With that caveat out of the way, here's a possible implementation.
First, we set up a flag to select between metric and imperial units.
\newif\ifmetric\metrictrue
We can then start by implementing a macro which switches between 24 hour time and 12 hour time, depending on the state of this flag. We'll assume that we input a time in 24 hour form, and convert it to 12 hour time if necessary.
\def\smarttime#1#2{%
\ifmetric%
#1:#2%
\else%
\ifnum#1>12%
\FPeval{\result}{trunc(#1 - 12:0)}%
\result:#2 PM%
\else%
#1:#2 AM%
\fi%
\fi%
}
Basically, what this does is check if the first argument (the hours) is greater than 12. If it is, then it uses the fp package's \FPeval
to subtract 12 from the number of hours. The time is then that new number of hours, followed by the minutes and PM. Otherwise, we just add an AM to the end of the time. This should actually completely work for your needs.
Next, let's do conversion between two units, say kilograms and pounds.
\def\smartkilogram#1{%
\ifmetric%
#1 kg%
\else%
\FPeval{\result}{round(#1 * 2.204:1)}%
\result\ lbs%
\fi%
}
Again we just do the math using \FPeval
and use our flag to switch between metric and imperial units.
Converting between meters and feet plus inches is a little bit more involved, but not fundamentally different from how we did kilograms to pounds.
% Conditionally converts meters to miles/feet/inches
\def\smartmeter#1{%
% Use metric units (meters)
\ifmetric%
\FPeval{\result}{trunc(#1:0)}%
\ifnum\result>1000%
\FPeval{\result}{trunc(#1/1000:1)}%
\result\ km%
\else%
\FPeval{\result}{trunc(#1:2)}%
\result\ m%
\fi%
% Use imperial units (feet and inches)
\else
\FPeval{\result}{trunc((3.281 * #1):0)}%
\ifnum\result<5280%
\FPeval{\result}{(3.281 * #1)}%
\FPeval{\feet}{trunc((\result):0)}%
\FPeval{\inch}{trunc((12 * ((\result) - (\feet))):0)}%
\feet'\inch"%
\else
\FPeval{\feet}{trunc((\result):0)}%
\FPeval{\miles}{trunc((\feet / 5280):1)}%
\miles\ miles%
\fi%
\fi%
}
If you are working with kilometers as well, it might make sense to define something like this:
\def\smartkilometer#1{\FPeval{\result}{trunc((#1 * 1000):0)}\smartmeter{\result}}
What this does is it multiplies whatever number you give it by 1000 and puts that into the \smartmeter
macro. It uses the name of the macro (\smartmeter
vs \smartkilometer
) to keep track of units.
With those macros defined, the following code:
\subsection*{Metric Units}
\metrictrue
Oscar Wilde's height is said to have been \smartmeter{1.91}.\\
Five kilometers is \smartkilometer{5}.\\
It is \smarttime{9}{00}. Later it will be \smarttime{13}{30}.\\
That ostrich weights \smartkilogram{100}!
\subsection*{Imperial Units}
\metricfalse
Oscar Wilde's height is said to have been \smartmeter{1.91}.\\
Five kilometers is \smartkilometer{5}.\\
It is \smarttime{9}{00}. Later it will be \smarttime{13}{30}.\\
That ostrich weights \smartkilogram{100}!
becomes this: