3

I was wondering how I can redefine an existing command by an own command using futurelet to determine the number and types of parameters? Basically what I wanted to do is similar to

\renewcommand{\log}[2][]{\mathrm{log}_{#1}\left( #2 \right)}

but with the additional option that the user can use the command without argument, i.e. write \log 5 to obtain an output log 5, since some people prefer writing the logarithm without brackets.

Here's what I tried

%logarithm
\newcommand{\logRM}{\mathrm{log}}                           %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}           %\logRM()
\newcommand{\logTwoArgs}[2][]{\logRM_{#1}\left(#2\right)}   %\logRM_basis()
\DeclareRobustCommand\log{\futurelet\logNext\logCheck}

\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg                %if \log is followed by {
  \else%
  \ifx[\logNext \expandafter\logTwoArgs                     %if \log is followed by [
  \else%
  \expandafter\logRM                                        %otherwise
  \fi%
  \fi%
}

I encountered two problems. One of which was that the optional argument did not act as I supposed it would, instead, \log[2]{8} gave me an output log()[2]8. The other problem was that I got an error message because \log was already defined. I tried to circumvent the problem by denoting above command by \xlog and then trying one of the following, but neither worked.

\def\log{\xlog}
\let\log\xlog
\renewcommand{\log}{\xlog}

\edit:
Maybe it was not clever to formulate two questions in one problem. So here is the information for the no argument case I would like to have. If we leave out the optional parameter, then

%logarithm
\newcommand{\logRM}{\mathrm{log}}                           %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}           %\logRM()
\DeclareRobustCommand\xlog{\futurelet\logNext\logCheck}

\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg                %if \log is followed by {
  \else%
  \expandafter\logRM                                        %otherwise
  \fi%
}

defines a command that will have no brackets if I don't have any arguments, i.e. I can write \xlog^+(x) for the positive part of the logarithm and \xlog{\frac{x+1}{x}} to have brackets of varying size around a more complicated expression.

Now one question is, how can I call this function \log even though \log is already defined? the other question is how to expand this macro to allow an additional optional argument, e.g. the basis of the logarithm, since it doesn't seem to work the way I posted in my first post.


The way (I hope) this should work is lined out in my edited post above. It works with futurelet to see if there is any argument at all, if we leave out the case with the optional argument like in my edited question, then

\xlog^+ : [1, \infty) \to \mathbb{R}_+
\xlog{\frac{x}{x+1}}

both produce the output we expect (which is log^+ : [1, \infty) \to R or log(x/(x+1)) respectively). I guess what I'm trying to say is that I'm looking to write this function in a way that latex does not wait for an argument if I don't write braces, because there won't be any. And sorry about my mistake with the brackets, I'm no native speaker, but at least I know now.

\edit:
Thought about your comment regarding the spacings and realized that the better way to generalize the \log command was of course to use \let, so we keep all the functionality of the old command and get the new ones, i.e. with something like this

\let\logRM\log                                                  %log operator
\newcommand{\logOneArg}[1]{\logRM\left(#1\right)}               %\logRM()
%\newcommand{\logTwoArgs}[2][]{\logRM_{#1}\left(#2\right)}      %\logRM_basis()
\DeclareRobustCommand\xlog{\futurelet\logNext\logCheck}         %look what next character is
\def\logCheck{%
  \ifx\bgroup\logNext \expandafter\logOneArg%                   %if \log is followed by {
  \else%
  %\ifx[\logNext \expandafter\logTwoArgs%                       %if \log is followed by [
  %\else%
  \expandafter\logRM                                            %otherwise
  %\fi%
  \fi%
}
\renewcommand{\log}{\xlog}

Now if \log is not followed by any braces, it behaves just like the initial \log, thus if we want to have parentheses with nath, we can still do that. On the other hand if we write \log{expression} we get the expression in braces. Now the only question remaining is how to extend that to take an optional argument like the base of the logarithm.

6
  • You always can skip the braces for a macro argument if the content is only one character or macro, i.e. \log{5} and \log 5 will both work. Also have a look at the xparse package. Nov 1, 2011 at 22:46
  • Thank you for your helpful reply. The enormous parentheses around \sum_{i = 1}^n is exactly what I'm looking for. About nested parentheses you may be right, however if I can wirte \log(...) and it just makes the operator without parentheses (since it is parentheses and not braces it should be treated as no argument) I can write \log and then nested parenthes if I'm looking for that functionality. If I'm writing \log^+ then I don't expect to give any argument to the logarithm at all, I'm willing to write \log^+(x) instead of \log^+{x} (or \log^+\of{x} where \of adapts the size of parentheses),
    – Benjamin
    Nov 2, 2011 at 3:04
  • but I don't want to have two separate commands for just the operator and the function. The reason that I'd prefer to write \log[2]{\sum...} instead of \log_2\left(\sum...\right) (or \log_2\of{\sum...}) is that in the end it is shorter, and also from an ideological viewpoint \log[i]{x} is a family of funcions whereas \log_i\of{x} is an operator with a subscript and a value in parentheses. If \log followed by a space (or anything else than bracket or brace) just outputs the operator then \log : \R \to \R, \log \num{100000}, \log 1e6 will all produce no problems.
    – Benjamin
    Nov 2, 2011 at 3:05
  • If I want to have parentheses around them, I write \log{\num{100000}} etc. which works fine as well. Interesting thing about the renaming. \renewcommand{\log}{\xlog} works fine, but a similar command \xspan cannot be renamed using \renewcommand{\span}{\xspan}, which is where I encountered the error originally, but decided to post the logarithm case because of the additional problem of an optional argument.
    – Benjamin
    Nov 2, 2011 at 3:05
  • I realize that it might seem strange that I don't want to write \log\of{x} or anything similar with the predefined \log, but this was just a problem I tried to tackle today and I could not solve, so I wondered if there are any futurelet experts that might know a simple solution.
    – Benjamin
    Nov 2, 2011 at 3:05

2 Answers 2

5

Gather the optional argument first; then check for ^ and finally for {:

\documentclass{article}
\makeatletter
\let\@@log\log
\renewcommand{\log}[1][]{%
  \@@log_{#1}\@ifnextchar^\log@withexp\log@maybeparen}
\def\log@withexp^#1{^{#1}\log@maybeparen}
\def\log@maybeparen{\@ifnextchar\bgroup{\log@paren}{}}
\def\log@paren#1{\mathopen{}\left(#1\right)\mathclose{}}

\makeatother

\begin{document}
$\log 2+\log[2]2$

$\log{2}+\log[2]{2}$

$\log^{+}2+\log[2]^{+}2$

$\log^{+}{2}+\log[2]^{+}{2}$
\end{document}

enter image description here

Just as an exercise, here is an xparse version:

\usepackage{xparse}
\makeatletter
\let\@@log\log
\DeclareDocumentCommand{\log}{o t^}{
  \@@log
  \IfNoValueTF{#1}{}{_{#1}}
  \IfBooleanTF{#2}{\log@exp}{\log@afterexp}
}
\DeclareDocumentCommand{\log@exp}{m}{^{#1}\log@afterexp}
\DeclareDocumentCommand{\log@afterexp}{g}{
  \IfNoValueTF{#1}{}{\mathopen{}\left(#1\right)\mathclose{}}
}
\makeatother
0

(Edit: My first answer misunderstood the question)

The basic problem in defining all-purpose smart macros like this is that they have to anticipate all kinds of situations you want to handle. In effect, you have to have the macro switch behind the scenes between all the usages that you can imagine wanting. It is not clear to me that this is worth the effort; for example, you want (in the comments) to be able to write \log^+{x} and have it parse correctly, but you don't want to have to write \log_2{x} but instead provide the subscript as an optional argument: \log[2]{x}: one more character, and an awkward one at that (on my keyboard, anyway).

I can see other issues. For example, you want it to notice when braces or parentheses are not given in the input and omit them in the output, so \log 20 becomes log 20 and not log(20), as Peter Grill pointed out to me. What about \log 100000? For big numbers, I sometimes like using siunitx to put in the commas: \log \num{100000}. Your macro will have to handle that. And also hand-written numerical notation, like \log 1e6. You will also have a hard time recognizing the notation \log \colon \mathbb{R}^+ \to \mathbb{R}, unless you make \log{} a special case that does not print parentheses around the empty argument.

Even your basic goal of getting the argument in resized parentheses is not so simple. What if you write \log((x + 1)(x + 2))? There is an agreeable school of thought that the parentheses on the outside should be larger than the ones on the inside, to visually separate the parts of the formula. This will not be done with \left and \right. If you write \log(\sum_{n = 1}^\infty ...) you will get enormous parentheses. The nath package (I think) handles this more gracefully.

My point is that you are probably better off not trying to have the computer read your mind when all you want to do is: print the word log like a math operator (we have \DeclareMathOperator for that, if \log were not already defined. Did you remember to take care of the spacing in your own macro?); put a base in if the code has one (easily done with subscripts, which are just as optional as an optional argument); and put the actual argument in resized parentheses, which I've argued is actually not what you want.

Finally, to answer the question now expressed in your revised post:

Answer: Use \renewcommand{\log}{\xlog}.

5
  • Both \log{2} \quad \log 2 and \log[5]{2} \quad \log[5] 2 produce identical results, but this won't work for \log 20 Nov 2, 2011 at 0:31
  • Yes, of course I meant to write #2 as second argument, but you misunderstood my point. I know that \log 5 and \log{5} will both produce log(5) (with brackets) but I want that \log 5 produces log 5 (without brackets). Maybe the example wasn't well chosen. For example I would like to be able to write \log^+(x) for the positive part of the logarithm, which of course will produce an error
    – Benjamin
    Nov 2, 2011 at 0:38
  • @PeterGrill: Oh, so not just for one-character logs?
    – Ryan Reich
    Nov 2, 2011 at 1:00
  • @Benjamin: I see, you want to skip the parentheses (don't call them brackets; those are [], and braces are {}. This way we can say exactly what we mean) both in the input and output. And you want the superscript to work as expected?
    – Ryan Reich
    Nov 2, 2011 at 1:07
  • @Benjamin: How do you refer to just the function \log? That is, if you want to say "$\log^+ \colon \mathbb{R}^+ \to \mathbb{R}^+$, how are you going to avoid having that come out at "log^+(:)"? Will this be a special case of \log{#2} where if #2 is empty, then parentheses are not printed?
    – Ryan Reich
    Nov 2, 2011 at 1:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .