31
\$\begingroup\$

The mean of a population \$(x_1,\dots,x_n)\$ is defined as \$\bar x=\frac1n\sum_{i=1}^n x_i\$. The (uncorrected) standard deviation of the population is defined as \$\sqrt{\frac1n\sum (x_i-\bar x)^2}\$. It measures how dispersed the population is: a large standard deviation indicates that the values are far apart; a low standard deviation indicates that they are close. If all values are identical, the standard deviation is 0.

Write a program or function which takes as input a (non-empty) list of non-negative integers, and outputs its standard deviation. But check the scoring rule, as this is not code golf!

Input/Output

Input/Output is flexible. Your answer must be accurate to at least 2 decimal places (either rounding or truncating). The input is guaranteed to contain only integers between 0 and 255, and to not be empty.

Scoring

To compute your score, convert your code to integer code points (using ASCII or whatever code page is standard for your language) and compute the standard deviation. Your score is the number of bytes in your code multiplied by the standard deviation. Lower score is better. You should therefore aim for code which at the same time (a) is short and (b) uses characters with close codepoints.

Here is an online calculator to compute your score (assuming you use ASCII).

Test cases

Input              | Output
77 67 77 67        | 5
82                 | 0
73 73 73           | 0
83 116  97 116 115 | 13.336

A word of caution about built-ins: if your language has a built-in, that's fine (and good for you if it only uses one character!). But make sure that it uses \$n\$ and not \$n-1\$ as the denominator in the formula, or else your answer won't be valid.

\$\endgroup\$
7
  • 2
    \$\begingroup\$ I had wondered if it would be worth it adding extra filler characters to one's code reduce the score, but it looks like that never works. It can reduce the sdev, but the score of sdev*length always goes up. \$\endgroup\$
    – xnor
    Aug 24, 2020 at 6:33
  • 2
    \$\begingroup\$ @mypronounismonicareinstate Yes, a solution in Lenguage or Unary will achieve a score of 0. As I wrote in the Sandbox: if somebody writes code to compute the standard deviation in Unary or Lenguage, they deserve my upvote! \$\endgroup\$ Aug 24, 2020 at 6:41
  • 6
    \$\begingroup\$ Related: Calculate Standard Deviation as pure code golf \$\endgroup\$
    – xnor
    Aug 24, 2020 at 6:57
  • 2
    \$\begingroup\$ Lenguage score 0 anyone? \$\endgroup\$ Aug 24, 2020 at 17:33
  • 2
    \$\begingroup\$ @JonathanAllan I'm trying, Might take a while though... \$\endgroup\$
    – CShark
    Aug 27, 2020 at 20:00

16 Answers 16

10
\$\begingroup\$

MATL, score 65.30697

tYmhZs

Try it online! Or verify all test cases.

How it works

The built-in function Zs with its default arity (1 input, 1 output) computes the corrected standard deviation:

\$\sqrt{\frac 1 {n-1}\sum (x_i-\bar x)^2}\$

The uncorrected standard deviation can be obtained with the 2-input version of Zs: 1&Zs, where 1 as second input means uncorrected. l or T could be used instead of 1 to reduce the score, but & is very far from the other characters. 2$ or H$ could be used instead of &, but $ is even farther.

So it is better to use the default version of Zs (corrected standard deviation) on the input with its mean appended. This increases the input length by 1 and contributes 0 in the numerator, which causes the corrected standard deviation to become uncorrected.

t     % Implicit input: numeric vector. Duplicate
Ym    % Mean
h     % Concatenate the input vector with its mean
Zs    % Corrected standard deviation
\$\endgroup\$
8
\$\begingroup\$

J, 19 bytes, Score 119.8249

-~1 thanks to Bubbler

Tries to have most characters between 0x23 and 0x2F #$%&'()*+,-./, with : being a bit further away.

(+/%$)&.:*:&(-+/%#)

Try it online!

How it works

(+/%$)&.:*:&(-+/%#)
            (-+/%#) x - sum divided by length
         *:&        and squared
(+/%$)&.:           mean of that
      &.:*:         reverse square -> square root
\$\endgroup\$
3
  • \$\begingroup\$ score 144 by avoiding @. \$\endgroup\$
    – Bubbler
    Aug 24, 2020 at 8:00
  • \$\begingroup\$ @Bubbler expanding is surprisingly even better! Funny scoring system. \$\endgroup\$
    – xash
    Aug 24, 2020 at 8:03
  • 1
    \$\begingroup\$ score 119.8 by changing the leftmost # to $. Input is required to be a vector in this case. \$\endgroup\$
    – Bubbler
    Aug 25, 2020 at 0:14
6
\$\begingroup\$

Google Sheets, Score 142.6885

=STDEVP(F:F

Google Sheets automatically closes parentheses, and using F as the input column minimizes the standard deviation. This saves one byte over Excel's uncorrected standard deviation, since Excel uses STDEV.P instead of STDEVP

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice idea to input in the F column to reduce the standard deviation! \$\endgroup\$ Aug 24, 2020 at 8:38
4
\$\begingroup\$

R, 34 bytes 24 bytes, score 789.5923 723.4687 722.6112

sd(c(scan()->J,mean(J)))

Try it online!

Edit: switched to a shorter formula to calculate the population sd (which I found here), which now only benefits from selecting the best variable name among the golfs outlined below for the previous version.

Edit2: score reduced by 0.8575 thanks to Robin Ryder

The (previous) ungolfed code is was: x=scan();sqrt(mean((x-mean(x))^2)) (which would have a score of 1104.484)

From this, sequential score-improving golfs are:

  • x=scan();`?`=mean;sqrt(?(x-?x)^2) = re-define mean() as a single character unary operator (score 983.8933)
  • x=scan();`?`=mean;(?(x-?x)^2)^.5 = exchange sqrt() for ()^.5 (score 918.6686)
  • H=scan();`?`=mean;(?(H-?H)^2)^.5 = exchange x for H which is the closest codepoint value to the mean of the program, thereby reducing the standard deviation (score 801.4687)
  • I=scan();`?`=mean;I=I-?I;(?I^2)^.5 = first calculate x-mean(x) separately, to reduce number of parentheses (which are at the far end of the ASCII range, and so increase the standard deviation), and re-adjust the variable name to I. Although this increases the code length by 2 characters, it reduces the score to 789.5923.

R + multicon, 15 bytes, score 273.5032

multicon::popsd

Trivial solution using built-in popsd function from multicon library.
Not installed at TIO, but you can try it at rdrr.io by copy-pasting this code:

x=c(67,77,67,77)  # data
multicon::popsd(x)
\$\endgroup\$
6
  • \$\begingroup\$ scan()->J rather than J<-scan() should improve your score slightly. \$\endgroup\$ Aug 24, 2020 at 11:33
  • \$\begingroup\$ Doh! I had the ASCII table sitting right in front of me trying to optimize this: why on earth didn't I realise that? Thanks a lot! \$\endgroup\$ Aug 24, 2020 at 11:35
  • \$\begingroup\$ For external packages, we usually require that your code either includes library(multicon) or that you call multicon::popsd, i.e. you cannot assume that the package is loaded when you start R). There was a short discussion about this in the golfr chatroom in July 2019. \$\endgroup\$ Aug 24, 2020 at 11:36
  • \$\begingroup\$ Ah. I somehow thought that it was also Ok to specify the language as 'R + multicon' (rather than simply 'R' which would require extra stuff to load the packages), but I can't remember why I thought so... \$\endgroup\$ Aug 24, 2020 at 11:44
  • \$\begingroup\$ At some point in the past I thought the same as you, but eventually got convinced by the consensus position: the language is 'R + multicon' (since you have to install both), and then you have to explicitly load the external package. \$\endgroup\$ Aug 24, 2020 at 11:53
4
\$\begingroup\$

Wolfram Language (Mathematica), Score 537.0884

A@((#-A@#)^2)^.5&;A=Mean

Try it online!

@att saved 17.6142 points

\$\endgroup\$
1
  • \$\begingroup\$ 537.0884 \$\endgroup\$
    – att
    Aug 25, 2020 at 20:13
3
\$\begingroup\$

Python 3, Score 680.5175

Where the golfiest solution is not the best. I doubt any non-builtin could be better but I might be wrong.

import statistics;statistics.pstdev

Try it online!

Python 3, Score 733.6818

from statistics import*;pstdev

Python 3, Score 798.5587

__import__('statistics').pstdev
\$\endgroup\$
7
  • 3
    \$\begingroup\$ @Dingus These are all function submissions. These are just different ways of referring to the same function, which is the library routine that does all of the required work. \$\endgroup\$
    – Neil
    Aug 24, 2020 at 9:40
  • \$\begingroup\$ @Dingus Providing a function is enough, even if the function is not named \$\endgroup\$
    – Luis Mendo
    Aug 24, 2020 at 10:10
  • 1
    \$\begingroup\$ @LuisMendo No problems with anonymous functions (I often use them myself). The confusion came because I don't recall having seen just a bare function before (I'm used to seeing things like (pseudocode) lambda s: stdev(s)). But looking at that pseudocode I can see that wrapping in a lambda is redundant here. It seems obvious now, but I've learnt something. \$\endgroup\$
    – Dingus
    Aug 24, 2020 at 11:05
  • \$\begingroup\$ @Dingus Ah, I see what you mean. That also confused me back in the day \$\endgroup\$
    – Luis Mendo
    Aug 24, 2020 at 12:02
  • 2
    \$\begingroup\$ @JonathanAllan There was a meta discussion on this, but it was a few years ago. \$\endgroup\$ Aug 24, 2020 at 17:54
3
\$\begingroup\$

05AB1E, Score: 531.168 431.516 360.278 (10 15 14 bytes)

Osg/nsn-Osg/(t

Uses the 05AB1E coding page. The characters used have the codepoints [79,73,103,47,110,73,110,45,68,79,73,103,47,40,116].

Try it online or verify all test cases.

Explanation:

                # Get the arithmetic mean of the (implicit) input-list by:
O               #  Summing the (implicit) input-list
 I              #  Push input-list again
  g             #  Pop and push its length
   /            #  Divide the sum by this length
                #  (which gives a better score than the builtin `ÅA`)
    n           # Square it
     I          # Push the input again (better score than `s` or `¹`)
      n         # Square each value in the input as well
       -        # Subtract each from the squared mean
                # Take the arithmetic mean of that list again by:
        O       #  Summing it
         Ig     #  Push the input-list again, and pop and push its length
           /    #  Divide the sum by this length
            (   # Negate it
             t  # And take its square-root
                # (after which the result is output implicitly)
\$\endgroup\$
0
3
\$\begingroup\$

JavaScript (ES7), Score  1359 1228  1156.077

Saved 72 points thanks to @edc65

D=>D[F='map'](C=>B-=(C+E/A)**2/A,D[F](C=>E+=--A?C:9,A=B=E=0))&&B**.5

Try it online!

Character breakdown

 char. | code | count
-------+------+-------
   0   |  48  |   1
   2   |  50  |   1
   5   |  53  |   1
   9   |  57  |   1
   &   |  38  |   2
   '   |  39  |   2
   (   |  40  |   3
   )   |  41  |   3
   *   |  42  |   4
   +   |  43  |   2
   ,   |  44  |   2
   -   |  45  |   3
   .   |  46  |   1
   /   |  47  |   2
   :   |  58  |   1   <-- mean ≈ 59.43
   =   |  61  |   9
   >   |  62  |   3
   ?   |  63  |   1
   A   |  65  |   4
   B   |  66  |   3
   C   |  67  |   4
   D   |  68  |   3
   E   |  69  |   3
   F   |  70  |   2
   [   |  91  |   2
   ]   |  93  |   2
   a   |  97  |   1
   m   | 109  |   1
   p   | 112  |   1
\$\endgroup\$
2
  • \$\begingroup\$ Better pre calculating both sum and length, avoiding 1 'map' (in fact avoiding a couple of brackets): D=>D[F='map'](C=>B-=(C+E/A)**2/A,D[F](C=>E+=--A?C:9,A=B=E=0))&&B**.5 score 1156.077 \$\endgroup\$
    – edc65
    Aug 27, 2020 at 7:13
  • \$\begingroup\$ @edc65 That's a great improvement. Thanks! (And nice to see you around, btw.) \$\endgroup\$
    – Arnauld
    Aug 28, 2020 at 15:17
3
\$\begingroup\$

Arn, score = 925.3172 655.6836 602.7985 123.2274

sdev:s

Uses the builtin standard deviation function. Go to the old answer for a more interesting one

Old Answer

I don't compress it because Standard Deviation would be way higher. I have updated this answer, since I found a much shorter method (sitting at 14 bytes). Link here (this is the program the score refers to). I will leave the original program for posterity's sake

:/(+v{:*v-(:s.mean}\)/((:s)#

Try it!

Explained

$$\large\sqrt {\frac1n \sum(x_i-\bar x)^2}$$ Just made use of the formula. :/ is the sqrt prefix, :* is the square prefix, +v{:*v-(:s.mean}\ Folds with + (addition) after mapping with the block v{:*v-(:s.mean}. v is current entry, :s splits on space (no variable is provided, so it assumes the variable _, which is STDIN). Then it just divides by the length (# suffix).

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

Io, score = 1454.7164672196433912

-19.58295474318379 thanks to @ManishKundu

method(:,:map(Z,(Z- :average)squared)average sqrt)

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ I think you can save some score by using different variable names instead of I and J, perhaps Y and Z? \$\endgroup\$ Aug 24, 2020 at 11:49
2
\$\begingroup\$

Jelly, (14 bytes), score 218.314

(218.31399405443526)

+/÷LN+*2+/÷L*.

Try it online! Or see a self-evaluation.

Bytecode: 2b 2f 1c 4c 4e 2b 2a 32 2b 2f 1c 4c 2a 2e

How?

A naive program would be _Æm²Æm½for 348.47 (subtract the mean from each, square each, take the mean of that and then square root it).

We know that to get rid of the two byte monad Æm whose code-points are quite far apart (0x0d and 0x6d) we need to either:

  • divide using ÷ (0x1c), or
  • multiply, × (0x11), and invert, İ (0xc6)

But the latter bytes are also fairly far apart, so this answer attempts to use bytes close to ÷ (0x1c).

+/÷LN+*2+/÷L*. - Link: list of numbers, A
 /             - reduce (A) by:
+              -   addition             -> sum(A)
   L           - length (A)
  ÷            - divide                 -> mean(A)
    N          - negate
     +         - add (to A, vectorised) -> [mean(A)-v for v in A]
       2       - two
      *        - exponentiate           -> [(mean(A)-v)² for v in A]
         /     - reduce by:
        +      -   addition             -> sum((mean(A)-v)² for v in A)
           L   - length (A)
          ÷    - divide                 -> sum((mean(A)-v)² for v in A)/n
             . - a half
            *  - exponentiate           -> √(sum((mean(A)-v)² for v in A)/n)
\$\endgroup\$
2
\$\begingroup\$

Wolfram Language (Mathematica), 31 bytes, score 478.3451

a[a_]=RootMeanSquare[a-Mean[a]]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Charcoal, 15 bytes, stddev 46.741654, score 701.12481

I₂∕ΣX⁻θ∕ΣθLθ²Lθ

Try it online! Link is to verbose version of code. Link test case is the byte values in the Charcoal code page of the code. Explanation:

         θ      Input `x`
        Σ       Summed
       ∕  Lθ    Divided by `n`
     ⁻θ         Vectorised subtracted from `x`
    X       ²   Squared
   Σ            Summed
  ∕          Lθ Divided by `n`
 ₂              Square rooted
I               Cast to string
                Implicitly printed

Note that the alternative formula for the standard deviation, \$ \sqrt{\bar{x^2}-\bar x^2} \$, while having a slightly smaller standard deviation, takes 17 bytes, and therefore results in a higher score of 755.6.

\$\endgroup\$
1
\$\begingroup\$

Setanta, score: 2728.508

gniomh(g){f:=0h:=0e:=fad@g le i idir(0,e){d:=g[i]f+=d h+=d*d}toradh freamh@mata((h-f*f/e)/e)}

Try it here!

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 107 104 99 bytes, stddev 25.25 \$\cdots\$25.32 25.00, score 2702.01 \$\cdots\$ 2634.27 2475.426270

Saved 3 bytes and 46.95288 points thanks to ceilingcat!!!
Saved 5 bytes and 158.848632 points thanks to att!!!

E;float D,G,H;float F(F,C)int*C;{E=F;for(H=G=0;E>-F;0>E?G+=D*D:(H+=*C++))D=H/F-C[--E];G=sqrt(G/F);}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ 2475.426 \$\endgroup\$
    – att
    Aug 26, 2020 at 20:42
  • \$\begingroup\$ @att Fantastic - thanks! :D \$\endgroup\$
    – Noodle9
    Aug 26, 2020 at 21:24
1
\$\begingroup\$

MATLAB/Octave, 12 bytes, score 336.32

(changed according to guidance by Giuseppe to conform with rules)

@(A)std(A,1)

Argument with name A provides the lowest deviation for score, output to standard output variable Ans and actually written to command window.
Try it online!

std is a built-in function. By default it uses \$N-1\$ as demoninator but by passing 1 as second argument it's changed to \$N\$.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ I believe you need a way of inputting the variable itself, so this needs to be a full program taking input through input or else as a function handle, e.g., @(H)std(H,1). Taking input as a predefined variable isn't really allowed any longer. \$\endgroup\$
    – Giuseppe
    Sep 25, 2020 at 14:59
  • \$\begingroup\$ @Giuseppe I would argue that MATLAB scripts just work in the way you can put some data into workspace before running the actual script. IMHO it's just another way of passing arguments, in rules it's said that input/output is flexible and I'm not pulling the answer from variables, only the inputs. But I'm new here and I might not know all the subtle rules, I'm sorry. I changed the answer, but I'd like to point out @(H)std(H,1) still doesn't technically allow inputting anything if you don't save it to a variable. \$\endgroup\$
    – elementiro
    Sep 25, 2020 at 18:14
  • 1
    \$\begingroup\$ No worries, I can see your rep and the "New contributor" tag on your profile, so I know the arcane rules of Code Golf are probably new to you. This is the relevant community consensus. Note that anonymous functions (i.e., function handles) are perfectly fine--see for instance this for a MATLAB example. \$\endgroup\$
    – Giuseppe
    Sep 25, 2020 at 20:11
  • 1
    \$\begingroup\$ If you have any doubts, feel free to go to the CGCC general chatroom as they can probably point you to any weird rules better than I can (I still don't know some of the rules, I'm sure). And if you're feeling up to it, as a fellow MATLAB/Octave golfer, MATL is a stack-based golfing language based on MATLAB that's pretty powerful and enjoyable to golf in. \$\endgroup\$
    – Giuseppe
    Sep 25, 2020 at 20:13

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.