7.0pt ≠ x⋅10.0pt for all x

It's not really that TeX floating point calculations are inaccurate, it simply isn't doing floating point at all, so you either need a macro implementation such as the xfp package in Werner's answer, or suitably scale the calculation so that it is accurate in the range of fixed point arithmetic being used by TeX and using integer quantities that can be stored exactly (as opposed to 0.7) also helps.


\setlength{\smallertopskip}{\dimexpr 7\topskip/10\relax}

Topskip: \the\topskip

Smaller: \the\smallertopskip


enter image description here

Although it only really makes a difference in this special case that the value is a known integer. In general, if you are going to need decimal places in the answer just rounding to 1 or two decimal places will ensure a consistent result and not make any real difference to the output, .000001pt isn't very big.

Use xfp:





\setlength{\myLength}{\fpeval{round(0.7 * \topskip, 0)}pt}%


Dimensions in \fpeval are converted to pt and stripped of the dimension part in order to perform calculations (hence the addition of a "closing pt").

If you want you can define

\newcommand{\mult}[2]{\fpeval{round(#1 * #2, 0)}pt}

to support your input


There is no way to get a length of 458752sp from <factor>\topskip if \topskip has the value 10pt, that is, 655360sp, because TeX don't do floating-point computations, but fixed-point base two arithmetic.1

The binary representation of 7/10 is 0.10(1100), parentheses denote the period. and the multiplication rules of TeX can only provide either 458750sp or 458760sp, represented respectively as 6.99997pt and 7.00012pt.

The difference between the upper and lower best representations is 10sp, which is less than 0.000435 millimeters or 0.00016 points.

Since the usual value of \vfuzz is 0.1pt (less than 0.03mm), there should be no concern about getting an “exact” value: you'd need to cumulate more than 680 such errors in order to exceed the \vfuzz.




Topskip: \the\topskip (\number\topskip sp)

70\% topskip: \the\dimexpr 7\topskip/10\relax (\number\dimexpr 7\topskip/10\relax sp)

0.7 topskip: \the\multipletopskip (\number\multipletopskip sp)

0.70001 topskip: \the\multipletopskip (\number\multipletopskip sp)


As you see, 0.7\topskip is accurate up to 2sp, less than 0.00009mm.2

Unless you completely override TeX's computation by using a different model such as IEEE754 (decimal32) as is done in Werner's answer, you can't get “exact” values.


1 When TeX was written, there was no agreed upon standard for floating-point computations and Knuth's aim was to obtain the same output on every machine TeX was implemented on. Using 64 bits instead of 32 could have achieved “better” accuracy, but at the expense of speed and need for memory: PC's of that time might have even less than 640 kiB of RAM.

2 Being a skip, it would be more sensible to use \glueexpr rather than \dimexpr, as noted by GuM in comments. Note that <factor><skip register> will discard the plus and minus components, whereas \multiply and \divide don't. So


could be better.