Feed: MemSQL Blog.
Author: Nikita Shamgunov.
In celebration of Pi Day, I asked MemSQL’s Engineering team to come up with clever ways to compute pi in SQL. Because that’s the kind of thing we engineers enjoy! And, given pi’s privileged status in mathematical history – and my own history of earning a bachelor’s degree in Mathematics – I just couldn’t resist.
Truth be told, in the early days of MemSQL, my fellow math geeks and I had some fun with Pi Day – yes, including eating actual pies – and we even had a colleague with the nickname of Pieguy. Pie, not Pi, btw. So, if anyone was going to put together a blog post on calculating pi in honor of Pi Day, it would be me.
How else is MemSQL Pi/Pie-forward? Here are a few fun facts:
- All of our conference rooms in San Francisco are named after mathematicians and their accomplishments: (Thomas) Bayes, (Emmy) Noether, (Maryam) Mirzakhani, (Alan) Turing, and (John) Venn. (Oh, and the conference rooms in our Portugal engineering office are named for pastries. And, if you squint hard enough, pastel de nata – the name of a conference room – is a mini-pie!)
- All of our product releases are named after pies. We used to eat pie for major releases. For instance, for icecreampie, we ate ice cream pie. But we haven’t eaten any fictional pies like KeyUsingClusteredColumnstorePie (lol). We’re on Kalm at the moment, which stands for keypie a la mode. I dare you to top that!
That being said, we had fun putting this post together, and we hope you have a great #piday.
Let’s Use Stored Procedures
create database if not exists pi; use pi create table if not exists mc (d int, key() using clustered columnstore); create table if not exists tries(iter integer, pi float); delimiter // CREATE OR REPLACE PROCEDURE px(iter INTEGER) AS DECLARE q query(value FLOAT) = select 4*sum(d)/count(d) from mc; pi FLOAT; BEGIN delete from mc; delete from tries; insert into mc values (1-floor(pow(rand(),2)+pow(rand(),2))); FOR i IN 1 .. iter LOOP insert into mc (select (1-floor(pow(rand(),2)+pow(rand(),2))) from mc); pi = scalar(q); insert into tries values (i, pi); END LOOP; END // DELIMITER ; memsql> call px(20); Query OK, 0 rows affected (0.65 sec) memsql> select * from tries order by iter desc limit 10; +------+---------+ | iter | pi | +------+---------+ | 20 | 3.14454 | | 19 | 3.14319 | | 18 | 3.14456 | | 17 | 3.13928 | | 16 | 3.13794 | | 15 | 3.1488 | | 14 | 3.15527 | | 13 | 3.14941 | | 12 | 3.12695 | | 11 | 3.17773 | +------+---------+ 10 rows in set (0.01 sec)
Let’s Generate a Large(-ish) Dataset with Some Random Data
memsql> create table pi (x double, y double, d as 1-floor(x*x+y*y) persisted int); memsql> insert into pi (select rand(),rand()); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1391 | +-------------------+ 1 row in set (0.01 sec) memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); Query OK, 262144 rows affected (0.30 sec) Records: 262144 Duplicates: 0 Warnings: 0 memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1378 | +-------------------+ 1 row in set (0.02 sec) memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); Query OK, 524288 rows affected (0.54 sec) Records: 524288 Duplicates: 0 Warnings: 0 memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1372 | +-------------------+ 1 row in set (0.02 sec) memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); Query OK, 1048576 rows affected (1.18 sec) Records: 1048576 Duplicates: 0 Warnings: 0 memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1390 | +-------------------+ 1 row in set (0.05 sec) memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); Query OK, 2097152 rows affected (2.51 sec) Records: 2097152 Duplicates: 0 Warnings: 0 memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1404 | +-------------------+ 1 row in set (0.08 sec) memsql> insert into pi (select x, y from (select rand() as x, rand() as y, d from pi)); Query OK, 4194304 rows affected (5.46 sec) Records: 4194304 Duplicates: 0 Warnings: 0 memsql> select 4*sum(d)/count(d) from pi; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1411 | +-------------------+ 1 row in set (0.20 sec)
From there, the conversation digressed into the quality of our RAND() implementation and our engineers started to compare it with loading data from /dev/urandom with data generated by calling RAND()
memsql> load data infile '/tmp/random2.csv' into table rand fields terminated by ',' (@x,@y) set x = @x/65536, y = @y/65536; Query OK, 5000 rows affected (0.01 sec) memsql> select 4*sum(d)/count(d) from rand; +-------------------+ | 4*sum(d)/count(d) | +-------------------+ | 3.1640 | +-------------------+ 1 row in set (0.00 sec)
We Also Got an Alternative Solution
memsql> CREATE TABLE `pi` ( -> `i` bigint(11) PRIMARY KEY AUTO_INCREMENT -> ); memsql> insert into pi values (null); memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; memqsl> insert into pi select null from pi; — now pi has values from 1 to 64 memsql> SELECT -> CONCAT( -> LPAD("", ROUND((20 - (SQRT(POW(20, 2) - POW(20 - (i - 1), 2)) * 2) / 2) * 2), " "), -> "+", -> LPAD("", 80 - (2 * ROUND((20 - (SQRT(POW(20, 2) - POW(20 - (i - 1), 2)) * 2) / 2) * 2)), " "), -> -- LPAD("", ROUND(SQRT(POW(10, 2) - POW(10 - (i - 1), 2)) * 2 * 2), " "), -> "+" -> ) as c -> FROM pi order by i asc LIMIT 41; +------------------------------------------------------------------------------------+ | c | +------------------------------------------------------------------------------------+ | ++ | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | + + | | ++ | +------------------------------------------------------------------------------------+ 41 rows in set (0.113 sec)
This one outputs pie – the author says it is a pecan pie, but it’s hard to tell for sure.
This is all fun and good, but of course you can just do
memsql> select PI(); +-------------------+ | PI() | +-------------------+ | 3.141593 | +-------------------+ 1 row in set (0.00 sec)
Thank you all for reading! Now, time for some cherry pie.