Bounce-modulo two numbers The graph of the modulo operation (\$y = x \mod k\$) looks like this:



This is a very useful function, as it allows us to create "wrapping" behavior. However, it is very cumbersome when I want to use it to create an appearance of "bouncing" between two walls. The graph of the "bounce" function (\$y = \text{bounce} (x, k)\$) looks like this:



The period of the graph of \$y = x \mod k\$ is \$k\$. The period of the graph of \$y = \text{bounce} (x, k)\$ is \$2k\$, because it moves upwards for \$k\$ units, and then moves downwards for another \$k\$ units, before returning to where it started. For both functions, the minimum value for \$y\$ is 0, and the maximum is \$k\$ (Actually, for the modulus function with integral inputs, it's \$k-1\$). In addition, for both functions, the value where \$x=0\$ is 0.

The challenge

Given an integer \$x\$ and a positive integer \$k\$, return an integer or floating-point approximation of \$y = \text{bounce} (x, k)\$.

This is code-golf, so the shortest valid submission (counted in bytes) wins.

Test Cases

  x,  k -&gt; bounce(x, k)
  0, 14 -&gt;            0
  3,  7 -&gt;            3
 14, 14 -&gt;           14
 15, 14 -&gt;           13
-13, 14 -&gt;           13 (12.999997 etc would be an acceptable answer)
-14, 14 -&gt;           14
191,  8 -&gt;            1
192,  8 -&gt;            0


Bonus points for a Fourier-based approach in Fourier.
x86-64 Machine Code, 18 bytes
97
99
31 D0
29 D0
99
F7 FE
29 D6
A8 01
0F 45 D6
92
C3 

This code defines a function in x86-64 machine language that computes bounce(x, k). Following the System V AMD64 calling convention used on Gnu/Unix systems, the x parameter is passed in the EDI register, while the k parameter is passed in the ESI register. As with all x86 calling conventions, the result is returned in the EAX register.
To call this from C, you would prototype it as follows:
int Bounce(int x, int k);

Try it online!
Ungolfed assembly mnemonics:
; Take absolute value of input 'x' (passed in EDI register).
; (Compensates for the fact that IDIV on x86 returns a remainder with the dividend's sign,
; whereas we want 'modulo' behavior---the result should be positive.)
xchg   eax, edi      ; swap EDI and EAX (put 'x' in EAX)
cdq                  ; sign-extend EAX to EDX:EAX, effectively putting sign bit in EDX
xor    eax, edx      ; EAX ^= EDX
sub    eax, edx      ; EAX -= EDX

; Divide EDX:EAX by 'k' (passed in ESI register).
; The quotient will be in EAX, and the remainder will be in EDX.
; (We know that EAX is positive here, so we'd normally just zero EDX before division,
; but XOR is 2 bytes whereas CDQ is 1 byte, so it wins out.)
cdq
idiv   esi

; Pre-emptively subtract the remainder (EDX) from 'k' (ESI),
; leaving result in ESI. We'll either use this below, or ignore it.
sub    esi, edx

; Test the LSB of the quotient to see if it is an even number (i.e., divisible by 2).
; If not (quotient is odd), then we want to use ESI, so put it in EDX.
; Otherwise (quotient is even), leave EDX alone.
test   al, 1
cmovnz edx, esi

; Finally, swap EDX and EAX to get the return value in EAX.
xchg   eax, edx
ret

Note that the first section (that takes the absolute value) could have equivalently been written:
; Alternative implementation of absolute value
xchg    eax, edi
neg     eax
cmovl   eax, edi

which is the exact same number of bytes (6). The performance should be similar, perhaps slightly faster (except on certain Intel chips, where conditional moves are slow).
XCHG is, of course, relatively slow and would not be preferred over MOV except in code golfing (that the former is 1-byte when one of the operands is the accumulator, whereas a register-register MOV is always 2 bytes).