[Tex/LaTex] Reformat \frac depending on numerator/denominator size difference

fractions

Is it possible to detect cases where the second argument of \frac is much smaller than the first argument, and split it? Namely (I'm using a new macro name \wfrac to simplify things),

\wfrac{x}{2} % => \frac{x}{2}
\wfrac{x+y}{2} % => \frac{1}{2}\left(x+y\right)
\wfrac{\sum_{i=1}^{N} i^3}{x+y+z+t}
% => \frac{1}{x+y+z+t} \left(\sum_{i=1}^{N} i^3\right)
% => or \left(\sum_{i=1}^{N} i^3\right) / \left(x+y+z+t\right)
\wfrac{\sum_{i=1}^{N} i^3}{\sum_{i=1}^{N} i}
% => \frac{...}{...} (unchanged)

Feel free to tell me that this is a bad idea.

EDIT: As David notes in his comment, it is not clear what I define as bigger/smaller. The third example in particular features a case where the numerator is taller, but the denominator is wider. he also notes that \wfrac{x}{y} could become (x)/(y). I am building the requirements as I write the question, so feel free to tweak them at your will.

\wfrac{x}{y} should become one of \frac{x}{y}, or \frac{1}{y}(x), or (x)/(y), with ()/ scaling as appropriate. Here is one scheme that could give nice results. Denote hx, hy the heights (plus depths) of x and y; wx, wy their widths; h0 and w0 customizable thresholds for what is considered "small", for instance the dimensions of the formula $a+b$, but probably the threshold should depend on the \mathstyle.

  1. If hy < h0 and wy < w0,

    1. If hx < h0 and wx < max(w0, 2 * wy), use \frac{x}{y}.
    2. Otherwise use \frac{1}{y}(x).
  2. Otherwise use (x)/(y).

Best Answer

I though this was an interesting question, so I gave it a try.
Let me start off with the result:

main.tex:

\documentclass{article}
\usepackage{wfrac}

\begin{document}
\setmaxeq{a+b} % Reference equation for size

\[ \wfrac{x}{2} \]
\[ \wfrac{x+y}{2} \]
\[ \wfrac{\sum_{i=1}^{N} i^3}{x+y+z+t} \]
\[ \wfrac{\sum_{i=1}^{N} i^3}{\sum_{i=1}^{N} i} \]

\setmax{34pt}{10pt} % Manual maximum size

\[ \wfrac{\sum_{i=1}^{N} i^3}{\sum_{i=1}^{N} i} \]

\setmaxeq{x} % Reference equation again

\[ \wfrac{x}{x} \]
\[ \efrac{x}{x} \]
\end{document}

And it looks like this:

result

Options:

  • text: compare to the equation in \textstyle.
  • display: compare to the equation in \displaystyle.
  • none: compare to the equation in whatever style is currently active.
  • noparen: no parentheses
  • small: small maximum height and width
  • big: big maximum height and width
  • huge: huge maximum height and width
  • lparen: set left paren, eg: lparen=\left[
  • rparen: set right paren, eg: rparen={\right]}
  • div: set division mark, eg: div=\div

Commands

  1. \wfrac: fraction following 'less' rules.
  2. \efrac: fraction following 'less or equal' rules.
  3. \setmax: set the maximum size.
  4. \setmaxeq: set the maximum size using a reference equation.
  5. \getmax: get the maximum size.
  6. \getsize: get the size from an equation.
  7. \setparen: set the parentheses, takes two arguments.
  8. \setdiv: set the division mark.

And here is wfrac.sty:

\NeedsTeXFormat{LaTeX2e}[1994/12/01]
\ProvidesPackage{wfrac}[2012/11/03 v1.01 intelligent fractions]

% Lengths and widths
\newdimen \wfrac@hx
\newdimen \wfrac@hy
\newdimen \wfrac@hmax
\newdimen \wfrac@wx
\newdimen \wfrac@wy
\newdimen \wfrac@wmax
\newdimen \wfrac@wmaxcalc

% Parenthesis and division mark
\newcommand*{\wfrac@lparen}{\left(}
\newcommand*{\wfrac@rparen}{\right)}
\newcommand*{\wfrac@div}{\middle/}

% Options
\IfFileExists{xkeyval.sty}{
    \RequirePackage{xkeyval}
    \DeclareOptionX{lparen}{\renewcommand*{\wfrac@lparen}{##1}}
    \DeclareOptionX{rparen}{\renewcommand*{\wfrac@rparen}{##1}}
    \DeclareOptionX{div}{\renewcommand*{\wfrac@div}{##1}}
}{
    \let\DeclareOptionX\DeclareOption
    \let\ExecuteOptionsX\ExecuteOptions
    \let\ProcessOptionsX\ProcessOptions
}

\DeclareOptionX{text}{\edef\wfrac@style{\textstyle}}
\DeclareOptionX{display}{\edef\wfrac@style{\displaystyle}}
\DeclareOptionX{none}{\edef\wfrac@style{}}
\DeclareOptionX{noparen}{\renewcommand*{\wfrac@lparen}{}\renewcommand*{\wfrac@rparen}{}}
\DeclareOptionX{small}{\wfrac@wmax = 25pt \wfrac@hmax = 10pt}
\DeclareOptionX{big}{\wfrac@wmax = 50pt \wfrac@hmax = 50pt}
\DeclareOptionX{huge}{\wfrac@wmax = 100pt \wfrac@hmax = 100pt}
\ExecuteOptionsX{text,small}
\ProcessOptionsX\relax

% Fraction variations
\newcommand*{\wfrac@Afrac}[2]{\left. \wfrac@lparen #1 \wfrac@rparen \wfrac@div \wfrac@lparen #2 \wfrac@rparen \right.}
\newcommand*{\wfrac@Bfrac}[2]{\frac{1}{#2}\wfrac@lparen #1 \wfrac@rparen}
\newcommand*{\wfrac@Cfrac}[2]{\frac{#1}{#2}}

% Main commands
\newcommand*\setparen[2]{
    \renewcommand*{\wfrac@lparen}{#1}
    \renewcommand*{\wfrac@rparen}{#2}
}

\newcommand*\setdiv[1]{
    \renewcommand*{\wfrac@div}{#1}
}

\newcommand*\setmax[2]{
    \wfrac@wmax = #1
    \wfrac@hmax = #2
}

\newcommand*\setmaxeq[1]{
    \settowidth{\wfrac@wmax}{$ \wfrac@style #1 $}
    \settoheight{\wfrac@hmax}{$ \wfrac@style #1 $}
}

\newcommand*\getmax{
    \the\wfrac@wmax $\times$ \the\wfrac@hmax
}

\newcommand*\getsize[1]{
    \settowidth{\wfrac@wx}{$ \wfrac@style #1 $}
    \settoheight{\wfrac@hx}{$ \wfrac@style #1 $}
    \the\wfrac@wx $\times$ \the\wfrac@hx
}

\newcommand*\wfrac[2]{
    \settowidth{\wfrac@wx}{$ \wfrac@style #1 $}
    \settowidth{\wfrac@wy}{$ \wfrac@style #2 $}
    \settoheight{\wfrac@hx}{$ \wfrac@style #1 $}
    \settoheight{\wfrac@hy}{$ \wfrac@style #2 $}    
    % max(w0, 2 * wy)
    \ifdim \wfrac@wmax < 2\wfrac@wy
        \wfrac@wmaxcalc = 2\wfrac@wy
    \else
        \wfrac@wmaxcalc = \wfrac@wmax
    \fi
    %
    \ifdim \wfrac@hy < \wfrac@hmax
        \ifdim \wfrac@wy < \wfrac@wmax
            \ifdim \wfrac@hx < \wfrac@hmax
                \ifdim \wfrac@wx < \wfrac@wmaxcalc
                    \let\wfrac@frac=\wfrac@Cfrac
                \else
                    \let\wfrac@frac=\wfrac@Bfrac
                \fi
            \else
                \let\wfrac@frac=\wfrac@Bfrac
            \fi 
        \else
            \let\wfrac@frac=\wfrac@Afrac
        \fi
    \else
        \let\wfrac@frac=\wfrac@Afrac
    \fi
    %
    \wfrac@frac{#1}{#2}
}

\newcommand*\efrac[2]{
    \settowidth{\wfrac@wx}{$ \wfrac@style #1 $}
    \settowidth{\wfrac@wy}{$ \wfrac@style #2 $}
    \settoheight{\wfrac@hx}{$ \wfrac@style #1 $}
    \settoheight{\wfrac@hy}{$ \wfrac@style #2 $}    
    % max(w0, 2 * wy)
    \ifdim \wfrac@wmax < 2\wfrac@wy
        \wfrac@wmaxcalc = 2\wfrac@wy
    \else
        \wfrac@wmaxcalc = \wfrac@wmax
    \fi
    %
    \ifdim \wfrac@hy > \wfrac@hmax
        \let\wfrac@frac=\wfrac@Afrac
    \else
        \ifdim \wfrac@wy > \wfrac@wmax
            \let\wfrac@frac=\wfrac@Afrac
        \else
            \ifdim \wfrac@hx > \wfrac@hmax
                \let\wfrac@frac=\wfrac@Bfrac
            \else
                \ifdim \wfrac@wx > \wfrac@wmaxcalc
                    \let\wfrac@frac=\wfrac@Bfrac
                \else
                    \let\wfrac@frac=\wfrac@Cfrac
                \fi
            \fi 
        \fi
    \fi
    %
    \wfrac@frac{#1}{#2}
}

\endinput