Created
February 21, 2013 04:52
-
-
Save ryanjsfx/5002193 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BigNumber(object): | |
"""BigNumber stores nonnegative integers. | |
BigNumber takes a string, of ints and only ints, creates an integer | |
(not long) representation of that many charactered string of ints. | |
Any negative int (in form of string) input will be made into the | |
absolute value (positive) integer equivalent of that input. | |
""" | |
def __init__(self,string_literal): | |
"""Inits BigNumber | |
Takes the string input and stores each character | |
in its own (always) unique variable. | |
Args: | |
string_literal: A string representation of | |
a large int. It is the input for init | |
BigNumber that is taken and made into a | |
corresponding, representative, integer. | |
Is type string. | |
Returns: | |
None | |
Raises: | |
KeyError: for when the global "i" is referenced | |
before assignment the first time a BigNumber | |
is created. | |
ValueError: if a string not of underlying type | |
int. | |
""" | |
if string_literal[0] == "-": | |
pop(string_literal[0]) | |
# Removes the negative sign, if there, from the string # comment to left refers up | |
# representation of the int. | |
# Sets up a dummy counting variable i which is concatenated | |
# to the end of the counter variable "counter" so that the | |
# correct counter (and corresponding sequence of digits) | |
# can later be accessed in reference to which number created # comment to left refers down | |
# instance of BigNumber is such (that is, the first BigNumber | |
# instance, as first, has i = 0, which corresponds to | |
# counter0 = 1 which corresponds to (up to) 80,000 unique digit | |
# values available). | |
try: | |
globals()["i"] = globals()["i"] + 1 | |
globals()["counter" + str(globals()["i"])] = globals()["counter" + str(globals()["i"] - 1)] + 80000 | |
except KeyError as error: | |
globals()["i"] = 0 | |
globals()["counter" + str(globals()["i"])] = 1 | |
# Constructs a unique "max_digit" variable for each BigNumber | |
# instance created. Each max_digit variable has the value of # comment to left refers down | |
# the length of total digits in that BigNumber (needed for | |
# knowing how long to loop for). | |
globals()["max_digit" + "_" + str(globals()["counter" + str(globals()["i"])])] = len(string_literal) | |
print globals()["max_digit" + "_" + str(globals()["counter" + str(globals()["i"])])] | |
# Catches if a non-int string representation is given as input; | |
# otherwise, gives a unique (up to 80,000) variable name for each # refers below | |
# digit in the BigNumber | |
for x in xrange(0,globals()["max_digit" + "_" + str(globals()["counter" + str(globals()["i"])])] + 1): | |
try: | |
globals()["digits" + str(x) + "_" + str(globals()["counter" + str(globals()["i"])])] = int(string_literal[x-1]) | |
except ValueError as error: | |
print "BigNumber does not accept any type of string besides int." | |
def print_number(self): | |
"""Prints a string that is the BigNumber representation of a large | |
ingeger. | |
Args: | |
None except for self. | |
Returns: | |
self.re_string_literal: The re-formed string representation of | |
the big int that was originally input to init BigNumber and is | |
now returned after its necessary information has been taken. | |
Returns type string | |
""" | |
self.re_string_literal = "" | |
for x in xrange (1, globals()["max_digit" + "_" + str(globals()["counter" + str(globals()["i"])])] + 1): | |
self.re_string_literal = self.re_string_literal + str(globals()["digits" + str(x) + "_" + str(globals()["counter" + str(globals()["i"])])]) | |
return self.re_string_literal | |
def add_da_numbers(self, number_created_add1, number_created_add2): | |
"""Arithmetically adds two BigNumber instances. | |
Args: | |
self | |
number_created_add1: Refers to when the particular instance | |
of the BigNumber class was created (first = 0, second = 1...). | |
Necessary for selecting the correct maxDigits and stored digits | |
for that number that is to be added. Type int. | |
number_created_add2: See number_created_add1. | |
Returns: | |
Returns the addition of the two instances of the BigNumber | |
class as a string representative of the corresponding int. | |
Type string. | |
""" | |
if globals()["max_digit" + "_" + str(globals()["counter" + str(number_created_add1)])] > globals()["max_digit" + "_" + str(globals()["counter" + str(number_created_add2)])]: | |
ranger = globals()["max_digit" + "_" + str(globals()["counter" + str(number_created_add1)])] | |
else: | |
ranger = globals()["max_digit" + "_" + str(globals()["counter" + str(number_created_add2)])] | |
carryEr = 0 | |
# adds the two numbers together, digit by digit. (refers below, not above) | |
for x in xrange(ranger, 0, -1): | |
globals()["summed_digit" + str(x)] = globals()["digits" + str(x) + "_" + str(globals()["counter" + str(number_created_add1)])] + globals()["digits" + str(x) + "_" + str(globals()["counter" + str(number_created_add2)])] + carryEr | |
carryEr = 0 | |
if globals()["summed_digit" + str(x)] == 10: | |
carryEr = 1 | |
globals()["summed_digit" + str(x)] = 0 | |
elif globals()["summed_digit" + str(x)] > 10 and globals()["summed_digit" + str(x)] < 20: | |
carryEr = 1 | |
globals()["summed_digit" + str(x)] = int(globals()["summed_digit" + str(x)]) - 10 | |
re_string_literal_summed = "" | |
for x in xrange (1, ranger + 1): | |
re_string_literal_summed = re_string_literal_summed + str(globals()["summed_digit" + str(x)]) | |
return re_string_literal_summed | |
def shift_left(self, number_created): | |
"""Arithmetically shifts the BigNumber instance to the left one digit. | |
Args: | |
number_created: Refers to when the particular instance | |
of the BigNumber class was created (first = 0, second = 1...). | |
Necessary for selecting the correct maxDigits and stored digits | |
for that number that is to be left shifted. Type int. | |
Returns: | |
Adds a digit (0) to the end of the BigNumber and returns | |
that larger BigNumber as a string representative of the | |
corresponding int. Type string. | |
""" | |
ranger = globals()["max_digit" + "_" + str(globals()["counter" + str(number_created)])] | |
globals()["digits" + str(ranger+1) + "_" + str(globals()["counter" + str(number_created)])] = 0 | |
self.re_string_literal = self.re_string_literal + str(globals()["digits" + str(ranger+1) + "_" + str(globals()["counter" + str(number_created)])]) | |
return self.re_string_literal | |
def shift_right(self, number_created): | |
"""Arithmetically shifts right the BigNumber instance by one digit. | |
Reduces the appropriate maxDigit by 1 so that the ones place is | |
shifted one to the right. | |
Args: | |
number_created: Refers to when the particular instance | |
of the BigNumber class was created (first = 0, second = 1...). | |
Necessary for selecting the correct maxDigits and stored digits | |
for that number that is to be right shifted. Type int. | |
Returns: | |
One less digit (old ones digit not printed) is returned as a | |
string representation of the corresponding integer. Tyep string. | |
""" | |
ranger = globals()["max_digit" + "_" + str(globals()["counter" + str(number_created)])] | |
ranger -= 1 | |
self.re_string_literal = "" | |
for x in xrange (1, ranger + 1): | |
self.re_string_literal = self.re_string_literal + str(globals()["digits" + str(x) + "_" + str(globals()["counter" + str(number_created)])]) | |
return self.re_string_literal | |
def main(): | |
first_test=BigNumber("38921689416894156419816111145611984156") | |
print "\nHello first Big Number: ", first_test.print_number() | |
second_test = BigNumber("43634634634734732110000151449946100111") | |
print "\nHello second Big Number: ", second_test.print_number() | |
third_test = first_test.add_da_numbers(0,1) | |
print "\nHello sum of first and second Big Numbers: ", third_test | |
fourth_test = first_test.shift_left(0) | |
print "\n One shift left: ", fourth_test | |
fifth_test = second_test.shift_right(1) | |
print "\n One shift right: ", fifth_test | |
main() | |
# Exploration Questions: | |
"""1. In storing the integer data, there are advantages and disadvantages to | |
how you divide the contents of the BigNumber into manageable parts | |
(i.e., 109). Using your coding decisions as context, explain why you | |
chose your approach to implement BigNumber. Contrast it with another approach | |
that you did not implement.""" | |
# I chose to break up the initial string literal of the BigNumber into one | |
# variable per digit. I made this decision to make the addition simple; all | |
# I had to do was add the corresponding digits of the two BigNumbers, which | |
# is also how I add (I think) manually. This method also made it simple to | |
# perform right and left shifts. | |
# I chose this method of storing the values of BigNumber instead of storing, | |
# say, the eight digits at a time as separate variables because it was | |
# easier for me to see a way of implementing my method into code and | |
# because it seemed to me nicer to have access to each digit. | |
"""2. Of addition, subtraction, multiplication, and division, you were | |
instructed to implement only addition. What considerations are required | |
in the implementation of the other three operations? Does your existing | |
design allow for implementing those operations easily? Why or why not?""" | |
# As addition requires the consideration of carrying the tens digit, | |
# subtraction requires the consideration of 'borrowing'. I think I | |
# would be able to code 'borrowing' into my code without too much | |
# difficulty and this would be the only addition to my code | |
# necessary because my code stores each digit as a value and could | |
# therefore just follow manual subtraction: check if the numbers | |
# that would be subtracted would yield a negative value. If so then | |
# add ten to the top number and subtract again (giving a positive | |
# number) and activate a subtractor variable that would take off 1 | |
# from the next digit unless that digit is 0. If the next digit is | |
# 0, it is likely that that digit will also need to borrow, so | |
# increment the subtractor to 2 and go through with the subtraction | |
# digit by digit. | |
# Multiplication would be a bit more difficult, but still fairly | |
# simple to implement; all I would have to do is use the same | |
# addition code, changing the plus to multiplies and take more | |
# scenarios into account: carry variable can take values up to 8 | |
# and an additional for loop would be necessary to multiply the | |
# lower number digit by each digit of the upper number. But still, | |
# I think my code is set up in such a way that it would not be | |
# too difficult to set up that code. | |
# For division, my code could very easily solve for orders of | |
# magnitude by comparing the max digit values of each BigNumber. | |
# For more precise division, it would have to check what multplies | |
# the leading n numbers that the number being divided into would | |
# supply and then check which would be the greatest multiple not | |
# exceeding the value of the number doing the dividing. In other | |
# words, division would be fairly tough to implement. It took me | |
# quite a bit to think of how division would be done with any | |
# implementation (assuming only up to 9 digits could be stored per | |
# variable and the numbers being divided would be many more than | |
# 9 digits). However, I do believe that I could implement division | |
# with my code, though it would probably be fairly inefficient | |
# because it would have to cross check every number in the BigNumbers. | |
# Divying up the digits by 8 into variables would increase the | |
# efficiency 8 times over mine, so mine is not the best implementation | |
# for division, but I believe it could still be done. | |
"""3. Make a claim about the largest BigNumber you think you can store. Justify your claim (i.e., | |
create a BigNumber object for that number).""" | |
# I think I can make a number as big as my computer can make... let's | |
# try a google. | |
## This is where I had the code for the call that made a BigNumber (using | |
## my above code) that I got up to 260,000 digits. | |
# (I'm not displaying the actual calls that I did because they were slowing my | |
# computer down and it took up a lot of space. | |
# (The below block of code was performed yesterday and therefore has today's | |
# revisions written in a bit.) | |
# Well, my code was able to print a number as large as my computer would let it | |
# (though not a google sadly). Up to 10,000 digits it only took my computer | |
# a few seconds to create and print the BigNumber (it started slowing down a bit | |
# at 40,000 but up to 100,000 was the same as 40,000 (about)), it took about 5 minutes to print 70,000 digits, and the above | |
# call's formatting (when it was displayed it was above) went to hell when | |
# I tried (not to run the code) but simply to copy and paste another 10,000 digits | |
# to up the antie to 80,000 (my computer is definitely at its limit; it is | |
# taking a whole second or so just to display the text that I'm typing now). | |
# Also, I just found out that the reason why it went to hell (I tried running it now) | |
# is because it says IndexError: string index out of range. So, it would seem | |
# that just as there is a max int that python can store, there is a max string | |
# (who's value is somewhere between 70,000 and 80,0000 characters). | |
# It would seem that the max characters allowed in a string varies by day, | |
# today it is 262,000. My computer is doing better today and printed that | |
# BigNumber in less than a minute. Also, the Wing editor can display 128 '2's | |
# per line. | |
"""4. The underlying long representations do exist in Python. In only this case, create large long | |
values and perform arithmetic operations with them. Compare and contrast your addition | |
implementation with that of adding the same integers (e.g., compare timings of both operations). | |
Explain your findings.""" | |
# I am currently trying to make BigNumbers to use for the comparison that are | |
# not too large that I cannot display them below but are large enough that | |
# the two methods don't both give a time difference of "0.0" | |
# Well, it's not much, but I don't want to be displaying too big BigNumbers. | |
# Result: 366 digit BigNumbers added my way take 0.01 (about) seconds, whereas | |
# longs addition is still "0.0" | |
to_add1 = BigNumber("847483932028284374748349302029384747565464783392901902923938384748393202828437474834930202938474756546478339290190292393838474839320282843747483493020293847475654647833929019029239383847483932028284374748349302029384747565464783392901902923938384748393202828437474834930202938474756546478339290190292393838474839320282843747483493020293847475654647833929019029239383") | |
to_add2 = BigNumber("999999999922222222222777777777744444444440000000000111111111199999999992222222222277777777774444444444000000000011111111119999999999222222222227777777777444444444400000000001111111111999999999922222222222777777777744444444440000000000111111111199999999992222222222277777777774444444444000000000011111111119999999999222222222227777777777444444444400000000001111111111") | |
import time | |
start = time.time() | |
to_add1.add_da_numbers(2,3) | |
stop = time.time() | |
print ("my way: ", stop - start) | |
long1 = 847483932028284374748349302029384747565464783392901902923938384748393202828437474834930202938474756546478339290190292393838474839320282843747483493020293847475654647833929019029239383847483932028284374748349302029384747565464783392901902923938384748393202828437474834930202938474756546478339290190292393838474839320282843747483493020293847475654647833929019029239383 | |
long2 = 999999999922222222222777777777744444444440000000000111111111199999999992222222222277777777774444444444000000000011111111119999999999222222222227777777777444444444400000000001111111111999999999922222222222777777777744444444440000000000111111111199999999992222222222277777777774444444444000000000011111111119999999999222222222227777777777444444444400000000001111111111 | |
start = time.time() | |
long1 + long2 | |
stop = time.time() | |
print "longs: ", stop-start | |
# (I did the below but am not including it now because it took up many lines.) | |
# Instead, the above are more manageable BigNumber(s). | |
# Adding 262,000 digit numbers my way, at least according to 'timeit' took | |
# 2.8610000610351562 (seconds I'm assuming, it doesn't say...). It said | |
# that longs took 0.0 seconds. Second time run, my way took 2.53 (about) seconds(?) | |
# and longs took 0.00999990 seconds(?) | |
# It would seem that I have found that my code's addition vs. long addition, | |
# at least up until about 300 digits, is about the same quickness. At 366 digits, | |
# my code starts taking a bit longer to add than longs and at the biggest I got, | |
# 262,000 digits, my code took signficantly longer (2.86 seconds my way (or possibly | |
# minutes, it didn't specify) versus 0.00999990 seconds (probably, though also | |
# possibly minutes). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment