How come that in the code below, \foreach is unable to give me round numbers?


\usetikzlibrary{positioning, calc}

\foreach\x in {0.1,0.2,...,0.9}\node at (0,{-2*\x}){\tiny\x};
  • 3
    You should use \pgfmathprintnumber{\x}. I think it is a standard issue of representing floating point numbers in computers, especially when one is using something that was not intended to do mathematical computations. – Peter Grill Aug 20 '14 at 21:05

The more technical explanation is that your step size - the decimal number 0.1 - has no exact binary representation. In binary it has the infinite representation 0.0001100110011..., similar to 1/3 == 0.3333... in decimal.

So if you represent 0.1 using a finite number of bits, there is always an error. And that is what you are seeing here. As percusse said, this error accumulates when pgf adds the inaccurate step value multiple times.

However this is not always the case: If you choose a step size that can be represented exactly in binary, such as 1/8 or 0.125 (0.001 in binary), there is no error:

\foreach\x in {0,0.125,...,1}\node at (0,{-2*\x}){\tiny\x};

Loop with step size 0.125

You can reduce (but not eliminate) the error by using step size 1 and then scaling it down:

\foreach\x [evaluate=\x as \y using \x/10] in {1,2,...,9}\node at (0,{-2*\y}){\tiny\y};

Loop with step size 1, divided by 10

  • So, to have finite representation, it should be of type 1/2^n? – Sigur Jul 14 '15 at 6:33
  • 1
    @Sigur: Correct. Multiples of 1/2^n (for n < 16 I think) can be represented accurately. More precisely, any number which can be represented with 16 fractional bits should work, eg. multiples of 0.375, which is 0.011 in binary. – Fritz Jul 14 '15 at 7:49

It's because whenever you use the ... notation, TikZ performs calculations such as what is the second number 0.2 and what is the first one; 0.1 so what is the step size...

Then it does 0.2-0.1 operation to obtain the step size and TeX precision contaminates this result. After that TikZ starts adding the contaminated 0.1 to 0.2 (not 0.1 because these are given). You get noisy 0.3,0.4,... so on.

If you write down 0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9 explicitly in the list, you can see that there is no problem printing them properly because no arithmetic is performed on the numbers and they are used as is.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.