Format decimal(i) numbers
Tell Metapost to use better precision (see “3.9 Instances” in the Metafun manual).
\startMPpage[instance=decimalfun]
numeric u;
path yy;
u:= 3cm;
for i=0 step 2/10 until 2:
draw (left--right) shifted (0,i*u); label.lft(textext(decimal(i)), (-2,i*u));
endfor;
yy = (down-- 2 up) scaled u;
draw yy;
\stopMPpage
Nothing is wrong with your code, per se. The issue is that (by default) MetaPost uses a binary number system (scaled point arithmetic in fact, much like TeX). The MetaPost users manual, appendix A, describes it as follows.
The
scaled
number system refers to 32 bit fixed-point arithmetics described in Section 6.1.
A familiar issue common to all binary number systems is storing certain decimal values exactly. Quoting from the same section:
The point is that with base 2 [...] numbers some decimal numbers cannot be represented exactly, among them such strange numbers like 0.1. In a base 2 [...] number format, this value has an infinit [sic] repeating representation, which cannot be stored in a mantissa of finite precision without introducing a rounding error.
Fortunately, one of the interesting things about MetaPost is that we can pick and choose between a couple of different number systems. They are:
- scaled (32 bit binary, scaled point; the default),
- double (64-bit binary, floating point),
- binary (variable precision binary, floating point),
- decimal (variable precision decimal, floating point).
You certainly pay a price in performance for using decimal, but in exchange you can exactly represent values such as 0.2. And practically speaking, you may not notice the difference amidst everything else TeX is doing.
So, what about telling ConTeXt which number system to use. You can tell ConTeXt to use a different MetaPost "instance" which is already configured to use a specific number system. There are various pre-defined instances; for our purposes, we mention four of them:
metafun
(the default instance) uses scaled,doublefun
uses double,binaryfun
uses binary,decimalfun
uses decimal.
The MPcode
environment takes an optional argument to tell it which instance to use. Thus, changing
\startMPcode
...
\stopMPcode
to
\startMPcode{decimalfun}
...
\stopMPcode
will run the code with the decimalfun
instance and thereby "fix" your code.
Another possibility is to say \setupMPinstance[method=<method>]
before your code, where <method>
is one of values scaled
, double
, binary
, and decimal
. Then all the instances will use that number system. In particular, changing your code to
\setupMPinstance[method=decimal]
\startMPcode
...
\stopMPcode
will also resolve the issue.
Metapost is not very good at additions with floating point numbers; it's better at divisions by 10, though.
\documentclass{article}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
beginfig(1);
numeric u;
path yy;
u:= 3cm;
for i=0 step 2 until 20:
draw (left--right) shifted (0,i*u/10); label.lft(textext(decimal(i/10)), (-2,i*u/10));
endfor;
yy = (down-- 2 up) scaled u;
draw yy;
endfig;
\end{mplibcode}
\mplibnumbersystem{decimal}
\begin{mplibcode}
beginfig(2);
numeric u;
path yy;
u:= 3cm;
for i=0 step 2/10 until 2:
draw (left--right) shifted (0,i*u); label.lft(textext(decimal(i)), (-2,i*u));
endfor;
yy = (down-- 2 up) scaled u;
draw yy;
endfig;
\end{mplibcode}
\end{document}
(Sorry, no ConTeXt for me). How you pass the decimal
number system in ConTeXt I don't know, but anyway it's just an example.