13
\$\begingroup\$

You have been collecting data from a Advanced Collecting Device Controller™ for a long time. You check the logs, and to your horror you discover that something has gone terribly wrong: the data only contains the last bits of the numbers!

Luckily, you know the starting value and that the value never changes fast. That means you can recover the rest by just finding the distance from the start.

Challenge

You will write a program or a function to calculate the amount a value has changed, given a modulus N and a list of the intermediate values modulo N.

The change between every pair of numbers is always less than N/2, so there will only be one valid answer for each test case.

You will be given as input an integer N > 2 and a list of values, in a format of your choice. Input may be given via STDIN or command line or function arguments.

You will output a single integer, the amount the original value has changed. Output may be printed to STDOUT or returned.

Rules

  • Your program must work for any distance and modulus less than 2^20.
  • You may assume that:
    • N is at least 3.
    • The list has at least 2 values.
    • All the values in the list are at least 0 and less than N.
    • All changes in the numbers are less than N/2.
  • Anything else is an invalid input, and your program may do whatever it wants.
  • Standard loopholes, any non-standard libraries and built-in functions for this exact purpose are forbidden.
  • This is , so the shortest program in bytes wins.

Example test cases

Input:

3
0 1 2 2 0 1 0 2 1 2 0 1 2 1 1

Output:

4

Explanation (with example value):

Value mod 3: 0 1 2 2 0 1 0 2 1 2 0 1 2 1 1
Value:       0 1 2 2 3 4 3 2 1 2 3 4 5 4 4

Input:

10
5 2 8 9 5

Output:

-10

Explanation (with example value):

Value mod 10:  5  2  8  9  5
Value:        15 12  8  9  5

Invalid inputs:

2
0 0 0 0 0

(too small modulus)

6
2 5 4 2

(too large change between 2 and 5)

\$\endgroup\$
3
  • \$\begingroup\$ A format of your choice is a slippery slope. Can my GolfScript solution rely on an input list looking like :^;[5 2 8 9 5](\ ? \$\endgroup\$
    – Lynn
    May 13, 2015 at 13:16
  • 3
    \$\begingroup\$ @Mauris Generally, no... "a format of your choice" is usually assumed to mean "a conventional representation in your language of choice". \$\endgroup\$ May 13, 2015 at 13:42
  • \$\begingroup\$ You can, however, rely on the input list looking like "10 5 2 8 9 5" or "10,5 2 8 9 5" or "10 5,2,8,9,5". \$\endgroup\$
    – Sparr
    May 13, 2015 at 14:00

11 Answers 11

9
\$\begingroup\$

Python 2, 53 bytes

lambda n,l:sum((b-a+n/2)%n-n/2for a,b in zip(l,l[1:]))

Super straight forward answer. I wonder if there is a shorter way.

\$\endgroup\$
3
  • \$\begingroup\$ I missed that bit. Thanks. \$\endgroup\$
    – Lynn
    May 13, 2015 at 13:01
  • \$\begingroup\$ @Jakube I already did it - I wasn't aware of .:_2 to generate pairs until I saw your answer - I was using zip. \$\endgroup\$
    – orlp
    May 13, 2015 at 16:42
  • 1
    \$\begingroup\$ @Jakube I got it down to 19 :) \$\endgroup\$
    – orlp
    May 13, 2015 at 16:44
7
\$\begingroup\$

Mathematica, 30 bytes

Tr@Mod[Differences@#2,#,-#/2]&

This is an anonymous function which takes two arguments. Example usage:

Tr@Mod[Differences@#2,#,-#/2]&[3, {0, 1, 2, 2, 0, 1, 0, 2, 1, 2, 0, 1, 2, 1, 1}]
(* 4 *)
Tr@Mod[Differences@#2,#,-#/2]&[10, {5, 2, 8, 9, 5}]
(* -10 *)

This works by taking the Differences between successive elements, wrapping them to the range -n/2 to +n/2 with Mod and its offset parameter, then taking the total with Tr (matrix trace, sum of diagonal elements).


Note that even ungolfed it's only 43 bytes!

f[n_, l_] := Total[Mod[Differences[l], n, -n/2]]
\$\endgroup\$
2
  • \$\begingroup\$ @ is unnecessary when you're already calling the function with square brackets. Having both is a syntax error. \$\endgroup\$ May 14, 2015 at 9:11
  • \$\begingroup\$ @DavidZhang Whoops, don't know what I was thinking. Serves me right for trying to answer without opening Mathematica! \$\endgroup\$ May 14, 2015 at 12:14
5
\$\begingroup\$

J, 24 bytes

[+/@(]-(>-:)~*[)[|2-~/\]

Usage:

   f=:[+/@(]-(>-:)~*[)[|2-~/\]

   3 f 0 1 2 2 0 1 0 2 1 2 0 1 2 1 1
4

   10 f 5 2 8 9 5
_10

Will try to golf more and add some explanation after that.

Try it online here.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Sure its J and not CJam ? :P \$\endgroup\$
    – Optimizer
    May 13, 2015 at 12:00
4
\$\begingroup\$

Pyth, 20 19 bytes

sm-J/Q2%+-FdJQ.:vw2

Stole .:_2 from Jakube, idea from Mauris.

\$\endgroup\$
3
\$\begingroup\$

R, 38 bytes

function(n,v)sum((diff(v)+n/2)%%n-n/2)

This creates an unnamed function that accepts an integer and a vector as input and returns a single integer. To call it, give it a name, e.g. f=function(n,v)....

Ungolfed + explanation:

f <- function(n, v) {
    # Compute the differences between sequential elements of v
    d <- diff(v)

    # Add n/2 to the differences and get the result modulo n
    m <- (d + n/2) %% n

    # Subtract n/2 then sum the vector
    sum(m - n/2)
}

Examples:

> f(3, c(0, 1, 2, 2, 0, 1, 0, 2, 1, 2, 0, 1, 2, 1, 1))
[1] 4

> f(10, c(5, 2, 8, 9, 5))
[1] -10
\$\endgroup\$
3
\$\begingroup\$

MatLab, 33 bytes

@(x,y)sum(mod(diff(y)+x/2,x)-x/2)

My apologies, this is my first answer on this website. Typing this in MatLab then using the input ans(modulus_value, [intermediate_values]) will return the requested value, where 'modulus_value' is the modulus value, and 'intermediate_values' is a list of the intermediate values separated by either spaces or commas.

Example:

ans(3, [0 1 2 2 0 1 0 2 1 2 0 1 2 1 1])

The anonymous function takes advantage of MatLab's mod, diff, and sum functions to compute the answer. First, the difference between each of the intermediate values is calculated. The result is then offset by the modulus divided by two, resulting in a set of difference values that is bound by [-modulus/2 modulus/2]. The result is then offset and summed again.

I think this can be golfed more, I'll be back soon with an update. Special thanks to @2012rcampion for the idea.

Edit: Matlab's unwrap function almost works here, but it's tough to golf. The following code returns an array where the last value is the amount the first value has changed: @(x,y)unwrap(y/x*2*pi)/2/pi*x-y(1)

The intermediate values are scaled to the range of [-pi pi], then "unwrapped" such that no consecutive value is more than pi apart. These values are then re-scaled and shifted, resulting in an array of distances from the starting value.

Interesting, but not very practical for this challenge :D

\$\endgroup\$
2
\$\begingroup\$

TI-BASIC, 15 bytes

Input N
sum(N/πtan⁻¹(tan(ΔList(πAns/N

Takes the list from Ans and the modulus from Input.

                       πAns/N    ; Normalize the list to [0,π)
                 ΔList(          ; Take differences, which are in the range (-π,π)
       tan⁻¹(tan(                ; Modulo, but shorter. Now elements are in (-π/2,π/2)
    N/π                          ; Multiply by N/π. These are displacements at each step.
sum(                             ; Add up all the displacements
\$\endgroup\$
2
\$\begingroup\$

Pyth, 29 bytes

+sm**._K-Fdvz>y.aKvz.:Q2-eQhQ

Try it online: Pyth Compiler/Executor

\$\endgroup\$
3
  • \$\begingroup\$ Input is space-separated, not comma-separated; your program doesn't seem to handle this. \$\endgroup\$
    – Lynn
    May 13, 2015 at 12:56
  • 2
    \$\begingroup\$ @Mauris "a list of values, in a format of your choice" \$\endgroup\$
    – Jakube
    May 13, 2015 at 12:57
  • \$\begingroup\$ Oh, my bad! I totally missed that part of the spec. \$\endgroup\$
    – Lynn
    May 13, 2015 at 13:01
2
\$\begingroup\$

CJam, 27 bytes

0q~:_2ewf{~\m1$2/:I+\,=I-+}

Test it here.

\$\endgroup\$
0
2
\$\begingroup\$

Pip, 39 bytes

Qn$+({a>n/2?a-na<-n/2?a+na}Mg@>1-g@<-1)

Requires the list of data as command-line arguments and the modulus on STDIN. If that's too much of a stretch, I have a version that takes two command-line args for 5 bytes more.

Explanation:

                                         g is list of cmdline args (implicit)
Qn                                       Read n from stdin
                            g@>1         All but the first of the cmdline args
                                -g@<-1   ...minus all but the last of the cmdline args
                                         (i.e. a list of the differences of adjacent items)
     {                    }M             ...to which, map the following function:
      a>n/2?a-n                            If diff is too big, subtract n;
               a<-n/2?a+n                  else if too small, add n;
                         a                 else return unchanged
  $+(                                 )  Sum; print (implicit)

And just to prove that this not-so-competitive score is more reflective on my golfing skills than my language, here's a port of Mauris's Python solution in 30 bytes:

Qn$+({(n/2-$-a)%n-n/2}MgZg@>1)
\$\endgroup\$
2
\$\begingroup\$

Jelly

6 bytes

Iæ%H}S

Try it online!

How it works

Iæ%H}S    Main link. Left input: A (list). Right input: N (integer).

I         Compute the increments (deltas of consecutive elements) of A.
   H}     Halve the right input (N).
 æ%       Mod the increments into (-N/2, N/2].
     S    Take the sum of all results.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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