{"id":9384,"date":"2025-03-14T03:14:00","date_gmt":"2025-03-14T07:14:00","guid":{"rendered":"https:\/\/www.both.org\/?p=9384"},"modified":"2025-01-27T19:57:46","modified_gmt":"2025-01-28T00:57:46","slug":"calculate-pi-by-counting-pixels","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=9384","title":{"rendered":"Calculate pi by counting pixels"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"9384\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">1    <\/span>\r\n<\/div><\/div>\n<p>To celebrate Pi Day (3\/14) this year, I thought it would be fun to calculate pi using a nonstandard method. For this method, I used DOS graphics mode to draw a circle, then <em>counted the pixels<\/em> to measure the circle. This is a very simple way to measure pi, but it was a fun exercise and I wanted to share it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"dos-graphics\">DOS graphics<\/h2>\n\n\n\n<p>For this exercise, I wrote my sample programs in FreeDOS using the Open Watcom compiler. I used the standard 640&#215;480 graphics mode, which you may recognize as the classic \u201cVGA\u201d graphics mode from the IBM PC era.<\/p>\n\n\n\n<p>Programming graphics in DOS is fairly simple. With DOS graphics, you don\u2019t have to set up windowing or make a specialized call to a game library just to draw to the screen. Simply use the <code>_setvideomode<\/code> function to set up the display with a specific video mode, and then you\u2019re ready to start drawing to the screen.<\/p>\n\n\n\n<p>Open Watcom provides several other functions in <code>graph.h<\/code> to support graphics elements. For example, the <code>_setcolor<\/code> function sets the color to draw in, using the iRGB color space: that\u2019s <em>intensity<\/em>, Red, Green, and Blue. The value 0001 (1) is low-intensity blue, 0010 (2) is low-intensity green, and 0111 (7) is low-intensity white.<\/p>\n\n\n\n<p>To draw a circle on the screen, use the <code>_ellipse<\/code> function, with an option to either fill in the ellipse (<code>_GFILLINTERIOR<\/code>) or draw just an outline (`_GBORDER). Graphics uses x,y screen coordinates, so define the ellipse as the upper-left and bottom-right \u201ccorners.\u201d To draw a circle, draw an ellipse with the same x and y dimensions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"counting-pixels\">Counting pixels<\/h2>\n\n\n\n<p>A core part of measuring a circle is <em>counting pixels<\/em>. For that, Open Watcom provides a <code>_getpixel<\/code> function to query the color at a specific x,y coordinate. This makes it easy to count pixels to measure a circle; draw the circle in white on a black background and <code>_getpixel<\/code> will return either 7 (white) or 0 (black).<\/p>\n\n\n\n<p>I wrote this function (<code>count.c<\/code>) to count the pixels in an area from x0,y0 to x1,y1:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;graph.h&gt;\n\nunsigned long count_pixels(short x0, short y0, short x1, short y1)\n{\n    unsigned long count = 0;\n    short x, y;\n\n    for (x = x0; x &lt;= x1; x++) {\n        for (y = y0; y &lt;= y1; y++) {\n            \/* count pixels .. change colors as we go, so we can see\n               the counting process *\/\n\n            if (_getpixel(x, y)) {\n                _setcolor(14);         \/* br yellow *\/\n                count++;\n            }\n            else {\n                _setcolor(1);          \/* blue *\/\n            }\n\n            _setpixel(x, y);\n        }\n    }\n\n    return count;\n}<\/code><\/pre>\n\n\n\n<p>The function loops through every x,y coordinate in the specified area, and examines each pixel. If the pixel has <em>any<\/em> color, the function increments a counter and turns that pixel bright yellow. If the pixel was originally black, the function simply turns the x,y coordinate into a blue pixel. This allows me to watch the function as it counts pixels.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"measure-the-circumference\">Measure the circumference<\/h2>\n\n\n\n<p>My first attempt drew the <em>outline<\/em> of a circle to the screen, and counted the pixels for the circumference. This is a very naive way to estimate the circumference using pixels, and gives a completely wrong result.<\/p>\n\n\n\n<p>But let\u2019s see it anyway! The formula for the circumference <em>C<\/em> of a circle is <em>2 \u03c0 r<\/em>, where <em>r<\/em> is the radius. The diameter <em>d<\/em> is <em>2r<\/em>, so really the circumference is <em>C = \u03c0 d<\/em>. With a little algebra, we can calculate \u03c0 as <em>C\/d<\/em>.<\/p>\n\n\n\n<p>The program defines a few values for the mode and diameter; this allowed me to update the program more easily if I wanted to instead use a higher graphics mode like 1024&#215;768. After that, the program uses <code>_setvideomode<\/code> to put the display into graphics mode at 640&#215;480 resolution, then uses <code>_ellipse<\/code> to draw a circle from 0,0 to 479,479, then counts the pixels with my other function.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;graph.h&gt;\n\nextern unsigned long count_pixels(short x0, short y0, short x1, short y1);\n\n#define MODE _VRES16COLOR\n#define DIAM 480\n\nint main()\n{\n    unsigned long circ;\n\n    if (_setvideomode(MODE) == 0) {    \/* 640x480 *\/\n        puts(\"cannot set video mode\");\n        return 1;\n    }\n\n    \/* calculate pi by circumference (will get the wrong value) *\/\n    \/* C = 2 pi r .. or C = pi d ... or pi = C \/ d *\/\n\n    _setcolor(7);                      \/* white *\/\n    _ellipse(_GBORDER, 0, 0, DIAM - 1, DIAM - 1);\n\n    circ = count_pixels(0, 0, DIAM - 1, DIAM - 1);\n\n    \/* done *\/\n\n    _setvideomode(_DEFAULTMODE);\n\n    printf(\"pi = C \/ d = %f\\n\", ((float) circ) \/ ((float) DIAM));\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Save this file as <code>circ.c<\/code> and combine it with the <code>count.c<\/code> function to create a DOS program:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; wcl circ.c count.c<\/code><\/pre>\n\n\n\n<p>Run the <code>circ.exe<\/code> program to calculate pi from the circumference of a circle:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"480\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2025\/01\/circ2.png\" alt=\"\" class=\"wp-image-9385\"\/><figcaption class=\"wp-element-caption\">Counting the pixels in the circumference<\/figcaption><\/figure>\n\n\n\n<p>Unfortunately, this calculates pi at 2.825. And because of the naive method to count pixels to \u201cmeasure\u201d the circumference, this is about as good as it gets. The reason is because pixels are <em>square<\/em> and estimating the circumference of a circle using square pixels will always be off.<\/p>\n\n\n\n<p>I\u2019ll save you the math, but look at the simple case: if you tried to measure the circumference of a circle of diameter <em>d<\/em> by drawing a square around it, you\u2019d have a square with sides of length <em>d<\/em>, and a perimeter that\u2019s four times that, or <em>4d<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"395\" height=\"395\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2025\/01\/circ-sq.png\" alt=\"\" class=\"wp-image-9386\"\/><figcaption class=\"wp-element-caption\">Measuring a circle with a square<\/figcaption><\/figure>\n\n\n\n<p>Calculating \u201cpi\u201d with this circumference is <em>C\/d<\/em>, or 4.<\/p>\n\n\n\n<p>You can break down the \u201csquare\u201d into a series of straight-line \u201csteps,\u201d shown above. But this doesn\u2019t really improve the measurement, because the perimeter is the sum of each of the \u201clines\u201d in the \u201csteps.\u201d Counting with pixels is just a simplification of that.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"measure-the-area\">Measure the area<\/h2>\n\n\n\n<p>A better way to calculate pi by counting pixels is to fill the circle, and count the pixels to estimate the area. The formula for the area <em>A<\/em> of a circle of radius <em>r<\/em> is <em>\u03c0 r\u00b2<\/em>. Doing a little algebra reveals the calculation for \u03c0 as <em>A\/r\u00b2<\/em>.<\/p>\n\n\n\n<p>The program to calculate pi from the area is a minor update to the previous program. Instead of using <code>_GBORDER<\/code> to draw an outline, use <code>_GFILLINTERIOR<\/code> to fill the area. Counting pixels gives an estimate of the area. The final calculation divides the area by the square of the radius:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;stdio.h&gt;\n#include &lt;graph.h&gt;\n\n#define MODE _VRES16COLOR\n#define DIAM 480\n\nextern unsigned long count_pixels(short x0, short y0, short x1, short y1);\n\nint main()\n{\n    unsigned long area;\n    float r = DIAM \/ 2.0;\n\n    if (_setvideomode(MODE) == 0) {    \/* 640x480 *\/\n        puts(\"cannot set video mode\");\n        return 1;\n    }\n\n    \/* calculate pi by area (not perfect, but closer) *\/\n    \/* A = pi r^2 .. or pi = A \/ r^2 *\/\n\n    _setcolor(7);                      \/* white *\/\n    _ellipse(_GFILLINTERIOR, 0, 0, DIAM - 1, DIAM - 1);\n\n    area = count_pixels(0, 0, DIAM - 1, DIAM - 1);\n\n    \/* done *\/\n\n    _setvideomode(_DEFAULTMODE);\n\n    printf(\"pi = A \/ r^2 = %f\\n\", ((float) area) \/ r \/ r);\n\n    return 0;\n}<\/code><\/pre>\n\n\n\n<p>Save this file as <code>area.c<\/code> and combine it with the <code>count.c<\/code> function to create a new DOS program:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&gt; wcl area.c count.c<\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"480\" src=\"https:\/\/www.both.org\/wp-content\/uploads\/2025\/01\/area3.png\" alt=\"\" class=\"wp-image-9387\"\/><figcaption class=\"wp-element-caption\">Counting the pixels in the area<\/figcaption><\/figure>\n\n\n\n<p>Since we\u2019re using pixels to \u201cmeasure\u201d the area of the circle, the final calculation of pi will be off, but not by much: 3.1444.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a very simple way to measure pi, but it was a fun exercise and I wanted to share it.<\/p>\n","protected":false},"author":33,"featured_media":9387,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[340,69,150],"tags":[267,147,210,152],"class_list":["post-9384","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-freedos","category-fun","category-programming","tag-freedos","tag-fun","tag-pi-day","tag-programming"],"modified_by":"Jim Hall","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9384","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/33"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9384"}],"version-history":[{"count":3,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9384\/revisions"}],"predecessor-version":[{"id":9571,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9384\/revisions\/9571"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/9387"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9384"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9384"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9384"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}