Skip to content

Commit

Permalink
Merge pull request #6 from Aethese/dev
Browse files Browse the repository at this point in the history
Allow rounding negatives and past decimal changes
  • Loading branch information
Aethese authored May 3, 2022
2 parents 535c091 + 20cac8b commit c99b22b
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 14 deletions.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
My ***fast*** custom implementation of the built-in `round` function in Python. It allows for **advanced** rounding with **artificial intelligence** to round fully, maybe even smarter than the built-in `round` function. I have no clue how it works, but it works (to my knowledge). Feel free to look at the source code and the tests I use to test it :)

# How it works and how to use
**Python 3.8 and above supported!** You will pass a float with a round to digit place (for example: hundredths) and it will round that float to that digit place. You don't have to pass round to digit place if you want to just round by the whole number (will return an integer). Example uses below:
**Python 3.8 and above supported!** You will pass a float with a 'round to' digit place (for example: hundredths), and it will round that float to that digit place you specified. If you want to round by the whole number, you can either pass a 0 for round place or don't pass any round places. The return value will be `int`. Example uses below:
```py
rounder.round(3.14159)
# Output: 3
>>> Output: 3
>>> Type: int
rounder.round(3.14159, 1)
# Output: 3.1
>>> Output: 3.1
>>> Type: float
```
## Please note
If you do attempt to round something that isn't a float or your round place is bigger than the current available digits, rounder will just return your original passed number. You can change that by editing the `rounder.return_format` variable through code or just hard coding the change with the documentation above the variable (only 3 options). Of course, feel free to add your own
If you do attempt to round something that isn't a float or your round place is bigger than the current available digits, Rounder will just return your original passed number. You can change that by editing the `rounder.return_format` variable through code or just hard coding the change with the documentation above the variable (only 3 options). Of course, feel free to add your own

# Fun fact
Rounder seems to be faster than the built-in round function (you can see my speed tests in `tests.py`)! Take that Python!
# Why use Rounder
## Comparing to built-in round function
Rounder, compared to the built-in round function of Python, is more 'advanced'. What I mean is that it rounds beyonds the number you want for a more estimate round. For example: 3.44445 rounded to the tenth place should be 3.5 if you round all the way through, which Rounder identifies correctly. Although it should be 3.5 (if you round all the way), the built-in round function defines it as 3.4. You may have different views on how to round so of course you can always use the built-in round function.

# Why?
Well first off, I kind of had to make this for a grade. Also I just wanted to make my own custom implemented round function for a while now (don't ask why), so this was the perfect excuse to make it. Feel free to actually use and edit the project to work to your liking. If you want to improve it feel free to make a pull request :)
## Speed
Rounder, overall, is faster than the built-in round function. You can check this info yourself by taking a look at the latest build tests.
38 changes: 35 additions & 3 deletions rounder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Rounding module that rounds a float just like the built in round function lol
'''

__version__ = '1.3.0'

# available options:
# same_number: the same number passed onto the function
# error_message: an error message as to why it failed
Expand Down Expand Up @@ -36,6 +38,8 @@ def _round_past_decimal(round_place, first_numbers, past_decimal):
new_past_numbers = str(zero_string + old_past).split('.') # new past decimal numbers
if int(new_past_numbers[0]) >= 1:
first_numbers += int(new_past_numbers[0])
elif int(new_past_numbers[0]) <= -1:
first_numbers -= int(new_past_numbers[0])

rounded_number = str(first_numbers) + '.' + new_past_numbers[1][:round_place]
return float(rounded_number)
Expand All @@ -52,6 +56,9 @@ def _search_number(round_place, first_numbers, past_decimal):
return float(rounded_number)

# if it goes through a whole number of 4s and can't round up
if round_place == 0:
return first_numbers

rounded_number = str(first_numbers) + '.' + past_decimal[:round_place]
return float(rounded_number)

Expand Down Expand Up @@ -86,20 +93,45 @@ def round(number: float, round_place: int = 0):
split_number = number_to_str.split('.')
first_numbers = int(split_number[0]) # the whole number as int
past_decimal = split_number[1] # number(s) past the decimal as str
# additional check to make sure there's only 15 digits past decimal
if len(past_decimal) > 15:
past_decimal = past_decimal[:15]
print('[Rounder] Warning: Automatically set digits past decimal place to just 15')

# honestly not sure if this is needed but gonna keep this for now
# added because a test failed because e was in it (at the end of it at least)
# a link to the test: https://github.com/Aethese/rounder/runs/6277132398
if past_decimal[-1] == 'e':
past_decimal = past_decimal[:-2]

if first_numbers < 0:
negative_number = True
else:
negative_number = False

if round_place == 0:
if int(past_decimal[:1]) >= 5:
first_numbers += 1
if negative_number:
first_numbers -= 1
else:
first_numbers += 1
return first_numbers
elif int(past_decimal[:1]) == 4:
search = _search_number(round_place, first_numbers, past_decimal)
# if the number doesn't need rounded up just return original first number(s)
if isinstance(search, int):
return search

search_split = str(search).split('.')
if int(search_split[1][:1]) >= 5:
first_numbers += 1
if negative_number:
first_numbers -= 1
else:
first_numbers += 1
return first_numbers
else:
return search
else:
else: # numbers past decimal don't need rounding
return first_numbers
else: # round past decimal
if len(past_decimal) <= round_place or len(past_decimal) == 1:
Expand Down
41 changes: 38 additions & 3 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

failed = 0

print(f'Running Rounder version {rounder.__version__}')

try: # Test 1
test_1a = rounder.round(4.5191, 0)
test_1b = rounder.round(4.4191)
Expand Down Expand Up @@ -66,11 +68,15 @@

try: # Test 5
start_time1 = time.time()
rounder.round(3.14159, 2)
rounder.round(3.14159, 3)
rounder.round(3.14159, 4)
finish_time1 = time.time() - start_time1
finish_time1a = rounder.round(finish_time1, 2) # hehe

start_time2 = time.time()
round(3.14159, 2)
round(3.14159, 3)
round(3.14159, 4)
finish_time2 = time.time() - start_time1
finish_time2a = rounder.round(finish_time2, 2)
Expand All @@ -80,15 +86,15 @@

print('Test 5 passed with times:')
print(finish_time1a, 'for rounder')
print(finish_time2a, 'for built in round')
print(finish_time2a, 'for built-in round')

print(finish_time1, 'rounder full number')
print(finish_time2, 'built in round full number')
print(finish_time2, 'built-in round full number')


try: # test 6
test_6a = rounder.round(3.99, 1)
test_6b = rounder.round(3.49)
test_6b = rounder.round(3.44512)
except Exception as e:
print('Test 6 failed with error:', e)
failed += 1
Expand All @@ -99,6 +105,35 @@
print('Test 6 failed:', test_6a, test_6b)
failed += 1


try: # Test 7
test_7a = rounder.round(2.444444444444)
test_7b = rounder.round(2.444444444445)
except Exception as e:
print('Test 7 failed with error:', e)
failed += 1

if test_7a == 2 and test_7b == 3:
print('Test 7 passed')
else:
print('Test 7 failed:', test_7a, test_7b)
failed += 1


try: # Test 8
test_8a = rounder.round(-3.5)
test_8b = rounder.round(-3.3445)
except Exception as e:
print('Test 8 failed with error', e)
failed += 1

if test_8a == -4 and test_8b == -3:
print('Test 8 passed')
else:
print('Test 8 failed:', test_8a, test_8b)
failed += 1

print(f'\n{failed} test(s) failed')

if failed >= 1:
exit(1)

0 comments on commit c99b22b

Please sign in to comment.