I'm using MathJax-Node to turn TeX maths equations into both MathML and SVG on my server. Mostly this works fine. But when I render Tupper's self-referential formula, a weird space appears after the second minus sign in the exponent: Rendered formula.

The space also appears on mathURL (which is where the above image comes from). When I examine the MathML generated, I can see that MathJax has explicitly inserted a mspace element.

The TeX I'm using is as follows:

\frac12<\left\lfloor\mod\left(\left\lfloor\frac y{17}\right\rfloor2^{{-17}\left\lfloor x\right\rfloor-\mod\left(\left\lfloor y\right\rfloor,17\right)},2\right)\right\rfloor

Any idea what's going on here?

  • 4
    Although this is not exactly a TeX question, but have you looked at the first \mod? It is not about the minus sign, but rather the \mod. The \mod has, by design, a preceding quad space and an appending half quad space. – Ruixi Zhang Sep 19 at 21:24
up vote 19 down vote accepted

You're using “mod” as a math operator like “exp” or “sin”. The command \mod is for notation such as

5 \equiv 2 \mod{3}

and the inserted space is obviously wanted here.

Use \operatorname{mod} instead.

\documentclass{article}
\usepackage{amsmath}

\begin{document}

\[
\frac{1}{2}<
  \left\lfloor
    \operatorname{mod}\left(
      \left\lfloor\frac{y}{17}\right\rfloor
      2^{-17\lfloor x\rfloor-\operatorname{mod}(\lfloor y\rfloor,17)},2
    \right)
  \right\rfloor
\]

\end{document}

I've removed useless (and wrong) \left and \right pairs.

enter image description here

It works equally well in MathJax (tested on Math.SE):

enter image description here

Do you mean this:

enter image description here

\documentclass{article}

\usepackage{xintexpr}

% Tupper

% q = floor(y/17)
% r = mod(y, 17)   (modulo for floor)

% Tupper formula boils down to say:

% Pixel (x, y) is ON <===> floor(q, 2**(17x+r)) is ODD

% https://fr.wikipedia.org/wiki/Formule_autor%C3%A9f%C3%A9rente_de_Tupper

% \xintiiexpr notations

% floored division is //
% associated modulo is /: (or 'mod')
% divmod(,) is both // and /: (as in Python)

\begin{document}

% 0 <= x < 106
% k <= y < k + 17

\xintdefiivar TupperK := 
960939379918958884971672962127852754715004339660129306651505519271702802395266
424689642842174350718121267153782770623355993237280874144307891325963941337723
487857735749823926629715517173716995165232890538221612403238855866184013235585
136048828693337902491454229288667081096184496091705183454067827731551705405381
627380967602565625016981482083418783163849115590225610003652351370343874461848
378737238198224849863465033159410054974700593138339226497249461751545728366702
369745461014655997933798537483143786841806593422227898388722980000748404719;

\setlength\unitlength{1pt}

\def\parseTupperXY#1#2{% #1 = x, #2=y, 
    \xintdefiivar Yq, Yr = divmod(#2, 17);%
    \edef\resultTupperXY{\xinttheiiexpr odd(Yq // 2**(17 * #1 + Yr))\relax}%
}%

% This is a bit slow, be patient (big powers of 2 are computed...)
% Much faster would be to convert TupperK to binary...
\begin{picture}(106,17)
  \xintFor* #1 in {\xintSeq{0}{105}}\do {% x
      \xintFor* #2 in {\xintSeq{0}{16}}\do {%  y - k
          \parseTupperXY{#1}{#2+TupperK}
          \if1\resultTupperXY
             \put(\numexpr105-#1, \numexpr16-#2){\rule{1pt}{1pt}}
          \fi
      }
  }
\end{picture}

\end{document}

I hoped this

\documentclass{article}

\usepackage{xintexpr}

% Tupper

% q = floor(y/17)
% r = mod(y, 17)   (modulo for floor)

% Tupper formula boils down to say:

% Pixel (x, y) is ON <===> floor(q, 2**(17x+r)) is ODD

% https://fr.wikipedia.org/wiki/Formule_autor%C3%A9f%C3%A9rente_de_Tupper

% \xintiiexpr notations

% floored division is //
% associated modulo is /: (or 'mod')
% divmod(,) is both // and /: (as in Python)

\begin{document}

% 0 <= x < 106
% k <= y < k + 17

\xintdefiivar TupperK := 
960939379918958884971672962127852754715004339660129306651505519271702802395266
424689642842174350718121267153782770623355993237280874144307891325963941337723
487857735749823926629715517173716995165232890538221612403238855866184013235585
136048828693337902491454229288667081096184496091705183454067827731551705405381
627380967602565625016981482083418783163849115590225610003652351370343874461848
378737238198224849863465033159410054974700593138339226497249461751545728366702
369745461014655997933798537483143786841806593422227898388722980000748404719;

\setlength\unitlength{1pt}

\xintdefiivar twoToThe17 := 2**17;
\xintdefiivar twoToThe17timesX := 1;

\begin{picture}(106,17)
  \xintFor* #1 in {\xintSeq{0}{105}}\do {% x
      \xintFor* #2 in {0123456789{10}{11}{12}{13}{14}{15}{16}}\do {%  y - k
          \xintdefiivar Yq, Yr = divmod(#2 + TupperK, 17);%
          \xintifbooliiexpr {odd(Yq // (twoToThe17timesX * 2**Yr ))}
             {\put(\numexpr105-#1, \numexpr16-#2){\rule{1pt}{1pt}}}
             {}
      }
   \xintdefiivar twoToThe17timesX := twoToThe17 * twoToThe17timesX;%
  }
\end{picture}

\end{document}

would be faster, but it is only a bit faster. Hence the bottleneck is in the big divisions, less so in the powers of two.

It would be faster to cheat a bit and compute binary representation of k via \xintDecToBin from xintbinhex for example.


Computing pixels with the real formula

The above cheated a bit: the actual used formula for deciding if a pixel is ON is slightly modified one from original, as it uses only integer arithmetic. One can definitely use \xintexpr rather than \xintiiexpr and do the "real" thing... of course it is a bit slower. (still)

\documentclass{article}

\usepackage{xintexpr}

% Tupper

% q = floor(y/17)
% r = mod(y, 17)   (modulo for floor)

% Tupper formula is (exactly) (apart from using floor rather than ⌊ and ⌋)

% Pixel (x, y) is ON <===> 1/2 < floor(mod(floor(y/17)2**(-17x-mod(y, 17)), 2))

% The latter means floor(q, 2**(17x+r)) is ODD, when using only
% integers
% but here we will be using the REAL THING !


\begin{document}

% 0 <= x < 106
% k <= y < k + 17

\xintdefiivar TupperK := 
960939379918958884971672962127852754715004339660129306651505519271702802395266
424689642842174350718121267153782770623355993237280874144307891325963941337723
487857735749823926629715517173716995165232890538221612403238855866184013235585
136048828693337902491454229288667081096184496091705183454067827731551705405381
627380967602565625016981482083418783163849115590225610003652351370343874461848
378737238198224849863465033159410054974700593138339226497249461751545728366702
369745461014655997933798537483143786841806593422227898388722980000748404719;

\setlength\unitlength{1pt}

% SLOW ! (about 55s on 2.4Ghz laptop)

\begin{picture}(106,17)
  \xintFor* #1 in {\xintSeq{0}{105}}\do {% x
          \xintdefiivar x = #1;% to let the formula use X, Y, not #1, #2
      \xintFor* #2 in {0123456789{10}{11}{12}{13}{14}{15}{16}}\do {%  y - k
          \xintdefiivar y = #2 + TupperK;%
          \xintifboolexpr 
% TUPPER FORMULA USED AS INPUT SHOWS IN OUTPUT
% EXCEPT WE USE floor NOT ⌊, ⌋ AS THIS IS XINTEXPR SYNTAX
          {1/2 < floor(mod(floor(y/17)2**(-17x-mod(y, 17)), 2))}
             {\put(\numexpr105-#1, \numexpr16-#2){\rule{1pt}{1pt}}}
             {}
      }
  }
\end{picture}

\end{document}

Cheating via binary digits for faster construction of picture

In the other direction, we can cheat completely and do a conversion to binary digits of k/17 analysing the original formula to say that a pixel is on when some bit is 1. Naturally, the image is then produced much faster.

\documentclass{article}

\usepackage{xintexpr}

% Tupper

% q = floor(y/17)
% r = mod(y, 17)

% Tupper formula boils down to say:

% Pixel (x, y) is ON <===> floor(q / 2**(17x+r)) is ODD

% https://fr.wikipedia.org/wiki/Formule_autor%C3%A9f%C3%A9rente_de_Tupper

% This also means that

% Pixel (x, y) is ON <==> 17x+r bit of q is 1

% where "Oth bit" means least significant bit aka parity bit.

% Specific case

% 0 <= x < 106
% k <= y < k + 17

% Where k is a multiple of 17, k = 17 q

% Then we get binary bits of q starting from least significant one
% by chunks of 17 for each x = 0, 1, ...

% The value given for k at wikipedia page is

\xintdefiivar TupperK := 
960939379918958884971672962127852754715004339660129306651505519271702802395266
424689642842174350718121267153782770623355993237280874144307891325963941337723
487857735749823926629715517173716995165232890538221612403238855866184013235585
136048828693337902491454229288667081096184496091705183454067827731551705405381
627380967602565625016981482083418783163849115590225610003652351370343874461848
378737238198224849863465033159410054974700593138339226497249461751545728366702
369745461014655997933798537483143786841806593422227898388722980000748404719;

\xintdefiivar TupperQ, TupperR := divmod(TupperK, 17);

\xintifboolexpr{TupperR}
   {% remainder would be not zero, which is not the case with this k
    \ERROR
   }
   {% remainder is zero as expected
    \typeout{k is multiple of 17: k mod 17 = \xinttheiiexpr TupperR\relax}
   }

% Now we will assign the binary digits of q to an "array" for later use

\usepackage{xintbinhex}

\xintAssignArray
   \xintReverseDigits
      {\xintDecToBin{\xinttheiiexpr TupperQ\relax}}\to
\TupperBits

% We need 1802 = 106 * 17 bits, but turns out the two leading ones are zero
% so \TupperBits{index} only works 1<= index <= 1800

% xinttools should definitely be extended to have array-extension macro
% but it only has the very starts of "array" concept so we will need  to
% add a check in the loop using it.

\typeout{Binary rep of k/17 has only \TupperBits{0} bits, not \the\numexpr106*17.}

\begin{document}

\setlength\unitlength{1pt}

% Now we use the binary digits of q = k/17

% \TupperBits items are enumerated starting at 1 not at 0

\begin{picture}(106,17)
  \xintFor* #1 in {\xintSeq{0}{105}}\do {%
      % #1 will be x
      \xintFor* #2 in {0123456789{10}{11}{12}{13}{14}{15}{16}}\do {%
      % #2 will be y mod 17
      % Due to possibly vanishing leading bits
          \ifnum \numexpr#1*17+#2+1>\TupperBits{0}
          \else
              \if1\TupperBits{#1*17+#2+1}% charms of expandability
% The x coordinate goes from right to left and the y from top to bottom
% in Tupper plane
                 \put(\numexpr105-#1, \numexpr16-#2){\rule{1pt}{1pt}}
              \fi
          \fi
      }
  }
\end{picture}

\end{document}

Variant using "floor" rather than left and right floor symbols

enter image description here

Original formula

1/2<floor(mod(floor(y/7)2^(-7x-mod(y,7)),2))

Region of plane

0 <= x < 308, k <= y < k + 7

with k given below.

I started from the formula and converted it to ascii-art with some online converter. Turns out it produced 8 lines, one empty. So I used 7 in place of 17 in formula and started again. Finally I converted the bit array to some number, which after multiplying by 7 is this one:

k = 38426720969186584676507136423746315165273305413945565187145665641304238215561995317662843293085432836310036135900849286588951953665639729939317005809629409803737705286494507269624061838603195349517975717012314034034886568013639993815956512735232451156976667291853312484643760872115994758595671605381979339411956400072599436927196143537882844410760247627090690368478688405508823263940609428350186251562536135575229759753524677106213338248890237354234165603070460931515868266696814935467260883698401252476941050712407716221704528350212280853722118440152424270081709425589819079391652824219385549071663086397901966417260775437015400315493361455291308484

It has 650 decimal digits and k/7 has 2156 = 308*7 binary digits.

One sees the original formula in the region 0<= x < 308, k <= y < k+7 with the k above. I am using a pixelated plane, where x increases from right to left and y from top to bottom and unit pixel at (x,y) has lower-left corner at (x,y).

Thus the formula does use real numbers in its evaluation, but x, y are integers.

Sadly, due to xintexpr using control sequence strings to store tokens, TeX memory got exhausted. So, as I had spent some time setting it all up, I reverted to typeset the picture from the (computed) binary digits directly.

\documentclass{article}

\usepackage{xintexpr}

% Tupper+xintexpr

% FORMULA:

% Pixel (x, y) is ON <===> 1/2 < floor(mod(floor(y/7)2**(-7x-mod(y,7)),2))

% 0 <= x < 308
% k <= y < k + 7

\xintdefiivar TupperKvariant :=
38426720969186584676507136423746315165273305413945565187145665641304238215561995317662843293085432836310036135900849286588951953665639729939317005809629409803737705286494507269624061838603195349517975717012314034034886568013639993815956512735232451156976667291853312484643760872115994758595671605381979339411956400072599436927196143537882844410760247627090690368478688405508823263940609428350186251562536135575229759753524677106213338248890237354234165603070460931515868266696814935467260883698401252476941050712407716221704528350212280853722118440152424270081709425589819079391652824219385549071663086397901966417260775437015400315493361455291308484;

% Turns out that here k/7 has 2156 bits (= 308*7)

% conversion to binary for "cheating approach" 
\usepackage{xintbinhex}

\xintdefiivar TupperQvariant := TupperKvariant/7;
\xintAssignArray
   \xintReverseDigits
      {\xintDecToBin{\xinttheiiexpr TupperQvariant\relax}}\to
\TupperBits

% no missing "0" leading bit in that case, length is 2156=308*7

\begin{document}

\setlength\unitlength{1pt}

% \begin{picture}(308,7)
%   \xintFor* #1 in {\xintSeq{0}{307}}\do {% x
%           \xintdefiivar x = #1;% to let the formula use x, y, not #1, #2
%       \xintFor* #2 in {0123456}\do {%  y - k
%           \xintdefiivar y = #2 + TupperKvariant;%
%           \xintifboolexpr 
% % MODIFIED TUPPER FORMULA USED IN INPUT SHOWS AS IS IN OUTPUT!
%           {1/2<floor(mod(floor(y/7)2^(-7x-mod(y,7)),2))}
%              {\put(\numexpr307-#1, \numexpr6-#2){\rule{1pt}{1pt}}}
%              {}
%       }
%   }
% \end{picture}

% ARRGGGGGGGGGGGHHHHHH after about 90s

% ! TeX capacity exceeded, sorry [pool size=6162206].
% <argument> ...535738417728939435264785252352[0],2 

% so we do it by cheating

\begin{picture}(308,7)
  \xintFor* #1 in {\xintSeq{0}{307}}\do {%
      % #1 will be x
      \xintFor* #2 in {0123456}\do {%
      % #2 will be y mod 7
      % no vanishing leading bits
              \if1\TupperBits{#1*7+#2+1}% charms of expandability
% The x coordinate goes from right to left and the y from top to bottom
% in Tupper plane
                 \put(\numexpr307-#1, \numexpr6-#2){\rule{1pt}{1pt}}
              \fi
      }
  }
\end{picture}

\end{document}
  • the ascii converter produced art on 8 lines, but using both * and /. After suppressing the lalter there remained 7 lines. Another converter had a tendency to split the banner into two parts, which made it more complicated to easily use as starting point. – jfbu Sep 20 at 14:36

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.