Compute pi to base 12 using Python?

mensanator at aol.com mensanator at aol.com
Wed Apr 13 18:16:55 EDT 2005


Dan Bishop wrote:
> Dick Moores wrote:
> > I need to figure out how to compute pi to base 12, to as many
digits
> as
> > possible. I found this reference,
> <http://mathworld.wolfram.com/Base.html>,
> > but I really don't understand it well enough.
>
> How many stars are in "*************************"?
>
> You probably answered "25".  This means that, for convenience, you've
> broken down the row of stars into ********** + ********** + *****,
that
> is, 2 tens with 5 left over, which the base-10 numeral system denotes
> as "25".
>
> But there's no reason other than tradition why you should arrange
them
> into groups of 10.  For example, you could write it as ******** +
> ******** + ******** + *, or 3 eights plus 1.  In octal (base-8)
> notation, this is written as "31"; the "tens" place in octal
represents
> eights.
>
> In general, in the base-r numeral system, the nth digit to the left
of
> the ones digit represents r^n.  For example, in the binary number
> 11001, the place values for each digit are, right to left, 1, 2, 4,
8,
> and 16, so the number as a whole represents
> 1×16+1×8+0×4+0×2+1×1=16+8+1=25.  This analogous to 25=2×10+5 in
> base-10.
>
> It's also possible to write it as 3×8+0×4+0×2+1×1 = 3001 base 2,
> but by convention, base-r only uses the digits in range(r).  This
> ensures a unique represenation for each number.  This makes "11001"
the
> unique binary representation for decimal 25.
>
> Note that for bases larger than 10, the digits will be numbers that
are
> not single digits in base 10.  By convention, letters are used for
> larger digits: A=10, B=11, C=12, ... Z=35.  For example, the number
> (dec) 2005 = 1×12³+1×12²+11×12+1×1 is represented in base-12 by
> "11B1".
>
> Fractions are handled in a similar manner.  The nth place to the
right
> of the radix point (i.e., the "decimal point", but that term is
> inaccurate for bases other than ten) represents the value
radix**(-n).
>
> For example, in binary,
> 0.1 = 1/2 = dec. 0.5
> 0.01 = 1/4 = dec. 0.25
> 0.11 = 1/2 + 1/4 = 3/4 = dec. 0.75
> 0.001 = 1/8 = dec. 0.125
> 0.01010101... = 1/4 + 1/16 + 1/64 + ... = 1/3
> 0.0001100110011... = 1/10 = dec. 0.1
>
> The last row explains why Python gives:
>
> >>> 0.1
> 0.10000000000000001
>
> Most computers store floating-point numbers in binary, which doesn't
> have a finite representation for one-tenth.  The above result is
> rounded to 53 signficant bits
> (1.100110011001100110011001100110011001100110011010×2^-4), which is
> exactly equivalent to decimal
> 0.1000000000000000055511151231257827021181583404541015625, but gets
> rounded to 17 significant digits for display.
>
> Similarly, in base-12:
>
> 0.1 = 1/12
> 0.14 = 1/12 + 4/144 = 1/9
> 0.16 = 1/12 + 6/144 = 1/8
> 0.2 = 2/12 = 1/6
> 0.3 = 3/12 = 1/4
> 0.4 = 4/12 = 1/3
> 0.6 = 6/12 = 1/2
> 0.8 = 8/12 = 2/3
> 0.9 = 9/12 = 3/4
> 0.A = 10/12 = 5/6
>
> Notice that several common fractions have simpler representations in
> base-12 than in base-10.  For this reason, there are people who
believe
> that base-12 is superior to base-10.
> (http://www.dozenalsociety.org.uk)
>
> > Could someone show me how to do what I need?
>
> You'll need 3 things:
>
> (1) An algorithm for computing approximations of pi.
>
> The simplest one is 4*(1-1/3+1/5-1/7+1/9-1/11+...), which is based on
> the Taylor series expansion of 4*arctan(1).
>
> There are other, faster ways.  Search Google for them.

That one's way too slow. I found the one I use below on Mathworld.

>
> (2) An unlimited-precision numeric representation.  The standard
> "float" isn't good enough: It has only 53 bits of precision, which is
> only enough for 14 base-12 digits.
>
> The "decimal" module will probably work, although of course its
base-10
> internal representation will introduce slight inaccuracies.

I'm using GMPY (see code).

>
> (3) A function for converting numbers to their base-12
representation.

GMPY can do this also.

>
> For integers, this can be done with:
>
> DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
> def itoa(num, radix=10):
>    is_negative = False
>    if num < 0:
>       is_negative = True
>       num = -num
>    digits = []
>    while num >= radix:
>       num, last_digit = divmod(num, radix)
>       digits.append(DIGITS[last_digit])
>    digits.append(DIGITS[num])
>    if is_negative:
>       digits.append("-")
>    digits.reverse()
>    return ''.join(digits)
>
> For a floating-point number x, the representation with d "decimal"
> places count be found by taking the representation of int(round(x *
> radix ** d)) and inserting a "." d places from the right.


# better pi/2 = 1 + 1/3 + (1*2)/(3*5) + (1*2*3)/(3*5*7) + ...

import gmpy
# unlimited precision math library

def pialso(n,b):
# input number of digits (n) in requested base (b)
        p = gmpy.mpq(1,1)
        # gmpy rationals are unlimited precision
        sn = 1
        sd = 3
        c = gmpy.mpq(sn,sd)
        # create the next term to be summed
        num = gmpy.mpf(p.numer())
        # seperately convert the numerator
        den = gmpy.mpf(p.denom())
        # and denominator to gmpy floats
        f = (num/den) * 2
        # to get unlimited precision float
        olds = gmpy.fdigits(f,b,n,0,1,2)
        # extract the requested digits and do base conversion
        done = 0
        while done==0:
                p = p + c
                # sum next term of pi equation
                sn += 1
                # set numerator
                sd += 2
                # and demoniator
                c = c * gmpy.mpq(sn,sd)
                # to create term for next iteration
                num = gmpy.mpf(p.numer())
                # meanwhile, convert this iteration
                den = gmpy.mpf(p.denom())
                f = (num/den) * 2
                # to an unlimited precision float
                s = gmpy.fdigits(f,b,n,0,1,2)
                if s[0]==olds[0]:
                # we're done when the number of digits
                        done = 1
                # we want stops changing
                else:
                # otherwise, keep iterating until we reach the
                        olds = s
                # the desired convergence
        print s[0],sn
        # prints the digits and how many iterations it took
        print

"""

The first 100 digits of pi in base 10.
>>> pialso(100,10)
3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067
327

The first 100 digits of pi in base 12.
>>> pialso(100,12)
3184809493b918664573a6211bb151551a05729290a7809a492742140a60a55256a0661a03753a3aa54805646880181a3682
353

Note it took more iterations (longer to converge) because base 12
digits are "bigger" than base 10.

"""




More information about the Python-list mailing list