HiveBrain v1.2.0
Get Started
← Back to all entries
snippetpythonMinor

Convert any number (up to 10^3000) to text

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
3000numberconverttextany

Problem

I kinda got the idea after playing Adventure Capitalist, since that goes up to 10300. I found a website that explained how to go up to 10^3000, so I mainly did this as a challenge to see if I could do it.

Also, I'm fairly new to writing the documentation bits, so feedback on what I did well/not so well would be appreciated. I'm not expecting people to read the entire thing since it ended up quite long, just general feedback would be good.

Basically, it works by initially building a list of every number suffix (like thousand and million) up to nongennovemnonagintillion. Then, when you run the code, it'll probably do similar stuff to conversion codes, with the exception of going a lot higher.

It'll split the number into separate parts matching the exponential values (like 1550 is 110^3 + 510^2 + 50*10^0, or {3:1, 2:5, 0:50}), then add the remainder on after the iterations finish. I initially had it calculate the remainder too, like 2 hundredths and 62 millions, but I realised nobody speaks like that so took it out aha.

Then with converting that to text, I made a separate function to print any number as text between 0-999. Getting it all working initially was really easy, and most of the code is just fixes for various cases when things didn't work quite right (and I'm still occasionally finding bits that don't work).

Some examples:

>>> LargeNumber('154024500.5').to_text(use_fractions=True)
'154 million, 24 thousand, 5 hundred and 1/2'

>>> LargeNumber('154024500.5').to_text(use_fractions=True, digits=False)
'one hundred and fifty-four million, twenty-four thousand and five hundred point five'

>>> LargeNumber(Decimal('1'+'0'*2000)+Decimal('523.275')).to_text(digits=False)
'one hundred sescenquinsexagintillion, five hundred and twenty-three'

>>> LargeNumber(123456789).to_text(max_iterations=0, num_decimals=2)
'123.46 million'


The script including the documentation is over the character limit so I put it here.

Edit: Before reading the reply from

Solution

Use syntax highlighting

Many nice modern IDEs have a feature called Syntax highlighting that will give nice colours to your code making it more readable and help you avoid shadowing built-in:

def remove_exponent(self, input):


should be:

def remove_exponent(self, input_):


to avoid deleting the native input function.

Be helpful

:) What a nice day to learn about this class:

>>> help(LargeNumber.__repr__)
Help on method __repr__ in module __main__:

__repr__(self) unbound __main__.LargeNumber method


:(

Instead if you change your code to be:

def __repr__(self):
    """
    Remove the exponent if a large int/float value is input
    Squared length seems to stop precision errors but increase if error happens
    """
    if 'E+' in str(self.input):
        original_precision = getcontext().prec
        getcontext().prec = len(str(self.input))**2
        formatted_input = self.remove_exponent(self.input)
        getcontext().prec = original_precision
    else:
        formatted_input = self.input

    return "LargeNumber('{}')".format(formatted_input)


The result is better:

>>> help(LargeNumber.__repr__)
Help on method __repr__ in module __main__:

__repr__(self) unbound __main__.LargeNumber method
    Remove the exponent if a large int/float value is input
    Squared length seems to stop precision errors but increase if error happens


:)

Must CalculateFraction be a class?

class CalculateFraction(object):

    @staticmethod
    def find(input, precision=100):
        #Convert to float
        if not isinstance(input, float):
            input = float(input)

        #Make sure it is between 0 and 1
        original_input = int(input)+1
        if not (0 < input < 1):
            input = input%1

        #Loop through all calculations until a match is found
        for j in xrange(2, precision+1):
            j = float(j)
            for i in xrange(1, int(j)):
                if i/j == input:
                    return i*original_input, int(j)

    @staticmethod
    def suffix(x, y):
        #Convert to str and get important characters
        y = str(y)
        x = str(x)
        last_num = y[-1]
        try:
            second_num = y[-2]
        except IndexError:
            second_num = 0

        #Define rules
        if y == '1':
            suffix = ''
        elif last_num == '3':
            suffix = 'rd'
        elif second_num == '1':
            suffix = 'th'
        elif last_num == '2':
            if second_num:
                suffix = 'nd'
            else:
                suffix = ''
        elif last_num == '4' and not second_num:
            suffix = ''
        elif last_num == '1':
            suffix = 'st'
        else:
            suffix = 'th'

        #Make plural if x is above 1
        if x not in ('1', '0') and suffix:
            suffix += 's'

        return suffix


When you write staticmethod you mean 'this should be free floating but I put it in a class just because it belongs there logically. But your class contains only 2 staticmethod functions, I would let those float around.

Noisy commenting

For example:

#Iterate through exponential hundreds (cen+)
for prefix_hundreds in num_exp_hundreds:
    #Iterate through exponential tens (decillion+)
    for prefix_tens in num_exp_tens:
        #Iterate through exponential amounts (un, duo, tre, etc)
        for prefix in num_exp_prefix:
            num_dict[exp_current] = prefix_hundreds+prefix+prefix_tens
            exp_current += 3


Almost 1/3 of the lines are comments, and you are telling the what, it is like:

# a is assigned to 10
a = 10


Many of your comments can be removed and the code will improve as they are just noise ad will get obsolete. (Docstrings are great because they give general information, keep them all)

Code Snippets

def remove_exponent(self, input):
def remove_exponent(self, input_):
>>> help(LargeNumber.__repr__)
Help on method __repr__ in module __main__:

__repr__(self) unbound __main__.LargeNumber method
def __repr__(self):
    """
    Remove the exponent if a large int/float value is input
    Squared length seems to stop precision errors but increase if error happens
    """
    if 'E+' in str(self.input):
        original_precision = getcontext().prec
        getcontext().prec = len(str(self.input))**2
        formatted_input = self.remove_exponent(self.input)
        getcontext().prec = original_precision
    else:
        formatted_input = self.input

    return "LargeNumber('{}')".format(formatted_input)
>>> help(LargeNumber.__repr__)
Help on method __repr__ in module __main__:

__repr__(self) unbound __main__.LargeNumber method
    Remove the exponent if a large int/float value is input
    Squared length seems to stop precision errors but increase if error happens

Context

StackExchange Code Review Q#91509, answer score: 4

Revisions (0)

No revisions yet.