Why doesn't TikZ's \foreach iterate over the last element of the list?
Short answer
The problem illustrated by your example is due to round-off error. See the TikZ/PGF documentation (section 56 in v2.10, p.505; or section 83 in v3.0, p.910):
[...] for fractional steps that are not multiples of 2^{-n} for some small n, rounding errors can occur pretty easily. Thus, in
\foreach \x in {0,0.1,...,0.5} {\x, }
,0.5
should probably be replaced by0.501
for robustness.
In your particular example, using a value slightly greater than 2 (such as 2.0001) for the last element of the list, e.g.
\foreach \x in {1,1.1,...,2.0001}
gives some margin for round-off error and solves the problem.
However, a preferable way of obviating that round-off-error problem is, as suggested in g.kov's answer, percusse's comment, and Qrrbrbirlbel's comment, to iterate over integers and compute the value of interest elsewhere, either like so
\foreach \xx[evaluate={\x=\xx/10}] in {10,11,...,20}
or inside the body of \foreach
:
\foreach \xx in {10,11,...,20}{
\pgfmathsetmacro\x{.1*\xx}
...
}
For a more detailed explanation, see below.
TeX's fixed-point number system
Some real numbers have an infinite binary expansion, i.e. their fractional part contains an infinitely repeating bit pattern. For instance,
0.1 (in decimal form)
corresponds to
0.0001100110011001100110011... (in binary form)
with the bit pattern "0011" repeating "forever". Since finite-precision machine numbers only allocate a limited number of bits for the fractional part of a given real number, they cannot store that infinite expansion and some rounding has to occur. TeX uses a 32-bit fixed-point number representation system, where
- 1 bit is used to flag an overflow (if any),
- 1 bit is used to code the sign of the number,
- 14 bits are used for the integral part of the number,
- 16 bits are used for the fractional part of the number.
It follows that
are the largest and smallest (respectively) TeX numbers. By "TeX numbers", I mean numbers that can be represented exactly using the TeX number representation system. Any real number larger than about 16383.99999 in magnitude will cause an overflow. Moreover, a finite-precision number system can only represent a finite number of real numbers, which means that some real numbers between -16383.99999 +16383.99999 cannot be exactly represented by TeX numbers; those real numbers can be represented only approximately by TeX numbers.
I'm not sure what the rounding rule is in TeX but it seems that a (positive) real number gets
- rounded up if the 17th bit to the right of the binary point (in its binary expansion) is 1,
- truncated if the 17th bit to the right of the binary point (in its binary expansion) is 0,
In the case of 0.1, the 17th bit to the right of the binary point is 1; therefore, 0.1 gets rounded up to the next TeX number, i.e.
0.0001100110011010 (in binary form)
(Compare to the exact value of 0.1 written above.) In summary, the number manipulated by TeX is, not 0.1, but a number slightly larger than 0.1. Conversely
0.2 (in decimal form)
corresponds to
0.001100110011001100110011... (in binary form)
with the pattern "0011" repeating "forever" after the binary point. The 17th bit to the right of the binary point is 0; therefore, 0.2 gets truncated/rounded down to the preceding TeX number i.e.
0.001100110011011 (in binary form)
(Compare to the exact value of 0.2 written above.) In summary, the number manipulated by TeX is, not 0.2, but a number slightly smaller than 0.2.
Mechanics of \foreach
Compile
\documentclass{article}
\usepackage{pgffor}
\begin{document}
\noindent
\foreach \x in {1,1.1,...,2}{\x\\ } \\
\foreach \x in {1,1.2,...,2}{\x\\ }
\end{document}
and you get
To make sense of this output, you need to know a bit about how \foreach
's dots notation works. When \foreach
encounters a ...
element in its list argument, as in \foreach \i in {x,y,...,z}
, it computes the difference d
=y
-x
to fill in the "missing values". According to the TikZ/PGF manual (p.505),
the part of the list reading
x,y,...,z
is replaced byx
,x + d
,x + 2d
,x + 3d
, ...,x + md
, where the last dots are semantic dots, not syntactic dots. The valuem
is the largest number such thatx + md
<=z
ifd
is positive or such thatx + md
>=z
ifd
is negative.
In the case of \foreach \x in {1,1.1,...,2}
, the difference between the first two items is the TeX number 0.1
, which, as explained above, is slightly larger than the real number 0.1. Therefore, the largest m
such that 1+0.1*m
<= 2
is 9. As a result, the final value visited by the loop is, not 2, but a TeX number slightly larger than the mathematical number 1.9.
In the case of \foreach \x in {1,1.2,...,2}
, the difference between the first two items is the TeX number 0.2
, which, as explained above, is slightly smaller than the real number 0.2. Therefore, the largest m
such that 1+0.2*m
<= 2
is 5. As a result, the final value visited by the loop is, not exactly 2, but a TeX number only very slightly smaller than 2, hence the more satisfactory output obtained in this case compared to \foreach \x in {1,1.1,...,2}
.
References
pgffor
's\foreach
command: TikZ/PGF manual, section 56- Fixed-point arithmetic in TeX: http://www.tug.org/TUGboat/tb28-3/tb90beebe.pdf
- Dangers of using non-integer numbers in for loops: http://en.wikipedia.org/wiki/Control_flow#Count-controlled_loops
- PGF engine: TikZ/PGF manual, sections 61-62
Both commands behave exactly the same. The rounding error is the reason that the terminal value is "missed" in the first case. This check
\documentclass{report}
\usepackage{tikz}
\begin{document}
\foreach \x in {1,1.1,...,2}
{\number\x\ }
\foreach \x in {1,1.2,...,2}
{\number\x\ }
\end{document}
results in
1 1.1 1.20001 1.30002 1.40002 1.50003 1.60004 1.70004 1.80005 1.90005
1 1.2 1.4 1.59999 1.79999 1.99998
so, the next value would be greater than 2
in the first case.
The rule of thumb is: never ever use non-integer for the step value in a loop.
Rounding errors, yes, but it doesn't explain everything. \foreach
doesn't use the upper bound of the ellipsis (...)
list but rather relies on comparing the computed value with the upper bound by means of the delta (increment). \newforeach
enforces the upper bound, in the belief that the user intended the upper bound to be used as an explicit point/value.
\documentclass{article}
\usepackage{tikz}
\usepackage{loops}[2013/05/01]
\begin{document}
\begin{tikzpicture}
\draw[dashed] (1,-1) -- (1,2) node[above] {$1$};
\draw[dashed] (2,-1) -- (2,2) node[above] {$2$};
\newforeach \x in {1,1.1,...,2}{
\draw[fill = yellow] (\x,1) circle (0.05);
}
\newforeach \x in {1,1.2,...,2}{
\draw[fill = red] (\x,0) circle (0.05);
}
\end{tikzpicture}
\end{document}