Generate triangular signal

Given sample index, x, calculate sample value f(x) of triangular wave, with period of 4 samples and amplitude 1. Offset can be negative and sample value could be either {0, 1, -1}.

Test cases:

   -5 -> -1
-4 -> 0
-3 -> 1
-2 -> 0
-1 -> -1
0 -> 0
1 -> 1
2 -> 0
3 -> -1
4 -> 0
5 -> 1


Personally I know two approaches in C - the first is using lookup table, the second is using conditional instructions. For brownie points, could you impress me with a pure "math" approach? (I mean a pure functional approach, e.g. not using conditional instructions or using memory for LUT.) But this is not an restriction. If you can't, or your language does not support it - just post any solution

• What do you mean by "offset can be negative"? Also this is basically just a trigonometric function, so I'd be surprised if it isn't a dupe of something. May 16, 2017 at 1:08
• @JungHwanMin This has much more relaxed rules, so it's not really a dupe (though it asks for the same thing).
– user45941
May 16, 2017 at 1:09
• @Mego alright. Retracting my vote. May 16, 2017 at 1:10
• May 16, 2017 at 1:13
• Can the wave be out of phase relative to the example? May 16, 2017 at 17:45

Mathematica, 8 bytes

Im[I^#]&


Explanation

Im[I^#]&
I^#    (* Raise the imaginary unit to the input power *)
Im[   ]   (* Take the imaginary part *)

• Ohh, beautiful approach. How did I not see this? :D May 16, 2017 at 1:19
• cant see algo how to generate imaginary unit in C.. =( im assembler man ^^ using builtins in exotic languages is not in my favor ) however is an answer..
– user69099
May 17, 2017 at 23:54

TI-Basic, 75 4 bytes

sin(90Ans


(Degree mode) -1 byte from @immibis from my old answer.

imag(i^Ans


Pure-math approach on a calculator. :)

Just for fun, here's another pure-math (ish) solution for 9 bytes (In radian mode), or 8 bytes (Degree mode)

2/πsin-1sin(πAns/2 # Radians
90-1sin-1sin(90Ans # Degrees

• yeah, but you just forget an imag() implementation.. but usin others code is fine, though.. good answer :)
– user69099
May 18, 2017 at 0:03
• @xakepp35 I don't understand. imag() is a valid function on TI-BASIC. May 18, 2017 at 13:52
• What's wrong with sin(90Ans? Why do you need the extra 90-1sin-1? May 19, 2017 at 0:47
• @immibis The 90^-1sin^-1 makes it a triangle wave for all values, but sin(90Ans works for what the question asks. May 19, 2017 at 3:46

Python 2, 20 bytes

lambda n:n%2-n%4/3*2


Try it online!

I'm running a brute-force search for shorter arithmetic or bitwise expressions, I'll see if anything turns up. This one I hand-found.

• Brute force expression search? Nice! May 16, 2017 at 2:31

Julia 0.5, 12 bytes

!n=(2-n&3)%2


I like this approach because it's unlikely to be the shortest in any other language.

Try it online!

How it works

Julia's operator precedence is a bit unusual: unlike most other languages, bitwise operators have the same precedence as their arithmetic counterparts, so & (bitwise multiplication) has the same precedence as *.

First, n&3 takes the input modulo 4, with positive sign.

The result – 0, 1, 2, or 3 – is then subtracted from 2, yielding 2, 1, 0, or -1.

Finally, we take the signed remainder of the division by 2, returning 0, 1, 0, or -1.

Jelly, 3 bytes

ı*Ċ


Try it online!

How it works

ı*Ċ  Main link. Argument: n

ı*   Elevate i, the imaginary unit, to the n-th power.
Ċ  Take the imaginary part of the result.


dc, 13

Not sure if you count the modulo % operator as "pure math":

?1+d*v4%1-2%p


Try it online. Note that dc uses _ instead of - to indicate negative numbers.

Explanation

?              # read input
d*v         # duplicate, multiply, square root (poor-mans abs())
4%       # mod 4
1-     # subtract 1
2%   # mod 2
p  # print


Note that dc's % mod operator is the standard "CPU" version that maps negative values to negative values.

• Can you just do abs((x+1)%4)-1 instead? May 16, 2017 at 18:02

brainfuck, 136 bytes

>,>++++<[>->+<[>]>[<+>-]<<[<]>-]>>>>-[>+<-----]>--[-<+>>>+>>>+>>>+<<<<<<<<]<->>>>>>->--[>+<++++++]>++<<<<<<<<<<[[->>>+<<<]>>>-]>[.[-]]>.


Try it online!

There's probably a more trivial answer, but this essentially uses a table of values. Although brainfuck takes input as ASCII characters with positive values from 0 to 127, it still works as if it were able to accept negative values (to test, replace the , with n amount of - characters).

How it works

>,                                   take input (X)
>++++<                               take second input for modulo (4)
[>->+<[>]>[<+>-]<<[<]>-]             calculate X mod 4
>>>>-[>+<-----]>--                   create initial '1' character
[-<+>>>+>>>+>>>+<<<<<<<<]            duplicate '1' four times as 1,1,1,1
<->>>>>>->--[>+<++++++]>++<<<<<<<<<< change 1,1,1,1 to 0,1,0,-1
[[->>>+<<<]>>>-]>[.[-]]>.            move to the right X%4 * 3 times, then print the following two characters ( 0, 1, 0,-1)


Python, 2624 21 bytes

lambda x:(1j**x).imag


-2 bytes thanks to ValueInk for realizing that the mathematical method is actually longer than the trivial approach :P
-3 bytes thanks to Dennis for pointing out that I don't need the int(...), thus making this shorter :)

• lambda x:[0,1,0,-1][x%4] is actually shorter than your int-coerced answer lol May 16, 2017 at 1:44
• @ValueInk Oh...um this is embarrasing lol May 16, 2017 at 1:52
• Why would you use int() in the first place though? May 16, 2017 at 1:59
• @Dennis Because .imag gives a floating-point value and I'm not sure if that's allowed by the specs. It doesn't matter now :) May 16, 2017 at 2:19
• If floats aren't allowed, JavaScript will not be able to compete. May 16, 2017 at 2:28

Python, 20 bytes

lambda n:n%2*(2-n%4)


An unnamed function which returns the result.

Try it online!

Mathematica, 18 bytes

#~JacobiSymbol~46&

• This doesn't quite work: inputs 9 and 11 both give 1 as output, for example. The period of this function is 184, not 4. May 16, 2017 at 4:22
• However, JacobiSymbol[-4,#]& does work, and just costs one more byte. Nice idea! May 16, 2017 at 6:15
• again cant see an algrithm( just builtines written by others and couple of short code.. ah, all as usual. fine answer though
– user69099
May 17, 2017 at 23:56

Pari/GP, 12 bytes

n->imag(I^n)


Try it online!

<?=2<=>($argn&3?:2);  Haskell, 19 bytes Port of Dennis's Julia solution, just because he said it wouldn't be shortest in any other language. (Someone might still prove me wrong that it's shortest in Haskell.) f n=rem(2-nmod4)2  Try it online! Haskell has two different remainder functions, one (rem) works like the Julia one, while the other (mod) gives a positive result even when the first argument is negative, and so is suitable for translating &3. (Haskell's actual &, called .&., alas requires an import Data.Bits.) • As far as I can tell, a port of Dennis's Julia solution is optimal for JavaScript too (14 bytes). Shows that even Dennis is fallible! – Neil May 16, 2017 at 22:02 Octave, 22 bytes @(x)round(sin(x*pi/2))  Try it online! Ruby, 20 bytes Simple and clean. ->x{[0,1,0,-1][x%4]}  C99, 27 bytes Assuming you want the wave to be centered at the origin: f(n){return cpow(1i,n)/1i;}  otherwise f(n){return cpow(1i,n);} will do. I originally had a cimag in there, but apparently trying to return an int from a _Complex int yields the real part, so I used that. It makes sense, but it'snnothing I would have predicted. Behavior is the same in gcc and clang • cpow is undefined xD – user69099 May 17, 2017 at 23:59 • some #includes omitted, does not compile))))) – user69099 May 18, 2017 at 0:00 • but +1 just for C – user69099 May 18, 2017 at 0:00 • @xakepp35 That's actually not the fault of the includes, it's a linker problem. Compile with -std=c99 -lm and it should work. It works fine for me with both gcc and clang without any includes. Well, by fine I mean there are no errors, but a large number of warnings. May 18, 2017 at 0:06 05AB1E, 5 bytes 4%<Ä<  Try it online! The output is reversed, but from what I understood this is allowed: +1 byte to multiply output by -1 using (.  -5 -> 1 -4 -> 0 -3 -> -1 -2 -> 0 -1 -> 1 0 -> 0 1 -> -1 2 -> 0 3 -> 1 4 -> 0 5 -> -1  4% # Amplitude of 4... < # Period of 1... Ä # Absolute value... < # Period of 1 centered at 0...  • what I understood this is allowed – user69099 May 18, 2017 at 0:03 • test cases are not passed ;-) – user69099 May 18, 2017 at 0:04 • but +1 nice try – user69099 May 18, 2017 at 0:04 Pyth - 7 bytes (possibly 6) ta2%tQ4  Try it If the phase of the wave isn't important, 6 bytes: ta2%Q4  Try it Explanation: ta2%tQ4 Q # The input t # Subtract 1 to get the phase right (might not be necessary) % 4 # Take mod 4 a2 # Absolute value of the result - 2 t # Subtract 1 so the result is in [-1,0,1]  AWK, 26 bytes {$0=(sqrt(($0%4)^2)-2)%2}1  Try it online! This is an alternate approach using trig functions without the modulus operator. {$0=int(sin($0*atan2(0,-1)/2))}1  Try it online ! Javascript ES6, 18 17 bytes n=>n&1&&(++n&2)-1  Firstly, check if the input is even or odd and return 0 for all even values. For all odd inputs, increment and bitwise with 0b10 to remove any bits that don't interest us, then return the answer with an offset. const f = n=>n&1&&(++n&2)-1; for (let i = -5; i < 6; i++) { document.body.appendChild(document.createElement('pre')).innerHTML = f(${i}) => \${f(i)};
}

• Save a byte by replacing ? :0 with && May 16, 2017 at 22:28
• @SteveBennett Thanks, great idea! May 17, 2017 at 0:50

JavaScript, 15 bytes

n=>n&3&&2-(n&3)


Bitwise and 3 is equivalent to modulo 4 except without the weird rule on JavaScript's modulos of negative numbers. I did polynomial regression on the first four points at first but then realized I was being dumb because (1, 1), (2, 0), and (3, -1) is just 2-n.

a=n=>n&1&&2-(n&3);
console.log([a(-5), a(-4), a(-3), a(-2), a(-1), a(0), a(1), a(2), a(3), a(4), a(5)])

• very well! +1 for the answer
– user69099
May 18, 2017 at 0:05

R, 19 bytes

function(n)Im(1i^n)


Try it online!

A port of JungHwan Min's Mathematica answer.