7.0pt ≠ x⋅10.0pt for all x
Consider the following input:
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
Topskip: thetopskip
Smaller: thesmallertopskip
Larger: thelargertopskip
end{document}
Running pdflatex
on it results in
Topskip: 10.0pt
Smaller: 6.99997pt
Larger: 7.00012pt
As you see above, I tried hard to get exactly 7pt as a result of multiplication of some fixed-point constant with topskip
, but failed. Sure, it's very well-known that fixed-point computations are really inaccurate in TeX, but I'm wondering whether some external package could provide us with a rather general-purpose multiplication function (say, mult
) that is more precise than the built-in multiplication such that
newlength{myLength}
setlength{myLength}{mult{x}{topskip}}
themyLength
(or similar code) would result in 7.0pt for some verbatim fixed-point constant x
assuming that topskip
is 10.0pt? Notice that both 7.0 and 10.0 are representable in binary, and the mathematically correct answer x=7/10=0.7 is not representable in binary, but the fixed-point arithmetics is different anyway...
Aside: As some answers and comments notice, the difference between the under- and overapproximation is invisible to the naked eye. But the difference has an effect on potential further computations with myLength
, including choosing, e.g., a font size (which is a non-continuous operation).
lengths arithmetic
|
show 1 more comment
Consider the following input:
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
Topskip: thetopskip
Smaller: thesmallertopskip
Larger: thelargertopskip
end{document}
Running pdflatex
on it results in
Topskip: 10.0pt
Smaller: 6.99997pt
Larger: 7.00012pt
As you see above, I tried hard to get exactly 7pt as a result of multiplication of some fixed-point constant with topskip
, but failed. Sure, it's very well-known that fixed-point computations are really inaccurate in TeX, but I'm wondering whether some external package could provide us with a rather general-purpose multiplication function (say, mult
) that is more precise than the built-in multiplication such that
newlength{myLength}
setlength{myLength}{mult{x}{topskip}}
themyLength
(or similar code) would result in 7.0pt for some verbatim fixed-point constant x
assuming that topskip
is 10.0pt? Notice that both 7.0 and 10.0 are representable in binary, and the mathematically correct answer x=7/10=0.7 is not representable in binary, but the fixed-point arithmetics is different anyway...
Aside: As some answers and comments notice, the difference between the under- and overapproximation is invisible to the naked eye. But the difference has an effect on potential further computations with myLength
, including choosing, e.g., a font size (which is a non-continuous operation).
lengths arithmetic
12
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units ofsp
, where1 pt
equals65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your10 pt
corresponds to655360 sp
, yoursmallertopskip
to458750 sp
, and yourlargertopskip
to458760 sp
. (And your desired “target”7 pt
corresponds to458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.
– ShreevatsaR
Feb 7 at 4:55
7
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between6.9997pt
and7.00012pt
? Please clarify.
– Mico
Feb 7 at 5:39
1
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
1
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe whenmyLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which usesmyLength
inside some macro that is used at many places, tiny changes inmyLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.
– user49915
Feb 7 at 18:47
1
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49
|
show 1 more comment
Consider the following input:
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
Topskip: thetopskip
Smaller: thesmallertopskip
Larger: thelargertopskip
end{document}
Running pdflatex
on it results in
Topskip: 10.0pt
Smaller: 6.99997pt
Larger: 7.00012pt
As you see above, I tried hard to get exactly 7pt as a result of multiplication of some fixed-point constant with topskip
, but failed. Sure, it's very well-known that fixed-point computations are really inaccurate in TeX, but I'm wondering whether some external package could provide us with a rather general-purpose multiplication function (say, mult
) that is more precise than the built-in multiplication such that
newlength{myLength}
setlength{myLength}{mult{x}{topskip}}
themyLength
(or similar code) would result in 7.0pt for some verbatim fixed-point constant x
assuming that topskip
is 10.0pt? Notice that both 7.0 and 10.0 are representable in binary, and the mathematically correct answer x=7/10=0.7 is not representable in binary, but the fixed-point arithmetics is different anyway...
Aside: As some answers and comments notice, the difference between the under- and overapproximation is invisible to the naked eye. But the difference has an effect on potential further computations with myLength
, including choosing, e.g., a font size (which is a non-continuous operation).
lengths arithmetic
Consider the following input:
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
Topskip: thetopskip
Smaller: thesmallertopskip
Larger: thelargertopskip
end{document}
Running pdflatex
on it results in
Topskip: 10.0pt
Smaller: 6.99997pt
Larger: 7.00012pt
As you see above, I tried hard to get exactly 7pt as a result of multiplication of some fixed-point constant with topskip
, but failed. Sure, it's very well-known that fixed-point computations are really inaccurate in TeX, but I'm wondering whether some external package could provide us with a rather general-purpose multiplication function (say, mult
) that is more precise than the built-in multiplication such that
newlength{myLength}
setlength{myLength}{mult{x}{topskip}}
themyLength
(or similar code) would result in 7.0pt for some verbatim fixed-point constant x
assuming that topskip
is 10.0pt? Notice that both 7.0 and 10.0 are representable in binary, and the mathematically correct answer x=7/10=0.7 is not representable in binary, but the fixed-point arithmetics is different anyway...
Aside: As some answers and comments notice, the difference between the under- and overapproximation is invisible to the naked eye. But the difference has an effect on potential further computations with myLength
, including choosing, e.g., a font size (which is a non-continuous operation).
lengths arithmetic
lengths arithmetic
edited Feb 8 at 1:29
user49915
asked Feb 7 at 3:46
user49915user49915
682122
682122
12
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units ofsp
, where1 pt
equals65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your10 pt
corresponds to655360 sp
, yoursmallertopskip
to458750 sp
, and yourlargertopskip
to458760 sp
. (And your desired “target”7 pt
corresponds to458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.
– ShreevatsaR
Feb 7 at 4:55
7
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between6.9997pt
and7.00012pt
? Please clarify.
– Mico
Feb 7 at 5:39
1
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
1
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe whenmyLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which usesmyLength
inside some macro that is used at many places, tiny changes inmyLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.
– user49915
Feb 7 at 18:47
1
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49
|
show 1 more comment
12
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units ofsp
, where1 pt
equals65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your10 pt
corresponds to655360 sp
, yoursmallertopskip
to458750 sp
, and yourlargertopskip
to458760 sp
. (And your desired “target”7 pt
corresponds to458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.
– ShreevatsaR
Feb 7 at 4:55
7
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between6.9997pt
and7.00012pt
? Please clarify.
– Mico
Feb 7 at 5:39
1
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
1
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe whenmyLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which usesmyLength
inside some macro that is used at many places, tiny changes inmyLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.
– user49915
Feb 7 at 18:47
1
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49
12
12
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units of
sp
, where 1 pt
equals 65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your 10 pt
corresponds to 655360 sp
, your smallertopskip
to 458750 sp
, and your largertopskip
to 458760 sp
. (And your desired “target” 7 pt
corresponds to 458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.– ShreevatsaR
Feb 7 at 4:55
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units of
sp
, where 1 pt
equals 65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your 10 pt
corresponds to 655360 sp
, your smallertopskip
to 458750 sp
, and your largertopskip
to 458760 sp
. (And your desired “target” 7 pt
corresponds to 458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.– ShreevatsaR
Feb 7 at 4:55
7
7
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between
6.9997pt
and 7.00012pt
? Please clarify.– Mico
Feb 7 at 5:39
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between
6.9997pt
and 7.00012pt
? Please clarify.– Mico
Feb 7 at 5:39
1
1
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
1
1
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe when
myLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which uses myLength
inside some macro that is used at many places, tiny changes in myLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.– user49915
Feb 7 at 18:47
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe when
myLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which uses myLength
inside some macro that is used at many places, tiny changes in myLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.– user49915
Feb 7 at 18:47
1
1
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49
|
show 1 more comment
4 Answers
4
active
oldest
votes
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.
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{dimexpr 7topskip/10relax}
Topskip: thetopskip
Smaller: thesmallertopskip
end{document}
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.
That's probably better than loading thousands of lines ofexpl3
macros.
– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations withmyLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so usingglueexpr
might hypothetically be more accurate than usingdimexpr
.
– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form<factor><glue>
discards the stretch and shrink components anyway.
– David Carlisle
Feb 7 at 20:11
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
|
show 7 more comments
Use xfp
:
7.0pt
documentclass{article}
usepackage{xfp}
begin{document}
newlength{myLength}%
setlength{myLength}{fpeval{round(0.7 * topskip, 0)}pt}%
themyLength
end{document}
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
setlength{myLength}{mult{0.7}{topskip}}
Thanks! Yourmult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?
– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
@user0 Of course, even withxfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.
– ShreevatsaR
Feb 7 at 6:25
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
@user0 that was a joke. But I would usesetlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.
– Ulrike Fischer
Feb 7 at 19:12
|
show 2 more comments
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
.
documentclass{article}
newlength{multipletopskip}
begin{document}
Topskip: thetopskip (numbertopskip sp)
70% topskip: thedimexpr 7topskip/10relax (numberdimexpr 7topskip/10relax sp)
setlength{multipletopskip}{0.7topskip}
0.7 topskip: themultipletopskip (numbermultipletopskip sp)
setlength{multipletopskip}{0.70001topskip}
0.70001 topskip: themultipletopskip (numbermultipletopskip sp)
end{document}
As you see, 0.7topskip
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.
Footnotes
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
setlength{multipletopskip}{glueexprtopskip*7/10relax}
could be better.
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
This answer contains the implicit remark that eTeX’sdimexpr
(orglueexpr
) provides better precision: why not to make this remark explicit?
– GuM
Feb 7 at 18:59
1
@user0: I don’t think it is a good idea to allow thetopskip
glue to stretch or shrink; nonetheless, Knuth decided to maketopskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, usingglueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to killtpskip
’s shrinkability/stretchability intentionally.
– GuM
Feb 7 at 19:15
1
@user07topskip
discards the stretch, if you don't want to do that usesetlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
|
show 6 more comments
This should not be an answer, but rather a comment both to @egreg’s answer and to David Carlisle’s; unfortunately, I need to include some sample code, and this can only be done (in an intelligible form) in an answer. I willingly concede that it doesn’t add anything substantial to those two answers—except, perhaps, a bit of clarity. I’m ready to remove this answer if either of the abovementioned authors clarifies his.
As already repeatedly remarked, Knuth’s TeX does (or rather, did) its calculations with dimensions using 32-bit fixed points arithmetics; all modern typesetting engines, however, incorporate the so-called “e-TeX” (for Extended, or Enhanced, TeX) extensions, among which is the ability to perform dimension scaling, that is, multiplication of a dimension for a fraction, with 64-bit precision. More precisely, e-TeX extensions introduce a new type of syntax by means of which dimensions can be specified, that enables the use of “expressions”, in the customary sense of the term; in particular, you are allowed to multiply a certain dimension for a fraction, as in
setlengthsomeotherdimen{dimexpr somedimen * 7/10}
(the primitive dimexpr
marks the beginning of a “dimen-valued” expression; the end is implicitly marked by the first token that cannot be interpreted as part of the expression itself—you can assume it is the closing brace, in the above example). When this is done, a 64-bit temporary register is used to hold the intermediate result of the multiplication of the dimension for the numerator of the fraction (somedimen * 7
, in the above example); thank to this expedient, when the subsequent division for the denominator (10, in our case) is performed, all bits of the final (32-bit) result are significant.
As already said, dimexpr
starts a “dimen-valued” expression; there exists a similar primitive for “glue-valued” expressions, named glueexpr
. Note, however, the difference, that others have already explained, between
setlengthsomeotherskip{glueexpr 7someskip /10}
and
setlengthsomeotherskip{glueexpr someskip * 7/10}
In the former, 7someskip
is converted to a dimen value, destroying (that is, zeroing) its stretch and shrink components, if any; this doesn’t happen with the latter.
The following code proves that
setlength{someotherskip}{glueexpr topskip * 7/10}
attains the same precision as explicitly setting someotherskip
to 7pt
(and similarly for the stretch and shrink components, if present):
% My standard header for TeX.SX answers:
documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
usepackage[T1]{fontenc} % Not always necessary, but recommended.
% End of standard header. What follows pertains to the problem at hand.
newcommand*{ReportDimen}[2]{%
#1:>texttt{the #2}\>texttt{(number #2sp)}\%
}
newcommand*{ReportGlue}[2]{%
#1:>texttt{the #2}\>%
texttt{(%
number #2sp
plus numberexpandafterdimexprthegluestretch #2relax sp
minus numberexpandafterdimexprtheglueshrink #2relax sp%
)}\%
}
setlength{topskip}{10.0pt plus 1pt minus 1 pt}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
newlength{eTeXTopskip}
setlength{eTeXTopskip}{glueexpr topskip * 7/10}
newlength{sevenpoints}
setlength{sevenpoints}{7.0pt plus .7pt minus .7pt}
begin{document}
begin{tabbing}
Topskip:quad=kill
ReportGlue {Topskip}{topskip}
ReportDimen{Smaller}{smallertopskip}
ReportDimen{Larger}{largertopskip}
ReportGlue {eTeX's}{eTeXTopskip}
ReportGlue {Exact}{sevenpoints}
end{tabbing}
end{document}
(values in scaled points are shown as well).
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "85"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f473706%2f7-0pt-%25e2%2589%25a0-x%25e2%258b%258510-0pt-for-all-x%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
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.
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{dimexpr 7topskip/10relax}
Topskip: thetopskip
Smaller: thesmallertopskip
end{document}
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.
That's probably better than loading thousands of lines ofexpl3
macros.
– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations withmyLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so usingglueexpr
might hypothetically be more accurate than usingdimexpr
.
– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form<factor><glue>
discards the stretch and shrink components anyway.
– David Carlisle
Feb 7 at 20:11
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
|
show 7 more comments
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.
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{dimexpr 7topskip/10relax}
Topskip: thetopskip
Smaller: thesmallertopskip
end{document}
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.
That's probably better than loading thousands of lines ofexpl3
macros.
– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations withmyLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so usingglueexpr
might hypothetically be more accurate than usingdimexpr
.
– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form<factor><glue>
discards the stretch and shrink components anyway.
– David Carlisle
Feb 7 at 20:11
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
|
show 7 more comments
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.
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{dimexpr 7topskip/10relax}
Topskip: thetopskip
Smaller: thesmallertopskip
end{document}
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.
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.
documentclass{article}
begin{document}
newlength{smallertopskip}
setlength{smallertopskip}{dimexpr 7topskip/10relax}
Topskip: thetopskip
Smaller: thesmallertopskip
end{document}
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.
answered Feb 7 at 7:54
David CarlisleDavid Carlisle
496k4111441890
496k4111441890
That's probably better than loading thousands of lines ofexpl3
macros.
– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations withmyLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so usingglueexpr
might hypothetically be more accurate than usingdimexpr
.
– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form<factor><glue>
discards the stretch and shrink components anyway.
– David Carlisle
Feb 7 at 20:11
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
|
show 7 more comments
That's probably better than loading thousands of lines ofexpl3
macros.
– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations withmyLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so usingglueexpr
might hypothetically be more accurate than usingdimexpr
.
– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form<factor><glue>
discards the stretch and shrink components anyway.
– David Carlisle
Feb 7 at 20:11
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
That's probably better than loading thousands of lines of
expl3
macros.– Henri Menke
Feb 7 at 8:07
That's probably better than loading thousands of lines of
expl3
macros.– Henri Menke
Feb 7 at 8:07
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
@HenriMenke yes but if you know you want a zero decimal places answer it's easy to arrange an integer answer, if you want 75% of 11pt, then perhaps less so, it depends why you are worrying about a +/-.00001 pt difference I suppose.
– David Carlisle
Feb 7 at 11:42
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations with
myLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so using glueexpr
might hypothetically be more accurate than using dimexpr
.– user49915
Feb 7 at 19:39
Thx! Regarding .000001pt: Alone, this difference is invisible. But it does get visible whenever there is further processing and rounding down the pipe (e.g., when choosing a font size depending on some computations with
myLength
). Moreover, GuM said that topskip is a <glue parameter>, not a <dimen parameter>, so using glueexpr
might hypothetically be more accurate than using dimexpr
.– user49915
Feb 7 at 19:39
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form
<factor><glue>
discards the stretch and shrink components anyway.– David Carlisle
Feb 7 at 20:11
@user0 you need an awful lot of rounding to make that visible, it really isn't ever going to happen. How many further calculations are you ever going to do with topskip? and dimexpr and gluexpr are the same here as the form
<factor><glue>
discards the stretch and shrink components anyway.– David Carlisle
Feb 7 at 20:11
1
1
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
@user0 yes that's why I constructed the arithmetic as I did in this answer, keeping all intermediate steps exactly representable *7 divide 10 rather than multiply by 0.7
– David Carlisle
Feb 7 at 20:48
|
show 7 more comments
Use xfp
:
7.0pt
documentclass{article}
usepackage{xfp}
begin{document}
newlength{myLength}%
setlength{myLength}{fpeval{round(0.7 * topskip, 0)}pt}%
themyLength
end{document}
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
setlength{myLength}{mult{0.7}{topskip}}
Thanks! Yourmult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?
– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
@user0 Of course, even withxfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.
– ShreevatsaR
Feb 7 at 6:25
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
@user0 that was a joke. But I would usesetlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.
– Ulrike Fischer
Feb 7 at 19:12
|
show 2 more comments
Use xfp
:
7.0pt
documentclass{article}
usepackage{xfp}
begin{document}
newlength{myLength}%
setlength{myLength}{fpeval{round(0.7 * topskip, 0)}pt}%
themyLength
end{document}
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
setlength{myLength}{mult{0.7}{topskip}}
Thanks! Yourmult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?
– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
@user0 Of course, even withxfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.
– ShreevatsaR
Feb 7 at 6:25
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
@user0 that was a joke. But I would usesetlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.
– Ulrike Fischer
Feb 7 at 19:12
|
show 2 more comments
Use xfp
:
7.0pt
documentclass{article}
usepackage{xfp}
begin{document}
newlength{myLength}%
setlength{myLength}{fpeval{round(0.7 * topskip, 0)}pt}%
themyLength
end{document}
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
setlength{myLength}{mult{0.7}{topskip}}
Use xfp
:
7.0pt
documentclass{article}
usepackage{xfp}
begin{document}
newlength{myLength}%
setlength{myLength}{fpeval{round(0.7 * topskip, 0)}pt}%
themyLength
end{document}
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
setlength{myLength}{mult{0.7}{topskip}}
answered Feb 7 at 3:54
WernerWerner
449k729951700
449k729951700
Thanks! Yourmult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?
– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
@user0 Of course, even withxfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.
– ShreevatsaR
Feb 7 at 6:25
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
@user0 that was a joke. But I would usesetlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.
– Ulrike Fischer
Feb 7 at 19:12
|
show 2 more comments
Thanks! Yourmult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?
– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
@user0 Of course, even withxfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.
– ShreevatsaR
Feb 7 at 6:25
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
@user0 that was a joke. But I would usesetlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.
– Ulrike Fischer
Feb 7 at 19:12
Thanks! Your
mult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?– user49915
Feb 7 at 5:14
Thanks! Your
mult
contains, I guess, rounding, so is it really more precise than the built-in TeX multiplication?– user49915
Feb 7 at 5:14
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
@user0: It may counter the errors that could result from floating point computations.
– Werner
Feb 7 at 5:28
1
1
@user0 Of course, even with
xfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to 0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.– ShreevatsaR
Feb 7 at 6:25
@user0 Of course, even with
xfp
(or any approach) once you assign to a length, you'll only get integer multiples of 1 sp (= 1/65536 pt), so this only affects the rounding that happens to 0.7
(or whatever) before the multiplication; it doesn't affect the range of possible values for the length at the end.– ShreevatsaR
Feb 7 at 6:25
4
4
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
This looks like a quite complicated way to say setlength{mylenth}{7pt}.
– Ulrike Fischer
Feb 7 at 7:50
2
2
@user0 that was a joke. But I would use
setlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.– Ulrike Fischer
Feb 7 at 19:12
@user0 that was a joke. But I would use
setlength{myLength}{fpeval{dim_to_decimal:n {topskip} * 0.7}pt}
instead of rounding the result.– Ulrike Fischer
Feb 7 at 19:12
|
show 2 more comments
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
.
documentclass{article}
newlength{multipletopskip}
begin{document}
Topskip: thetopskip (numbertopskip sp)
70% topskip: thedimexpr 7topskip/10relax (numberdimexpr 7topskip/10relax sp)
setlength{multipletopskip}{0.7topskip}
0.7 topskip: themultipletopskip (numbermultipletopskip sp)
setlength{multipletopskip}{0.70001topskip}
0.70001 topskip: themultipletopskip (numbermultipletopskip sp)
end{document}
As you see, 0.7topskip
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.
Footnotes
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
setlength{multipletopskip}{glueexprtopskip*7/10relax}
could be better.
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
This answer contains the implicit remark that eTeX’sdimexpr
(orglueexpr
) provides better precision: why not to make this remark explicit?
– GuM
Feb 7 at 18:59
1
@user0: I don’t think it is a good idea to allow thetopskip
glue to stretch or shrink; nonetheless, Knuth decided to maketopskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, usingglueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to killtpskip
’s shrinkability/stretchability intentionally.
– GuM
Feb 7 at 19:15
1
@user07topskip
discards the stretch, if you don't want to do that usesetlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
|
show 6 more comments
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
.
documentclass{article}
newlength{multipletopskip}
begin{document}
Topskip: thetopskip (numbertopskip sp)
70% topskip: thedimexpr 7topskip/10relax (numberdimexpr 7topskip/10relax sp)
setlength{multipletopskip}{0.7topskip}
0.7 topskip: themultipletopskip (numbermultipletopskip sp)
setlength{multipletopskip}{0.70001topskip}
0.70001 topskip: themultipletopskip (numbermultipletopskip sp)
end{document}
As you see, 0.7topskip
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.
Footnotes
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
setlength{multipletopskip}{glueexprtopskip*7/10relax}
could be better.
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
This answer contains the implicit remark that eTeX’sdimexpr
(orglueexpr
) provides better precision: why not to make this remark explicit?
– GuM
Feb 7 at 18:59
1
@user0: I don’t think it is a good idea to allow thetopskip
glue to stretch or shrink; nonetheless, Knuth decided to maketopskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, usingglueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to killtpskip
’s shrinkability/stretchability intentionally.
– GuM
Feb 7 at 19:15
1
@user07topskip
discards the stretch, if you don't want to do that usesetlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
|
show 6 more comments
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
.
documentclass{article}
newlength{multipletopskip}
begin{document}
Topskip: thetopskip (numbertopskip sp)
70% topskip: thedimexpr 7topskip/10relax (numberdimexpr 7topskip/10relax sp)
setlength{multipletopskip}{0.7topskip}
0.7 topskip: themultipletopskip (numbermultipletopskip sp)
setlength{multipletopskip}{0.70001topskip}
0.70001 topskip: themultipletopskip (numbermultipletopskip sp)
end{document}
As you see, 0.7topskip
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.
Footnotes
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
setlength{multipletopskip}{glueexprtopskip*7/10relax}
could be better.
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
.
documentclass{article}
newlength{multipletopskip}
begin{document}
Topskip: thetopskip (numbertopskip sp)
70% topskip: thedimexpr 7topskip/10relax (numberdimexpr 7topskip/10relax sp)
setlength{multipletopskip}{0.7topskip}
0.7 topskip: themultipletopskip (numbermultipletopskip sp)
setlength{multipletopskip}{0.70001topskip}
0.70001 topskip: themultipletopskip (numbermultipletopskip sp)
end{document}
As you see, 0.7topskip
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.
Footnotes
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
setlength{multipletopskip}{glueexprtopskip*7/10relax}
could be better.
edited Feb 7 at 21:14
answered Feb 7 at 11:33
egregegreg
730k8819283242
730k8819283242
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
This answer contains the implicit remark that eTeX’sdimexpr
(orglueexpr
) provides better precision: why not to make this remark explicit?
– GuM
Feb 7 at 18:59
1
@user0: I don’t think it is a good idea to allow thetopskip
glue to stretch or shrink; nonetheless, Knuth decided to maketopskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, usingglueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to killtpskip
’s shrinkability/stretchability intentionally.
– GuM
Feb 7 at 19:15
1
@user07topskip
discards the stretch, if you don't want to do that usesetlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
|
show 6 more comments
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
This answer contains the implicit remark that eTeX’sdimexpr
(orglueexpr
) provides better precision: why not to make this remark explicit?
– GuM
Feb 7 at 18:59
1
@user0: I don’t think it is a good idea to allow thetopskip
glue to stretch or shrink; nonetheless, Knuth decided to maketopskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, usingglueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to killtpskip
’s shrinkability/stretchability intentionally.
– GuM
Feb 7 at 19:15
1
@user07topskip
discards the stretch, if you don't want to do that usesetlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
2
2
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
In fact, how tiny these differences are becomes clearer when we switch to small units: a difference of 10 sp is about 53 nanometres. As The TeXbook says “Since the wavelength of visible light is approximately 100 sp, [DEK adds comment in texbook.tex: in fact, violet=75sp, red=135sp] rounding errors of a few sp make no difference to the eye”.
– ShreevatsaR
Feb 7 at 12:49
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
Don't you mean 0.1pt is approx. 0.03mm, not 0.3mm? 0.3mm is about 1/3 of a mm, which is about 1/75 of an inch, which is about 1pt not 0.1pt.
– alephzero
Feb 7 at 16:09
1
1
This answer contains the implicit remark that eTeX’s
dimexpr
(or glueexpr
) provides better precision: why not to make this remark explicit?– GuM
Feb 7 at 18:59
This answer contains the implicit remark that eTeX’s
dimexpr
(or glueexpr
) provides better precision: why not to make this remark explicit?– GuM
Feb 7 at 18:59
1
1
@user0: I don’t think it is a good idea to allow the
topskip
glue to stretch or shrink; nonetheless, Knuth decided to make topskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, using glueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to kill tpskip
’s shrinkability/stretchability intentionally.– GuM
Feb 7 at 19:15
@user0: I don’t think it is a good idea to allow the
topskip
glue to stretch or shrink; nonetheless, Knuth decided to make topskip
a <glue parameter>, not a <dimen parameter>, so, in the principle, using glueexpr
should be safer (and more elegant). It depends, however, on what you are trying to achieve: you may well want to kill tpskip
’s shrinkability/stretchability intentionally.– GuM
Feb 7 at 19:15
1
1
@user0
7topskip
discards the stretch, if you don't want to do that use setlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
@user0
7topskip
discards the stretch, if you don't want to do that use setlength{myLengthG}{glueexprtopskip*7/10relax}
– David Carlisle
Feb 7 at 20:15
|
show 6 more comments
This should not be an answer, but rather a comment both to @egreg’s answer and to David Carlisle’s; unfortunately, I need to include some sample code, and this can only be done (in an intelligible form) in an answer. I willingly concede that it doesn’t add anything substantial to those two answers—except, perhaps, a bit of clarity. I’m ready to remove this answer if either of the abovementioned authors clarifies his.
As already repeatedly remarked, Knuth’s TeX does (or rather, did) its calculations with dimensions using 32-bit fixed points arithmetics; all modern typesetting engines, however, incorporate the so-called “e-TeX” (for Extended, or Enhanced, TeX) extensions, among which is the ability to perform dimension scaling, that is, multiplication of a dimension for a fraction, with 64-bit precision. More precisely, e-TeX extensions introduce a new type of syntax by means of which dimensions can be specified, that enables the use of “expressions”, in the customary sense of the term; in particular, you are allowed to multiply a certain dimension for a fraction, as in
setlengthsomeotherdimen{dimexpr somedimen * 7/10}
(the primitive dimexpr
marks the beginning of a “dimen-valued” expression; the end is implicitly marked by the first token that cannot be interpreted as part of the expression itself—you can assume it is the closing brace, in the above example). When this is done, a 64-bit temporary register is used to hold the intermediate result of the multiplication of the dimension for the numerator of the fraction (somedimen * 7
, in the above example); thank to this expedient, when the subsequent division for the denominator (10, in our case) is performed, all bits of the final (32-bit) result are significant.
As already said, dimexpr
starts a “dimen-valued” expression; there exists a similar primitive for “glue-valued” expressions, named glueexpr
. Note, however, the difference, that others have already explained, between
setlengthsomeotherskip{glueexpr 7someskip /10}
and
setlengthsomeotherskip{glueexpr someskip * 7/10}
In the former, 7someskip
is converted to a dimen value, destroying (that is, zeroing) its stretch and shrink components, if any; this doesn’t happen with the latter.
The following code proves that
setlength{someotherskip}{glueexpr topskip * 7/10}
attains the same precision as explicitly setting someotherskip
to 7pt
(and similarly for the stretch and shrink components, if present):
% My standard header for TeX.SX answers:
documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
usepackage[T1]{fontenc} % Not always necessary, but recommended.
% End of standard header. What follows pertains to the problem at hand.
newcommand*{ReportDimen}[2]{%
#1:>texttt{the #2}\>texttt{(number #2sp)}\%
}
newcommand*{ReportGlue}[2]{%
#1:>texttt{the #2}\>%
texttt{(%
number #2sp
plus numberexpandafterdimexprthegluestretch #2relax sp
minus numberexpandafterdimexprtheglueshrink #2relax sp%
)}\%
}
setlength{topskip}{10.0pt plus 1pt minus 1 pt}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
newlength{eTeXTopskip}
setlength{eTeXTopskip}{glueexpr topskip * 7/10}
newlength{sevenpoints}
setlength{sevenpoints}{7.0pt plus .7pt minus .7pt}
begin{document}
begin{tabbing}
Topskip:quad=kill
ReportGlue {Topskip}{topskip}
ReportDimen{Smaller}{smallertopskip}
ReportDimen{Larger}{largertopskip}
ReportGlue {eTeX's}{eTeXTopskip}
ReportGlue {Exact}{sevenpoints}
end{tabbing}
end{document}
(values in scaled points are shown as well).
add a comment |
This should not be an answer, but rather a comment both to @egreg’s answer and to David Carlisle’s; unfortunately, I need to include some sample code, and this can only be done (in an intelligible form) in an answer. I willingly concede that it doesn’t add anything substantial to those two answers—except, perhaps, a bit of clarity. I’m ready to remove this answer if either of the abovementioned authors clarifies his.
As already repeatedly remarked, Knuth’s TeX does (or rather, did) its calculations with dimensions using 32-bit fixed points arithmetics; all modern typesetting engines, however, incorporate the so-called “e-TeX” (for Extended, or Enhanced, TeX) extensions, among which is the ability to perform dimension scaling, that is, multiplication of a dimension for a fraction, with 64-bit precision. More precisely, e-TeX extensions introduce a new type of syntax by means of which dimensions can be specified, that enables the use of “expressions”, in the customary sense of the term; in particular, you are allowed to multiply a certain dimension for a fraction, as in
setlengthsomeotherdimen{dimexpr somedimen * 7/10}
(the primitive dimexpr
marks the beginning of a “dimen-valued” expression; the end is implicitly marked by the first token that cannot be interpreted as part of the expression itself—you can assume it is the closing brace, in the above example). When this is done, a 64-bit temporary register is used to hold the intermediate result of the multiplication of the dimension for the numerator of the fraction (somedimen * 7
, in the above example); thank to this expedient, when the subsequent division for the denominator (10, in our case) is performed, all bits of the final (32-bit) result are significant.
As already said, dimexpr
starts a “dimen-valued” expression; there exists a similar primitive for “glue-valued” expressions, named glueexpr
. Note, however, the difference, that others have already explained, between
setlengthsomeotherskip{glueexpr 7someskip /10}
and
setlengthsomeotherskip{glueexpr someskip * 7/10}
In the former, 7someskip
is converted to a dimen value, destroying (that is, zeroing) its stretch and shrink components, if any; this doesn’t happen with the latter.
The following code proves that
setlength{someotherskip}{glueexpr topskip * 7/10}
attains the same precision as explicitly setting someotherskip
to 7pt
(and similarly for the stretch and shrink components, if present):
% My standard header for TeX.SX answers:
documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
usepackage[T1]{fontenc} % Not always necessary, but recommended.
% End of standard header. What follows pertains to the problem at hand.
newcommand*{ReportDimen}[2]{%
#1:>texttt{the #2}\>texttt{(number #2sp)}\%
}
newcommand*{ReportGlue}[2]{%
#1:>texttt{the #2}\>%
texttt{(%
number #2sp
plus numberexpandafterdimexprthegluestretch #2relax sp
minus numberexpandafterdimexprtheglueshrink #2relax sp%
)}\%
}
setlength{topskip}{10.0pt plus 1pt minus 1 pt}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
newlength{eTeXTopskip}
setlength{eTeXTopskip}{glueexpr topskip * 7/10}
newlength{sevenpoints}
setlength{sevenpoints}{7.0pt plus .7pt minus .7pt}
begin{document}
begin{tabbing}
Topskip:quad=kill
ReportGlue {Topskip}{topskip}
ReportDimen{Smaller}{smallertopskip}
ReportDimen{Larger}{largertopskip}
ReportGlue {eTeX's}{eTeXTopskip}
ReportGlue {Exact}{sevenpoints}
end{tabbing}
end{document}
(values in scaled points are shown as well).
add a comment |
This should not be an answer, but rather a comment both to @egreg’s answer and to David Carlisle’s; unfortunately, I need to include some sample code, and this can only be done (in an intelligible form) in an answer. I willingly concede that it doesn’t add anything substantial to those two answers—except, perhaps, a bit of clarity. I’m ready to remove this answer if either of the abovementioned authors clarifies his.
As already repeatedly remarked, Knuth’s TeX does (or rather, did) its calculations with dimensions using 32-bit fixed points arithmetics; all modern typesetting engines, however, incorporate the so-called “e-TeX” (for Extended, or Enhanced, TeX) extensions, among which is the ability to perform dimension scaling, that is, multiplication of a dimension for a fraction, with 64-bit precision. More precisely, e-TeX extensions introduce a new type of syntax by means of which dimensions can be specified, that enables the use of “expressions”, in the customary sense of the term; in particular, you are allowed to multiply a certain dimension for a fraction, as in
setlengthsomeotherdimen{dimexpr somedimen * 7/10}
(the primitive dimexpr
marks the beginning of a “dimen-valued” expression; the end is implicitly marked by the first token that cannot be interpreted as part of the expression itself—you can assume it is the closing brace, in the above example). When this is done, a 64-bit temporary register is used to hold the intermediate result of the multiplication of the dimension for the numerator of the fraction (somedimen * 7
, in the above example); thank to this expedient, when the subsequent division for the denominator (10, in our case) is performed, all bits of the final (32-bit) result are significant.
As already said, dimexpr
starts a “dimen-valued” expression; there exists a similar primitive for “glue-valued” expressions, named glueexpr
. Note, however, the difference, that others have already explained, between
setlengthsomeotherskip{glueexpr 7someskip /10}
and
setlengthsomeotherskip{glueexpr someskip * 7/10}
In the former, 7someskip
is converted to a dimen value, destroying (that is, zeroing) its stretch and shrink components, if any; this doesn’t happen with the latter.
The following code proves that
setlength{someotherskip}{glueexpr topskip * 7/10}
attains the same precision as explicitly setting someotherskip
to 7pt
(and similarly for the stretch and shrink components, if present):
% My standard header for TeX.SX answers:
documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
usepackage[T1]{fontenc} % Not always necessary, but recommended.
% End of standard header. What follows pertains to the problem at hand.
newcommand*{ReportDimen}[2]{%
#1:>texttt{the #2}\>texttt{(number #2sp)}\%
}
newcommand*{ReportGlue}[2]{%
#1:>texttt{the #2}\>%
texttt{(%
number #2sp
plus numberexpandafterdimexprthegluestretch #2relax sp
minus numberexpandafterdimexprtheglueshrink #2relax sp%
)}\%
}
setlength{topskip}{10.0pt plus 1pt minus 1 pt}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
newlength{eTeXTopskip}
setlength{eTeXTopskip}{glueexpr topskip * 7/10}
newlength{sevenpoints}
setlength{sevenpoints}{7.0pt plus .7pt minus .7pt}
begin{document}
begin{tabbing}
Topskip:quad=kill
ReportGlue {Topskip}{topskip}
ReportDimen{Smaller}{smallertopskip}
ReportDimen{Larger}{largertopskip}
ReportGlue {eTeX's}{eTeXTopskip}
ReportGlue {Exact}{sevenpoints}
end{tabbing}
end{document}
(values in scaled points are shown as well).
This should not be an answer, but rather a comment both to @egreg’s answer and to David Carlisle’s; unfortunately, I need to include some sample code, and this can only be done (in an intelligible form) in an answer. I willingly concede that it doesn’t add anything substantial to those two answers—except, perhaps, a bit of clarity. I’m ready to remove this answer if either of the abovementioned authors clarifies his.
As already repeatedly remarked, Knuth’s TeX does (or rather, did) its calculations with dimensions using 32-bit fixed points arithmetics; all modern typesetting engines, however, incorporate the so-called “e-TeX” (for Extended, or Enhanced, TeX) extensions, among which is the ability to perform dimension scaling, that is, multiplication of a dimension for a fraction, with 64-bit precision. More precisely, e-TeX extensions introduce a new type of syntax by means of which dimensions can be specified, that enables the use of “expressions”, in the customary sense of the term; in particular, you are allowed to multiply a certain dimension for a fraction, as in
setlengthsomeotherdimen{dimexpr somedimen * 7/10}
(the primitive dimexpr
marks the beginning of a “dimen-valued” expression; the end is implicitly marked by the first token that cannot be interpreted as part of the expression itself—you can assume it is the closing brace, in the above example). When this is done, a 64-bit temporary register is used to hold the intermediate result of the multiplication of the dimension for the numerator of the fraction (somedimen * 7
, in the above example); thank to this expedient, when the subsequent division for the denominator (10, in our case) is performed, all bits of the final (32-bit) result are significant.
As already said, dimexpr
starts a “dimen-valued” expression; there exists a similar primitive for “glue-valued” expressions, named glueexpr
. Note, however, the difference, that others have already explained, between
setlengthsomeotherskip{glueexpr 7someskip /10}
and
setlengthsomeotherskip{glueexpr someskip * 7/10}
In the former, 7someskip
is converted to a dimen value, destroying (that is, zeroing) its stretch and shrink components, if any; this doesn’t happen with the latter.
The following code proves that
setlength{someotherskip}{glueexpr topskip * 7/10}
attains the same precision as explicitly setting someotherskip
to 7pt
(and similarly for the stretch and shrink components, if present):
% My standard header for TeX.SX answers:
documentclass[a4paper]{article} % To avoid confusion, let us explicitly
% declare the paper format.
usepackage[T1]{fontenc} % Not always necessary, but recommended.
% End of standard header. What follows pertains to the problem at hand.
newcommand*{ReportDimen}[2]{%
#1:>texttt{the #2}\>texttt{(number #2sp)}\%
}
newcommand*{ReportGlue}[2]{%
#1:>texttt{the #2}\>%
texttt{(%
number #2sp
plus numberexpandafterdimexprthegluestretch #2relax sp
minus numberexpandafterdimexprtheglueshrink #2relax sp%
)}\%
}
setlength{topskip}{10.0pt plus 1pt minus 1 pt}
newlength{smallertopskip}
setlength{smallertopskip}{.700004577636718749999999999999999999999999999999topskip}
newlength{largertopskip}
setlength{largertopskip}{.700004577636718750000000000000000000000000000000topskip}
newlength{eTeXTopskip}
setlength{eTeXTopskip}{glueexpr topskip * 7/10}
newlength{sevenpoints}
setlength{sevenpoints}{7.0pt plus .7pt minus .7pt}
begin{document}
begin{tabbing}
Topskip:quad=kill
ReportGlue {Topskip}{topskip}
ReportDimen{Smaller}{smallertopskip}
ReportDimen{Larger}{largertopskip}
ReportGlue {eTeX's}{eTeXTopskip}
ReportGlue {Exact}{sevenpoints}
end{tabbing}
end{document}
(values in scaled points are shown as well).
edited Feb 8 at 17:49
answered Feb 7 at 23:34
GuMGuM
16.7k2459
16.7k2459
add a comment |
add a comment |
Thanks for contributing an answer to TeX - LaTeX Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2ftex.stackexchange.com%2fquestions%2f473706%2f7-0pt-%25e2%2589%25a0-x%25e2%258b%258510-0pt-for-all-x%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
12
To achieve exact results on any system, TeX does not use floating-point at all for lengths. It does everything with integer units of
sp
, where1 pt
equals65536 sp
. (Another way of saying it is that it uses fixed-point arithmetic.) Your10 pt
corresponds to655360 sp
, yoursmallertopskip
to458750 sp
, and yourlargertopskip
to458760 sp
. (And your desired “target”7 pt
corresponds to458752 sp
.) Knuth regrets using binary instead of decimal here, probably because it leads to confusion like this.– ShreevatsaR
Feb 7 at 4:55
7
You wrote, "Sure, it's very well-known that floating-point computations are really inaccurate in TeX." Actually, TeX does not use floating-point arithmetic, for reasons that have been noted many years ago -- by Knuth himself, as well as by others. Instead, as @ShreevatsaR has already point out in a comment, TeX uses fixed-point arithmetic. A separate comment: Are you concerned that there might be a meaningful, i.e., visually observable, difference between
6.9997pt
and7.00012pt
? Please clarify.– Mico
Feb 7 at 5:39
1
(Since I realized an ambiguity in my first comment) Using decimal instead of binary won't change the mathematics (with bounded memory you can have only limited precision), but just makes the human experience easier: e.g. instead of having fractions that are multiples of 1/65536 if you had say 1/10000 or 1/100000, then instead of 0.70000457763671875 being an interesting bound (it's halfway between two representable numbers 45875/65536 = 0.6999969482421875 and 45876/65536 = 0.70001220703125), some consecutive representable numbers may be (say) 0.69999, 0.70000, 0.70001 -- easier to understand.
– ShreevatsaR
Feb 7 at 18:38
1
@Mico You are right, technically speaking, it is fixed point. Corrected. As for the visible difference, there is one under magnification of 300%–400% (some further rounding happens down the pipe when
myLength
is used, which does result in a visible diffirence). For me, the differences accumulate so that in a large book which usesmyLength
inside some macro that is used at many places, tiny changes inmyLength
result in, e.g., changes in the page numbers of (sub)sections, and hence, the table of contents is different depending on whether you under- or overapproximate 7.0pt.– user49915
Feb 7 at 18:47
1
@ShreevatsaR Ok. Frankly, it doesn't matter that much to me whether a decimal or a binary system is used internally.
– user49915
Feb 7 at 18:49