6

I am new to LaTeX and found a helpful custom command for repeating text n times here. Below is an example use

\documentclass{minimal}
\usepackage{pgffor}
\newcommand{\myrepeat}[2]{\foreach \n in {1,...,#1}{#2}}

\begin{document}
\myrepeat{6}{x}  % prints xxxxxx
\end{document}

My goal is to pass a decimal number as the first argument to the command (as opposed to an integer currently). The for-loop in the command should round the decimal to determine how many iterations to execute. This way I can universally change the rounding mode (i.e. floor, ceiling, closest integer, etc) later just by updating the one command. For instance

\myrepeat{3.2}{x}  % should print xxx
\myrepeat{3.7}{x}  % should print xxxx

How can I achieve this behavior?

Most other threads I have seen only deal with printing rounding/ceiling/floor symbols instead of actually performing the rounding math and allowing you to use the resulting number in further computations.

6

One approach would be this. ceil and floor are alternatives to round. There are also command versions of each, as Alan Munn mentions in a comment, i.e. \pgfmathround{#1}, \pgfmathceil{#1}, \pgfmathfloor{#1}.

\documentclass{article}
\usepackage{pgffor}
\newcommand{\myrepeat}[2]{%
   \pgfmathparse{round(#1)}% set rounding function here
   \foreach \n in {1,...,\pgfmathresult}{#2}}

\begin{document}
\myrepeat{3.2}{x}  % should print xxx

\myrepeat{3.7}{x}  % should print xxxx
\end{document}
| improve this answer | |
  • Slightly shorter: \pgfmathround{#1} ... {1,...,\pgfmathresult} – Alan Munn Jul 18 '19 at 18:36
  • @AlanMunn Indeed, thanks. – Torbjørn T. Jul 18 '19 at 18:42
4

Here's a fairly general macro where you can set the mode as an optional argument: choose between round (default), floor, ceil or nearest.

The \generalrepeat macro accepts the starting point (an integer), the step (an integer, default 1) and the end point (a floating point number).

The \myrepeat macro is a reduced version, always starting from 1 with step 1.

In the final argument (code to repeat), the current value in the loop is denoted by #1.

\documentclass{article}
\usepackage{xfp}

\ExplSyntaxOn
\NewDocumentCommand{\generalrepeat}
 {
  O{round} % the mode
  m % the starting point
  O{1} % the step
  m % the final point
  +m % the code to repeat (can contain \par)
 }
 {
  \klinke_repeat_general:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 }
 }

\NewDocumentCommand{\myrepeat}
 {
  O{round} % the mode
  m % the final point
  +m % the code to repeat (can contain \par)
 }
 {
  \klinke_repeat_general:nnnnn { #1 } { 1 } { 1 } { #2 } { #3 }
 }

\cs_new_protected:Nn \klinke_repeat_general:nnnnn
 {
  \cs_set_eq:Nc \__klinke_repeat_mode:n { __klinke_repeat_#1:n }
  \cs_set_protected:Nn \__klinke_repeat_code:n { #5 }
  \int_step_function:nnnN
   { #2 } % start
   { #3 } % step
   { \__klinke_repeat_mode:n { #4 } } % end
   \__klinke_repeat_code:n % action
 }

\cs_new:Nn \__klinke_repeat_round:n { \fp_eval:n { round(#1,0,1) } }
\cs_new:Nn \__klinke_repeat_floor:n { \fp_eval:n { floor(#1,0) } }
\cs_new:Nn \__klinke_repeat_ceil:n  { \fp_eval:n { ceil(#1,0) } }
\cs_new:Nn \__klinke_repeat_nearest:n
 {
  \fp_eval:n { #1 - floor(#1,0) < 0.5 ? floor(#1,0) : ceil(#1,0) }
 }
\ExplSyntaxOff

\begin{document}

\generalrepeat{1}{3.4}{#1 }---
\generalrepeat{1}{3.5}{#1 }---
\generalrepeat{1}{3.6}{#1 }

\generalrepeat[ceil]{1}{3.4}{#1 }---
\generalrepeat[ceil]{1}{3.5}{#1 }---
\generalrepeat[ceil]{1}{3.6}{#1 }

\generalrepeat[floor]{1}{3.4}{#1 }---
\generalrepeat[floor]{1}{3.5}{#1 }---
\generalrepeat[floor]{1}{3.6}{#1 }

\generalrepeat[nearest]{1}{3.4}{#1 }---
\generalrepeat[nearest]{1}{3.5}{#1 }---
\generalrepeat[nearest]{1}{3.6}{#1 }

\myrepeat{3.4}{x}---\myrepeat[floor]{3.4}{x}---%
\myrepeat[ceil]{3.4}{x}---\myrepeat[nearest]{3.4}{x}

\myrepeat{3.5}{x}---\myrepeat[floor]{3.5}{x}---%
\myrepeat[ceil]{3.5}{x}---\myrepeat[nearest]{3.5}{x}

\myrepeat{3.6}{x}---\myrepeat[floor]{3.6}{x}---%
\myrepeat[ceil]{3.6}{x}---\myrepeat[nearest]{3.6}{x}

\end{document}

enter image description here

Both round and nearest integer are implemented to go upward in case of a tie (the 3.5 case).

| improve this answer | |
3

You can use the expandable functionality of xfp:

enter image description here

\documentclass{article}

\usepackage{pgffor,xfp}

\newcommand{\myrepeat}[2]{\foreach \n in {1,...,\fpeval{floor(#1)}}{#2}}

\begin{document}

\myrepeat{6}{x}                % prints xxxxxx

\myrepeat{3.2}{x}              % prints xxx

\myrepeat{8.1 * sin(pi / 6)}{x}% prints xxxx sin(pi/6) = 1/2; 8.1 * 1/2 = 4.05

\end{document}

You can use ceiling(#1), or round(#1,0), or whatever calculation you want.

| improve this answer | |
  • 1
    The function round uses “ties to even”, so both round(3.5,0) and round(4.5,0) will yield 4. You get “ties to infinity” with round(3.5,0,1) or round(4.5,0,1) that would yield 4 and 5 respectively. – egreg Jul 18 '19 at 20:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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