To flesh-out an siunitx
answer, you might do something like
\documentclass{article}
\usepackage{arrayjobx}
\newarray\MyData
\readarray{MyData}{ 3.14159 & 2077652 & 0.000006543 }
\usepackage{siunitx}
\sisetup{output-exponent-marker = E,round-mode = figures, round-precision = 3,
scientific-notation = true}
\begin{document}
\checkMyData(1)
\num{\cachedata}
\checkMyData(2)
\num{\cachedata}
\checkMyData(3)
\num{\cachedata}
\end{document}
This needs siunitx
v2.2, as the output-exponent-marker
option is new. (I notice that this points up an issue with negative exponents when not using \times 10^{<exponent>}
: I'll take a look at that over the next few days and see what I can do.)
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.
![enter image description here](https://i.stack.imgur.com/UIxxT.png)
\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}
Best Answer
Edit: I am adding a new method which is very nice for computing one by one digits of base 10 logarithms. It was inspired directly from this nice paper.
It is quite faster (I mean the implementation here at TeX macro level) than the method implemented next based on Borchardt algorithms operations.
(the background is that the poor math engine I am using has been too lazy to implement log so far so we have to find workarounds)
Because xintexpr is still lacking
log
I, for fun, did a (high level) usage of Borchardt's algorithm.A tad slow, but well not optimized in any way... (except cutting the table to not too many rows
;-)
).I took the canvas from this answer
Variant algorithm for 48 digits logarithms!
We use Newton method, assuming we have an
exp
function. But we don't have anexp
function so we must program it too...A bit slow in the end...