我正在尝试弄清楚如何减少分数。添加分数没有问题,请看此示例:
\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}