为什么 pgffor 在 \foreach 循环中估算出 0.1-0=0.100005 ?

为什么 pgffor 在 \foreach 循环中估算出 0.1-0=0.100005 ?

在第 902 页的手册中说

通常,当遇到列表项...时,它之前应该已经有两个列表项,即数字。

数字的例子有 1、-10 或 -0.24。我们把这些数字称为 x 和 y,设d:=y−x它们是差。接下来,三个点后面还应该有一个数字,我们把这个数字称为z

在这种情况下,列表阅读的部分x,y,...,z被替换为x,,,,,...,其中最后的点是语义点,而不是句法点。值 m 是满足以下条件的最大数:或x+d满足以下条件:x+2dx+3dx+mdx+md≤zd is positivex+md ≥ zd is negative

也许最好通过一些例子来解释这一点:以下<list>具有相同的效果:

\foreach \x in {0,0.1,...,0.5} {\x, }0收益率0.1,,,,,0.200010.300020.40002

正如这里x=0,我们推断2d=0.20001,因此只有d=0.100005

编辑: 3d=0.30002因此d=0.10000666666...

编辑:那么,在这种情况下,从条目0中减去,并修改0.1该条目。由于根本没有减去任何内容,这怎么可能呢?这是否意味着减法会从数字中减去某些内容?0.10.100.1

  • 是不是因为 2 进制中的二进制减法用TeX? 用pgffor?
  • TeX?是因为中的数字 0 的二进制编码吗pgffor
  • 如何pgffor计算 foreach 循环中的增量?

使用 www.DeepL.com/Translator 翻译

答案1

是如何\foreach \x in { a, b, ..., z } { <code> }工作的?

基本上,PGF 确实

\start=a pt
\step=b pt
\advance\step by -\start

此处abz应为十进制数,\start\step为dimen寄存器(不是真实名称)。然后,如手册所述,执行<code>具有\start初始值的;然后\advance\start by \step执行并<code>跟进。循环一直持续到\start>z pt(此时<code>不会执行)。这是\step>0pt,但情况\step<0pt类似。

现在,在 TeX 中如何使用 dimen 寄存器进行算术运算?

一个 dimen 寄存器的值以点为单位显示,但实际上以“缩放点”为单位存储,其中一个点是 65536 个缩放点。

在您的例子中,\step设置为 0.1pt,相当于 6554sp。再加 0.1pt 使内部值变为 13108sp。当 13108sp 转换回点时,该值为 0.20001pt。

但是,\dimen0=0.2pt对应于内部值 13107sp,因为 65536 乘以 2 等于 131072。并且0.00001pt是 1sp,即最小非零 TeX 维度。

随着进一步的增加,舍入误差会累积。

应尽可能避免使用\foreach小数值;当值为整数时,不会进行舍入。

答案2

0.1二进制有无限的表示形式。例如,为什么浮点数中不存在 0.1?因此会有舍入误差。此外,正如@DavidCarlisle 在评论中指出的那样,TeX 擅长整数运算,这又增加了一层误差。

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[scale=16]
\foreach \x in {0,0.1,...,0.5}
    \node at (\x,0.1) {\x};
\draw (0,0.05) -- (0.5,0.05);
\foreach \x[evaluate=\x as \y using \x/10] in {0,1,...,5}
    \node at (\y,0) {\y};
\draw (0,-0.05) -- (0.5,-0.05);
\foreach \x[evaluate=\x as \y using \x/10] in {0,1,...,5}
    \node at (\y,-0.1) {\pgfmathprintnumber[fixed,precision=1]{\y}};
\end{tikzpicture}
\end{document}

舍入误差

添加:的二进制表示 0.1

0.00011001100110011...(重复 0011)

如果计算机使用 16 个二进制小数存储上述内容,则将变成

0.0001100110011010

转换回3277/32768 = 0.100006103515625。然后您将得到0.200012207031250.3000183105468750.4000244140625。这里不涉及减法。这只是计算机存储数字的方式。

第二次编辑: 正如 @egreg 指出的那样,TeX 中的实际“浮点运算”是通过维度寄存器实现的。因此,您将受到将 pt转换为 时产生的舍入误差的影响sp

巧合的是,由于3277/32768 = 6554/65536,这符合完美与我上面说明的转换:0.1通过 0.5正在积累恰恰0.1000061035156250.200012207031250.3000183105468750.40002441406250.500030517578125

相关内容