自动添加分数并减少结果(如有必要)

自动添加分数并减少结果(如有必要)

我正在尝试弄清楚如何减少分数。添加分数没有问题,请看此示例:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\newcommand{\addfraction}[4]{% 1N, 1D, 2N, 2D
\pgfmathsetmacro{\newnumerator}{#1*#4+#3*#2}
\pgfmathsetmacro{\newdenominator}{#4*#2}
\pgfkeys{/pgf/number format/.cd,int detect,precision=2}
\[ \frac{#1}{#2} + \frac{#3}{#4} = \frac{\pgfmathprintnumber{\newnumerator}}{\pgfmathprintnumber{\newdenominator}} \]
}

\begin{document}

\addfraction{3}{4}{1}{2}

\end{document}

在本例中,3/4 和 1/2 相加的结果是 10/8,显然可以简化为 5/4。为了做到这一点,我尝试了frac提供的格式TikZ(参见 tikz 手册第 66 节“数字打印”):我计算了分数的十进制值,并通过 返回了结果\pgfmathprintnumber

但这种方法只在一定程度上有效。即使是“简单”任务,第 4/7 行 + 3/8 行也会返回 10000 及以上的分母,而不是 53/56。我还按照说明提高了准确度(frac shift\usepackage{fp}),但仍然没有成功。

现在我知道如何手动约分了,你必须找到最大公约数。但如何以自动化的方式做到这一点?我的猜测是,类似这样的事情隐藏在某个地方,TikZ因为它似乎在使用该格式时应用frac

所以基本上可以归结为:如何找到两个给定数字的最大公约数(最好使用TikZ)?

答案1

2020-04-14:更新以正确输出分母为 1 时的大小写。


使用如何在 LaTeX 中创建随机数学问题?,Cramdir 指出的链接,我们可以采用那里的两个解决方案来实现这一点。一个使用欧几里得算法,另一个使用tkz-fct

为了能够将这两种解决方案打包成一个宏,我们需要使用宏pgfmathtruncatemacro来确保我们处理的是整数,因为\pgfmathsetmacro始终是十进制值。这两种方法都会产生相同的结果。

在此处输入图片描述

以下是使用欧几里得算法的 MWE:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\makeatletter
% Use Euclid's Algorithm to find the greatest 
% common divisor of two integers.
\def\gcd#1#2{{% #1 = a, #2 = b
    \ifnum#2=0 \edef\next{#1}\else
        \@tempcnta=#1 \@tempcntb=#2 \divide\@tempcnta by\@tempcntb
        \multiply\@tempcnta by\@tempcntb  % q*b
        \@tempcntb=#1
        \advance\@tempcntb by-\@tempcnta % remainder in \@tempcntb
        \ifnum\@tempcntb=0
            \@tempcnta=#2
            \ifnum\@tempcnta < 0 \@tempcnta=-\@tempcnta\fi
            \xdef\gcd@next{\noexpand%
                \def\noexpand\thegcd{\the\@tempcnta}}%
        \else
            \xdef\gcd@next{\noexpand\gcd{#2}{\the\@tempcntb}}%
        \fi
    \fi}\gcd@next
}
\newcommand\reduceFrac[2]
{%
   \gcd{#1}{#2}{\@tempcnta=#1 \divide\@tempcnta by\thegcd
   \@tempcntb=#2 \divide\@tempcntb by\thegcd
   \ifnum\@tempcntb<0\relax
      \@tempcntb=-\@tempcntb
        \@tempcnta=-\@tempcnta
    \fi
    \xdef\rfNumer{\the\@tempcnta}
    \xdef\rfDenom{\the\@tempcntb}}%
}
\makeatother

\newcommand*{\fracReduced}[2]{%
    \reduceFrac{#1}{#2}%
    \ensuremath{%
        \ifnum\rfDenom=1
            \rfNumer
        \else
            \frac{\rfNumer}{\rfDenom}%
        \fi
    }%
}%


\newcommand{\addfraction}[4]{% 1N, 1D, 2N, 2D
    \pgfmathsetmacro{\newnumerator}{#1*#4+#3*#2}
    \pgfmathsetmacro{\newdenominator}{#4*#2}
    \pgfmathtruncatemacro{\newnumeratorTrunc}{\newnumerator}
    \pgfmathtruncatemacro{\newdenominatorTrunc}{\newdenominator}
    \pgfkeys{/pgf/number format/.cd,int detect,precision=2}
    \[ \frac{#1}{#2} + \frac{#3}{#4} 
        = \frac{\pgfmathprintnumber{\newnumerator}}{\pgfmathprintnumber{\newdenominator}} 
        = \fracReduced{\newnumeratorTrunc}{\newdenominatorTrunc} 
    \]
}

\begin{document}
\addfraction{3}{4}{1}{2}
\addfraction{3}{4}{5}{4}
\end{document}

下面是使用tikz-fct

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usepackage{tkz-fct}

\newcommand*{\fracReducedTkz}[2]{%
    \tkzReducFrac{#1}{#2}
    \ensuremath{
        \ifnum\tkzMathSecondResult=1
            \tkzMathFirstResult
        \else
            \frac{\tkzMathFirstResult}{\tkzMathSecondResult}
        \fi
    }
}

\newcommand{\addfraction}[4]{% 1N, 1D, 2N, 2D
    \pgfmathsetmacro{\newnumerator}{#1*#4+#3*#2}
    \pgfmathsetmacro{\newdenominator}{#4*#2}
    \pgfmathtruncatemacro{\newnumeratorTrunc}{\newnumerator}
    \pgfmathtruncatemacro{\newdenominatorTrunc}{\newdenominator}
    \pgfkeys{/pgf/number format/.cd,int detect,precision=2}
    \[ \frac{#1}{#2} + \frac{#3}{#4} 
        = \frac{\pgfmathprintnumber{\newnumerator}}{\pgfmathprintnumber{\newdenominator}} 
        = \fracReducedTkz{\newnumeratorTrunc}{\newdenominatorTrunc} 
    \]
}

\begin{document}
\addfraction{3}{4}{1}{2}
\addfraction{3}{4}{5}{4}
\end{document}

命令addfraction是相同的,只是两个示例中的最后一行调用了不同的宏。

答案2

这是一个有趣的 LuaTeX 解决方案,如果有人感兴趣的话。此解决方案处理负数情况和除以零,尽管它需要用 $...$ 括起来。\ifmmode不过,可以使用 进行进一步的调整。

%!TEX program = lualatex
\documentclass{standalone}
\usepackage{luacode}
\usepackage{amsmath}
\begin{luacode*}
function gcd(a,b)
    if b ~= 0 then
        return gcd(b, a % b)
    else
        return math.abs(a)
    end
end
function sgn(a)
    if a == 0 then 
        return 0
    else 
        return a/math.abs(a)
    end 
end
function fractionadd(a,b,c,d)
    local first = a*d + b*c
    local second = b*d
    frac = first/second
    local abs = math.abs
    local afirst = abs(first)
    local asecond = abs(second)
    if second == 0 then
        return [[\text{Impossible to divide by zero}]]
    elseif gcd(afirst,asecond) == asecond then
        return math.floor(sgn(frac)*afirst/(gcd(afirst,asecond)))
    else
        return [[\frac{]]..math.floor(sgn(frac)*(afirst/gcd(afirst,asecond)))..[[}{]]..math.floor(asecond/gcd(afirst,asecond))..[[}]]
    end 
end
\end{luacode*}
\newcommand{\fractionadd}[4]{\directlua{tex.print(fractionadd(#1,#2,#3,#4))}}
\begin{document}
$\fractionadd{8}{2}{9}{3}$,
$\fractionadd{1}{2}{1}{3}$,
$\fractionadd{1}{2}{-1}{3}$.
$\fractionadd{-4}{3}{-2}{3}$,
$\fractionadd{4}{-3}{-10}{6}$,
$\fractionadd{-4}{0}{-2}{3}$,
$\fractionadd{1}{5}{-2}{11}$
\end{document}

在此处输入图片描述

相关内容