# Waiting for PostgreSQL 16 – Invent random_normal() to provide normally-distributed random numbers.

On 9th of January 2023, Tom Lane committed patch:

```Invent random_normal() to provide normally-distributed random numbers.

There is already a version of this in contrib/tablefunc, but it
seems sufficiently widely useful to justify having it in core.

Paul Ramsey

Discussion: https://postgr.es/m/CACowWR0DqHAvOKUCNxTrASFkWsDLqKMd6WiXvVvaWg4pV1BMnQ@mail.gmail.com```

Description tells is all, but let's see how that works.

Let's generate som random_normal() values, which can be done using:

```=\$ SELECT random_normal() AS v FROM generate_series(1,10);
v
----------------------
2.0769129968970774
0.4215059076426097
1.085988642195048
-0.5816049253906204
0.8020449529886824
-0.28712441889530904
0.3608747983496689
1.9320722370416128
1.4822705736995292
-1.8661221359997575
(10 ROWS)```

and let's see the distribution of values. Let's say that we want to group them in ranges of 0.1, for example like this:

```=\$ SELECT round(random_normal()::NUMERIC, 1) AS v FROM generate_series(1,10)
v
------
-2.2
0.2
-0.4
-1.3
0.3
-2.5
-0.5
1.4
0.3
0.0
(10 ROWS)```

and now let's make lots of them, group by the rounded value, get count, and perhaps use this to generate “a graph":

```=\$ SELECT
round(
random_normal()::pg_catalog.numeric,
1
) AS v,
COUNT(*),
repeat('#', (COUNT(*) / 100)::int4)
FROM
generate_series( 1, 100000 )
GROUP BY
1
ORDER BY
1;
v   | COUNT |                  repeat
------+-------+------------------------------------------
-4.6 |     1 |
-4.0 |     1 |
-3.9 |     6 |
-3.7 |     5 |
-3.6 |     5 |
-3.5 |     9 |
-3.4 |    12 |
-3.3 |     9 |
-3.2 |    23 |
-3.1 |    36 |
-3.0 |    50 |
-2.9 |    49 |
-2.8 |    90 |
-2.7 |   125 | #
-2.6 |   115 | #
-2.5 |   181 | #
-2.4 |   217 | ##
-2.3 |   286 | ##
-2.2 |   360 | ###
-2.1 |   436 | ####
-2.0 |   521 | #####
-1.9 |   682 | ######
-1.8 |   777 | #######
-1.7 |   963 | #########
-1.6 |  1085 | ##########
-1.5 |  1317 | #############
-1.4 |  1531 | ###############
-1.3 |  1718 | #################
-1.2 |  1982 | ###################
-1.1 |  2137 | #####################
-1.0 |  2425 | ########################
-0.9 |  2652 | ##########################
-0.8 |  2949 | #############################
-0.7 |  3090 | ##############################
-0.6 |  3395 | #################################
-0.5 |  3529 | ###################################
-0.4 |  3759 | #####################################
-0.3 |  3827 | ######################################
-0.2 |  3916 | #######################################
-0.1 |  3898 | ######################################
0.0 |  3952 | #######################################
0.1 |  4017 | ########################################
0.2 |  3924 | #######################################
0.3 |  3822 | ######################################
0.4 |  3656 | ####################################
0.5 |  3601 | ####################################
0.6 |  3391 | #################################
0.7 |  3223 | ################################
0.8 |  2891 | ############################
0.9 |  2688 | ##########################
1.0 |  2317 | #######################
1.1 |  2195 | #####################
1.2 |  1897 | ##################
1.3 |  1685 | ################
1.4 |  1389 | #############
1.5 |  1272 | ############
1.6 |  1054 | ##########
1.7 |   932 | #########
1.8 |   750 | #######
1.9 |   619 | ######
2.0 |   538 | #####
2.1 |   386 | ###
2.2 |   375 | ###
2.3 |   285 | ##
2.4 |   250 | ##
2.5 |   183 | #
2.6 |   140 | #
2.7 |    94 |
2.8 |    78 |
2.9 |    57 |
3.0 |    48 |
3.1 |    35 |
3.2 |    19 |
3.3 |    22 |
3.4 |    11 |
3.5 |    12 |
3.6 |     8 |
3.7 |     5 |
3.8 |     4 |
3.9 |     3 |
4.0 |     2 |
4.2 |     1 |
(82 ROWS)```

We can, of course, use the params to move result set a bit, or make it wider/narrower:

```=\$ SELECT
round(
random_normal(10, 0.3)::pg_catalog.numeric,
1
) AS v,
COUNT(*),
repeat('#', (COUNT(*) / 100)::int4)
FROM
generate_series( 1, 100000 )
GROUP BY
1
ORDER BY
1;
v   | COUNT |                                                                repeat
------+-------+---------------------------------------------------------------------------------------------------------------------------------------
8.6 |     1 |
8.7 |     3 |
8.8 |     5 |
8.9 |    16 |
9.0 |    44 |
9.1 |   152 | #
9.2 |   353 | ###
9.3 |   895 | ########
9.4 |  1818 | ##################
9.5 |  3305 | #################################
9.6 |  5397 | #####################################################
9.7 |  8177 | #################################################################################
9.8 | 10542 | #########################################################################################################
9.9 | 12642 | ##############################################################################################################################
10.0 | 13300 | #####################################################################################################################################
10.1 | 12559 | #############################################################################################################################
10.2 | 10542 | #########################################################################################################
10.3 |  8051 | ################################################################################
10.4 |  5464 | ######################################################
10.5 |  3388 | #################################
10.6 |  1861 | ##################
10.7 |   824 | ########
10.8 |   392 | ###
10.9 |   191 | #
11.0 |    49 |
11.1 |    19 |
11.2 |     7 |
11.3 |     3 |
(28 ROWS)```

Looks pretty awesome. It will definitely help with building some test datasets. Thanks to all involved.

This site uses Akismet to reduce spam. Learn how your comment data is processed.