4

I know in latex it is possible to use counters which are based on integers. Is there also some way to define a floating point register to perform simple arithmetic operations?

Basically I would need some way to write something like

\newreg{myx}
\setreg{myx}{0.0}
\addreg{myx}{0.5}
\addreg{myx}{-0.25}
\valuereg{myx} % this expands to 0.25
nicmus
  • 217
  • @Werner It seems that it is not quite duplicate because OP needs something more simple than full float point arithmetic. This can be simply done by \newdimen\myx. Because this question is marked as "duplicate", I am unable to show full answer here. Unfortunately. – wipet Mar 14 '18 at 15:48
  • @wipet: There's no mention of the level of detail required, and it's all covered in the linked question. You can, of course, vote to re-open here since you have that privilege. Perhaps you can add your TeX answer to the linked duplicate...? – Werner Mar 14 '18 at 16:05
  • The linked answer seems indeed to propose solutions more complicated as necessary. I solved using the idea suggested by wipet. That is a combination of \newdimen (to init) \advance (to sum) and \the (to visualize) plus the aid of the latex macro \strip@pt (to strip the unit). – nicmus Mar 14 '18 at 16:33
  • @werner I cannot add my answer to the linked duplicate because there is question how to calculate 100*round((V-F)/T,2), where V, F and T are variables. This is much more complicated, this cannot be simply done using \newdimen. So, your decision about "duplicate question" yields to missing answer here. But OP understood my idea, fortunately. – wipet Mar 14 '18 at 20:08
  • @wipet: Why haven't you voted to re-open the question then? – Werner Mar 14 '18 at 20:09
  • @werner I don't agree with "voting philosophy" of this site. I only add sometimes an answer when I am happy with it. – wipet Mar 14 '18 at 20:11
  • @wipet: That's unfortunate. – Werner Mar 14 '18 at 20:14
  • @werner Yes, it is. I have created my answer, I was ready to put it on this site and bingo! ... somebody decided that this is duplicated. And he hasn't true because something different than the answers in the created link are needed here. And he stay with his decision (about duplicate) and he expects that I will attend to an absurd voting. – wipet Mar 14 '18 at 20:38
  • @wipet: It's a community-driven site and voting (in all ways) is one way of contributing to the community whether you like it or not. – Werner Mar 14 '18 at 20:42
  • @werner If you are unable to accept that your decision about "duplicating" is bad then all another discussion (or voting) is a lost cause. – wipet Mar 14 '18 at 21:50
  • @wipet: It's unfortunate that you're basing your decision on purely my voting behaviour. If you vote to re-open, the post will land in the re-open review queue where others in the community can contribute. If more people feel the way you do (about the closure, not the voting, of course), then they can support your cause and the question will be opened. That's how this community operate. – Werner Mar 14 '18 at 21:58
  • @werner You are alone but "more people" must vote (as you say). One vote -- more votes. There is something wrong. In normal environment: if somebody did mistake, I can explain that he did mistake and if he accept it then problem is solved. Nobody need to vote. That is the reason why I feel this voting as obscure. – wipet Mar 14 '18 at 22:32
  • @wipet: That's just it, I don't think I made a mistake in voting to close, since the question (as posed), can be solved by the linked duplicate. Nobody here reigns with an authoritarian hammer that can't be undone by the community. You have at least 447 other users (as of today) who can vote with you to re-open this question. – Werner Mar 14 '18 at 23:15
  • I disagree on the latter point. It is true that the solutions in the linked answer completely solve my problem. However in the posed question I actually specify that I need simple operations and an example of what I need is provided, which by the way only requires very modest precision and not e.g. 8 or more digits. I believe it is a waste of resources to call other package dependency or worse even lua dependency. I just want to point out that the comment provided by @wipet has been much more useful than all the discussion in the linked answer. Obviously other users may find this also useful. – nicmus Mar 14 '18 at 23:39
  • @werner sorry, you deactivated this post by your SINGLE click without "voting". And you recommend me to do "voting". I am asking you: be more careful with doing such clicks! It is absurd that we need more "votes" (how many in particular?) to reverse your single click. – wipet Mar 15 '18 at 18:46
  • 1
    @nicmus: Here's an easy implementation for what you're after - code. No testing for existing "variables" or "registers" is implemented, but it is extendable to use calculations in the assignment. – Werner Mar 15 '18 at 23:50

3 Answers3

7

If you need only addition, subtraction and multiplication and numbers are expected in the range +-16380 with four (or less) digits after decimal point then you can use directly dimension registers supported naturally by TeX. For example:

\def\newreg{\csname newdimen\endcsname}
\def\setreg#1#2{#1=#2pt }
\def\addreg#1#2{\advance#1by#2pt }
\def\mulreg#1#2{#1=#2#1}
\def\valuereg#1{\expandafter\ignorept\the#1}
\bgroup\lccode`\?=`\p \lccode`\!=`\t \lowercase{\egroup\def\ignorept#1?!{#1}}

\newreg\myx
\setreg\myx {0.0}
\addreg\myx {0.5}
\addreg\myx {-0.25}
\valuereg\myx  % this expands to 0.25

\bye

But division using dimension registers is somewhat more complicated.

Of course, you can use pgfmath or calc or lua or expl3 or apnum or somewhat similar but with declared needs it seems like using cannon on a sparrow.

wipet
  • 74,238
  • With etex: \def\divreg#1#2{#1=\dimexpr#1/#2\relax}. Or just: \def\divreg#1#2{\divide #1by#2} – Skillmon Mar 18 '18 at 15:08
  • @Skillmon This does not work when #2 is decimal number, for example 1.5 – wipet Mar 18 '18 at 16:07
  • Yes, that's correct. – Skillmon Mar 18 '18 at 16:16
  • one more doubt... I have defined: {\catcode``p=12 \catcode``t=12 \global\def\removedim#1pt{#1}} and seems to work. Would your definition \ignorept be safer? P.S. I used double backticks because of stack exchange code syntax. – nicmus Mar 22 '18 at 10:18
  • @nicmus If you are using LaTeX then you can use some similar macro from LaTeX. My macros (as usual) are LaTeX independent, so I need to define \ignorept specially. – wipet Mar 22 '18 at 18:02
  • Yes that was my intent too. I was previously using \strip@pt and then defined my own latex independent macro \removedim. Now I was just curious to know if there are differences in the behaviour of your macro and mine. – nicmus Mar 22 '18 at 18:06
  • I don't know how looks like your macro \removedim, but the LaTeX's macro \rem@pt looks more intelligent than mine because it does not print the decimal dot when only zero digit follows. – wipet Mar 22 '18 at 18:25
  • @wipet I defined it in the previous comment, here again {\catcode``p=12 \catcode``t=12 \global\def\removedim#1pt{#1}} (double backticks are for SE code syntax) – nicmus Mar 23 '18 at 07:19
  • @nicmus Your definition does essentially the same. The only difference is that your \removedim is defined globally but my definition is local. There is absolutely no difference when my definition is read at outer group (which is usual). But my definition can be read in a group and it is forgotten at the end of such group. – wipet Mar 23 '18 at 13:18
  • @wipet Perfect thanks! The latter group property might be indeed useful. – nicmus Mar 23 '18 at 15:29
6

Here a simple example with pgfmath, part of pgf/TikZ:

\documentclass{article}
\usepackage{pgfmath}
\begin{document}
  \pgfmathsetmacro\myx{0}
  \pgfmathsetmacro\myx{\myx + 0.5}
  \pgfmathsetmacro\myx{\myx - 0.25}
  \myx
\end{document}

Result

The "register" is a simple macro (\myx) here. Also, an "addto" macro can be defined:

\documentclass{article}
\usepackage{pgfmath}

% #1: macro token, e.g. \myx
% #2: math expression
\newcommand*{\pgfmathaddtomacro}[2]{%
  \pgfmathsetmacro#1{#1+(#2)}
}

\begin{document}
  \pgfmathsetmacro\myx{0}
  \pgfmathaddtomacro\myx{0.5}
  \pgfmathaddtomacro\myx{-0.25}
  \myx
\end{document}
Heiko Oberdiek
  • 271,626
5

You can use the powerful floating point module of expl3. I use global assignments, like for LaTeX counters, but it would be possible to do local assignments.

\documentclass{article}
\usepackage{xparse,xfp}

\ExplSyntaxOn
\NewDocumentCommand{\newreg}{m}
 {
  \fp_new:c { g_nicmus_#1_fp }
 }
\NewDocumentCommand{\setreg}{mm}
 {
  \fp_gset:cn { g_nicmus_#1_fp } { #2 }
 }
\NewDocumentCommand{\addreg}{mm}
 {
  \fp_gset:cn { g_nicmus_#1_fp } { \fp_use:c { g_nicmus_#1_fp } + (#2) }
 }
\NewExpandableDocumentCommand{\valuereg}{m}
 {
  \fp_use:c { g_nicmus_#1_fp }
 }
\ExplSyntaxOff

\newreg{myx}

\begin{document}

\setreg{myx}{0.0}
\addreg{myx}{0.5}
\addreg{myx}{-0.25}
\valuereg{myx} % this expands to 0.25

\addreg{myx}{sqrt(3)+pi}

\valuereg{myx} % this expands to 5.12364346115867

\fpeval{round(\valuereg{myx},2)} % this expands to 5.12

\end{document}

enter image description here

egreg
  • 1,121,712