dc, 47 bytes
dc, 48 bytes
Also Bash + Unix utilities, 29 bytes
dc (47 bytes):
Try it online!
Note that negative numbers must be entered with an underscore instead of a minus sign, because that's how dc accepts numeric input. So write, for example, _5 instead of -5.
dc can't read character or string input into a variable and process it (there's a more detailed explanation below), but I found two ways of working around this:
The 47-byte dc solution works on input that has argument1 and argument2 reversed, with spaces as the delimiter. So counting from 1 up to (but not including) 10 in steps of 3 would be entered as:
< 1 10 3
If it's not acceptable to change the order of the arguments, I also give a 48-byte dc solution which keeps the original order of the arguments. This one uses
zz as the delimiter between arguments. So counting from 1 up to (but not including) 10 in steps of 3 again would use the following input line:
Finally, the same ideas yield a 29-byte bash solution.
Details on dc's lack of string processing, and how this program deals with that:
Handling this problem in dc is tricky, because dc doesn't accept string or char input as most languages do. When dc reads an input string, it immediately runs that string as a dc program (a macro), and then discards the string. You can't store the characters of the string in memory and process them later, or in any other way. This interferes with the requirement to have '<' or '>' in the input.
I'll show two ways around this. In the solution above (47 bytes), we switch the order of the first two inputs. The input delimiter is the space character. For example, to count from 1 up to (but not including) 10 in steps of 3, you'd input
< 1 10 3
Here's the idea behind this solution:
Macros in dc are stored in registers, and registers have single-character names. I store a macro in the register whose name is just a space character.
The program works by pushing a 0 and 1 on the stack before getting the input. Then, when the input is run as a dc program (which is what dc does with input lines), the '<' or '>' character is executed as a command, which is a conditional macro execution of the macro whose name is the next char after the '<' or '>'. Specifically, the top two items on the stack are popped. If the first item popped is < (respectively, >) the second item popped, the indicated macro is executed. The next character (after the '<' or '>') is a space, so the macro that we've stored in the register whose name is the space char is the one executed if the condition holds. But we had pushed 0 and 1 on the stack, so the first item popped was a 1, and the second item popped was a 0. As a result, the macro is executed only if the conditional test was >, not <. This lets us distinguish between '<' and '>' in the input.
The remaining items in the line are just numbers, and dc will simply push those numbers, in turn, on the stack.
Here's a detailed description. Most of the time, the counting variable (i in the pseudocode in the problem statement) is stored at the top of the stack.
1sb Store 1 in register b. (b will end up being 1 for '<', and -1 for '>').
[_1sb]s Note that there is a space after the second s. So the space char is the name of a macro which stores -1 in b.
z Push 0 on the stack.
z Push 1 on the stack.
? Accept input in the format above. This will:
- Store 1 or -1 in b, depending on whether you've typed "<" or ">"
- Push each of the three numbers in turn on the stack.
sd Save the increment in register d.
lb*sc Save either limit or -limit in register c, depending on whether the input started with "<" or ">".
[pld+lnx]sl Define a macro called l which is the body of our loop:
- Prints the top of the stack
- Adds the increment to the top of the stack.
- Calls macro n (the loop test).
[dlb*lcr<l]dsn Define a macro called n which is the test of the loop:
It checks to see if i (at the top of the stack) times b is less than c; if so, it calls macro l (looping back).
x Execute the loop test macro initially (a while loop needs to have a test at the top before entering the loop the first time).
On the other hand, the OP stated:
Input can be in one-line using any format "a/b/c/d" or "a,b,c,d" etc.
So maybe it isn't legitimate to switch the order and require b before a in the input.
Here's an alternative which keeps a, b, c, and d in their original order. We are allowed to use any delimiter; I'll use zz as the delimiter. So counting from 1 up to (but not including) 10 in steps of 3 would be entered as:
The new program, with zz-delimited input, is
dc (48 bytes):
This is one byte longer than the 47-byte first solution.
Try the zz-delimited version online!
I personally think the different-order
< 1 10 3 formatting is more in the spirit of the problem, but maybe
1zz<zz10zz3 better meets the actual technical specification.
You could probably get a shorter solution if you allowed different delimiters between the different input arguments, but I don't think that's in the spirit of the problem.
Bash + Unix utilities, 29 bytes
You can turn the underlying idea above into a bash program (which calls dc); this avoids all the difficulties with "<" and ">", and it also simplifies handling the various numeric parameters, so it's only 29 bytes long, the same as @zeppelin's bash+bc answer.
bash version (29 bytes):
Try the bash version online!
Here's a description of how the dc program inside the bash program works:
The value of i is stored at the top of the stack most of the time.
[ Start of macro (i is at the top of the stack). This macro will be called l.
p Print i
$4+ i += (4th argument)
d Duplicate i at the top of the stack.
$3 Push the 3rd argument onto the stack.
r Swap the top two items on the stack, so i is at the top and arg3 is second
$2l $2 is "<" or ">", causing the top two items to be popped from the stack, and macro l is then called (effectively looping back) if i < arg3 or i > arg3, respectively.
]sl End of macro definition; store macro in register l.
$1 Push argument 1 onto the stack (i = 1st argument).
d$3r$2l Just as above, call macro l if i < arg3, or i > arg3, depending on whether arg2 is "<" or ">"