\newbox\mybox{}
\setbox\mybox=\vtop{This is the content of the box} 
\the\ht\mybox\  This is the height of the box
\par
\the\mybox\ This is the number of the box\par
\box16
How do I get a rounded 6.94pt from 6.94444pt ?
\bye

2

  • eTeX 扩展好吗?


    – 

  • 这里的总体目标是什么?正如在答案的评论中所暗示的那样,TeX 将 dimens 存储在sp并进行整数运算,并在最后一刻转换为浮点数。


    – 


5 个回答
5

辅助宏…

\newbox\mybox{}
\setbox\mybox=\vtop{This is the content of the box}
\the\ht\mybox\  This is the height of the box
\par
\the\mybox\ This is the number of the box\par
\box16
How do I get a rounded 6.94pt from 6.94444pt?
\newcount\mycount
\def\myrndaux#1.#2#3#4#5\nil{%
  \ifnum #4>4
    \mycount=#3
    \ifnum\mycount<9
      \advance\mycount by 1
      #1.#2\the\mycount pt%
    \else
      \mycount=#2
      \ifnum\mycount<9
        \advance\mycount by 1
        #1.\the\mycount 0pt%
      \else
        \mycount=#1
        \advance\mycount by 1
        \the\mycount .00pt%
      \fi
    \fi
  \else
    #1.#2#3pt%
  \fi
}%
\def\mydept#1pt{#1}%
\def\myinteger#1.#2\nil{#1}%
\def\mydecimal#1.#2\nil{#2}%
\def\myrnd#1{%
  \edef\tmpa{\expandafter\mydept#1}%
  \edef\tmpb{\expandafter\myinteger\tmpa.0\nil
  .\expandafter\mydecimal\tmpa.0\nil}%
  \expandafter\myrndaux\tmpb 000\nil
}%

\myrnd{6.94444pt} (rounds up)

\myrnd{6.4999pt} (rounds down)

\myrnd{6pt} (stet)

\bye

3

  • 谢谢,这样就好了。也许我对此理解得不够充分,但似乎不够准确。(6pt vs 6.94pt)。请查看我的“解决方法”答案。


    – 


  • @MBE 哦,我只是没有仔细阅读问题并将其四舍五入到最接近的点。如果您在排版中重复使用它,那么太精确也没有多大意义,因为尺寸算术在 tex 中本质上是不准确的。(对于大多数目的来说它“足够好”,但每一步都会引入不准确。)


    – 

  • @MBE 无疑是一种更好的方法,但你只需要几个步骤。请参阅编辑。


    – 

以下定义了一个名为 的不可扩展纯 TeX 宏\round。它具有语法\round{<places>}{<number-like>}并将四舍五入<number-like><places>小数位。负数<places>参数将四舍五入到整数部分(因此\round{-1}{5.5}将导致10)。

它将标记寄存器设置\roundResult为舍入操作的结果。尾随单位保持不变。您<number-like>应该将其扩展为具有前导整数部分的任何内容,然后如果后面是一个点,则必须有一个小数部分(因此\round{2}{3.}会导致低级 TeX 错误)。

\begingroup
\catcode`\@=11
\def\round#1{#1}
\round{%
\endgroup
\csname newcount\endcsname\round@int
\csname newcount\endcsname\round@dec
\csname newcount\endcsname\round@places
\csname newtoks\endcsname\round@trail
\csname newtoks\endcsname\roundResult
\def\round#1#2{%
  \round@places=#1\relax
  \afterassignment\round@afterint
  \round@int=#2\relax
}
\def\round@first#1#2\relax{#1}
\def\round@afterfi#1\fi{\fi#1}
\def\round@collect#1\relax{\roundResult={#1}}
\def\round@afterint#1{%
  \ifx.#1%
    \afterassignment\round@afterdec
    \round@dec=%
  \else
    \ifnum\round@places>0
      \round@places=0
    \fi
    \round@afterfi{\round@intloop#1}%
  \fi
}
\def\round@afterdec{%
  \ifnum\round@places>0
    \expandafter\round@loop
  \else
    \ifnum\round@places=0
      \ifnum\expandafter\round@first\the\round@dec\relax>4
        \advance\round@int1
      \fi
    \fi
    \expandafter\round@intloop
  \fi
}
\def\round@intloop{%
  \round@trail{}%
  \loop\ifnum\round@places<0
    \round@trail\expandafter{\the\round@trail0}%
    \ifnum\round@places=-1
      \advance\round@int5
    \fi
    \divide\round@int10
    \advance\round@places1
    \ifnum\round@int=0
      \round@trail{}%
      \round@places=0
    \fi
  \repeat
  \expandafter\round@collect\the\expandafter\round@int\the\round@trail
}
\def\round@loop{%
  \expandafter\round@count\the\round@dec\relax
  \loop\ifnum\round@places<0
    \ifnum\round@places=-1
      \advance\round@dec5
    \fi
    \divide\round@dec10
    \advance\round@places1
  \repeat
  \expandafter\round@collect
    \the\expandafter\round@int\expandafter.\the\round@dec
}
\def\round@count#1{%
  \ifx\relax#1%
  \else
    \advance\round@places-1
    \expandafter\round@count
  \fi
}
}

\newbox\mybox
\setbox\mybox=\vtop{This is the content of the box}
\the\ht\mybox\ This is the height of the box
\par
\round{2}{\the\ht\mybox}\the\roundResult\ This is the rounded height of the box
\par
\the\mybox\ This is the number of the box\par
\box16
How do I get a rounded 6.94pt from 6.94444pt ?
\bye

也许,你想要这个:

\newdimen\value

\value=6.94444pt

\the\value  % prints 6.94444pt

\let\ea=\expandafter
\ea\def \ea\readvalue \ea#\ea1\detokenize{pt}{#1}
\def\modifyvalue #1.#2#3#4\end{#1.#2#3}

\value=\ea\modifyvalue\expanded{\ea\readvalue\the\value}{}{}\end pt

\the\value  % prints 6.94pt

\bye

此代码会进行截断。如果您需要四舍五入,请\advance\value by 0.005pt在截断之前进行。

2

  • 3
    这难道不是截断而不是舍入吗?尽管给出了 OP 的自我回答,但我不再确定我是否知道问题是什么。


    – 

  • 是的,这是截断。而且只是非常脆弱的截断,因为如果我们将某个十进制表示设置为 pt 中的 dimen 值,那么它会被重新解释为 sp 的倍数,并\the\value可能打印出与设置不同的内容。这就是“可能”OP 想要这个的原因。我不确定。


    – 

这使用 e-TeX 扩展,以便宏可扩展。

它假设一个维度,并利用在整数部分后\the\dimexpr总是会添加一个小数部分(可能只是)。.0

将显示尾随零,并且可扩展性允许使用宏进行分配。由于 TeX 永远不会显示超过五个,因此没有必要超出。

%%%% requires pdftex or xetex or luatex (not Knuth TeX)

\catcode`@=11
\def\therounded#1#2{% #1 = digits, #2 = dimen
  \expanded{\noexpand\therounded@{#1}\the\dimexpr#2\relax}%
}
\expanded{\def\noexpand\therounded@#1#2\detokenize{pt}}{%
  \ifcase#1 
    \expandafter\therounded@zero\or
    \expandafter\therounded@one\or
    \expandafter\therounded@two\or
    \expandafter\therounded@three\or
    \expandafter\therounded@four\else
    \expandafter\therounded@five\fi
    #200000\relax pt
}
\def\therounded@zero  #1.#2#3#4#5#6#7\relax{\therounded@@{}{#1}{#2}}
\def\therounded@one   #1.#2#3#4#5#6#7\relax{\therounded@@{#1.}{#2}{#3}}
\def\therounded@two   #1.#2#3#4#5#6#7\relax{\therounded@@{#1.#2}{#3}{#4}}
\def\therounded@three #1.#2#3#4#5#6#7\relax{\therounded@@{#1.#2#3}{#4}{#5}}
\def\therounded@four  #1.#2#3#4#5#6#7\relax{\therounded@@{#1.#2#3#4}{#5}{#6}}
\def\therounded@five  #1.#2#3#4#5#6#7\relax{#1.#2#3#4#5#6}
\def\therounded@@#1#2#3{#1\the\numexpr#2\ifnum#3>4 +1\fi\relax}
\catcode`@=12

\newlinechar=`^^J

\dimen0=16.90053pt

\message{%
  \the\dimen0^^J%
  0: \therounded{0}{\dimen0}^^J%
  1: \therounded{1}{\dimen0}^^J%
  2: \therounded{2}{\dimen0}^^J%
  3: \therounded{3}{\dimen0}^^J%
  4: \therounded{4}{\dimen0}^^J%
  5: \therounded{5}{\dimen0}^^J%
}

\dimen0=16.94453pt

\message{%
  \the\dimen0^^J%
  0: \therounded{0}{\dimen0}^^J%
  1: \therounded{1}{\dimen0}^^J%
  2: \therounded{2}{\dimen0}^^J%
  3: \therounded{3}{\dimen0}^^J%
  4: \therounded{4}{\dimen0}^^J%
  5: \therounded{5}{\dimen0}^^J%
}

\dimen2=\therounded{0}{\dimen0}
\message{\the\dimen0 \space --> \the\dimen2^^J}

\setbox0=\vtop{abc\par def\par ghi}

\message{Height plus depth: \therounded{2}{\ht0+\dp0}^^J}

\bye

控制台上的输出:

16.90053pt
0: 17pt
1: 16.9pt
2: 16.90pt
3: 16.901pt
4: 16.9005pt
5: 16.90053pt

16.94453pt
0: 17pt
1: 16.9pt
2: 16.94pt
3: 16.945pt
4: 16.9445pt
5: 16.94453pt
16.94453pt --> 17.0pt
Height plus depth: 32.89pt

未完待续…

 \newbox\mybox{}
\setbox\mybox=\vtop{``This is the content of the box''} 
\the\ht\mybox\  This is the current height of the box

    \par
    \newdimen\start
    \start=\ht\mybox
    \the\start\ This is the start of the loop\par
    \newdimen\stop
    \stop=6.94000pt %
    \the\stop \ This is the wanted height of the box and stop of the loop
    \loop \ifdim\start>\stop \advance\start by -0.00001pt\repeat\par
    \the\start\ This is the resulting value
    \bye

6

  • 3
    我完全不明白这一点。为什么要用这种迂回的方式告诉 tex 使用6.94pt?我以为你想排版结果,而不知道结果是什么。但显然不是?


    – 

  • 2
    这不是我的意思。我的意思是,一旦处理 tex 维度,就无法1pt准确。即使存储维度也会带来不准确性。例如,如果您存储在维度寄存器中,则不一定存储1pt在维度寄存器中。您可能有0.999pt1.0001pt或其他东西。如果您想保持准确性,请存储整数并仅在最后一刻进行除法。


    – 

  • 1
    例如尝试\newdimen\mydimen \mydimen=0.001pt \advance\mydimen by 0.1pt \the\mydimen了解我的意思。


    – 

  • 1
    @MBE 我不明白你的代码风格。为什么在第 5 行有\par?前一行是空的,所以它生成了隐式的\par,为什么后面还有显式的\par?为什么第 5-14 行要缩进?你为什么要做这样一个荒谬的循环,其中 dimen 值减少 0.00001pt,四舍五入为 1sp?试试这个,看看这个荒谬的代码\newdimen\value \value=0.00001pt \the\value。它打印 0.00002pt。你为什么要做这个循环,而它必须在什么时候结束\start=\stop?你为什么不简单地写出\start=\stop具有完全相同效果的循环?


    – 


  • 1
    @MBE 我觉得你的思维方式有点奇怪。也许你想要一些东西,但在这里却呈现出不同的东西。当然,这种思维方式无法使 TeX 发挥最佳作用。对于 tex.stackexchange 也是如此。


    –