Gabriel-p
5/7/2016 - 7:00 PM

## error_round_test.py

``````import numpy as np
from random import randint
from decimal import Decimal
from math import log10, floor

def floats_5(N):
"""
Generate random floats between a random range, where all floats
end with a '5'.
"""
# rang = randint(1, 1)
flts = np.random.uniform(0., 1., N)

# Add '5' to the end of each random float, with different lengths.
fl_5 = []
for f in flts:
# Trim float.
i = randint(2, len(str(f).split('.')[1]))
# Create trimmed float that ends with a '5' .
f = Decimal(str(f).split('.')[0] + '.' + str(f).split('.')[1][:i] +
'5')
fl_5.append(f)

return fl_5

def format_e(x):
"""
Taken from: http://stackoverflow.com/a/6913576/1391441
"""
a = '%E' % x
return a.split('E')[0].rstrip('0').rstrip('.') + 'E' + a.split('E')[1]

def format_5(f, n):
"""
Round floats that end with a '5' correctly, bypassing Python's issue
with the round() function.

See: http://codereview.stackexchange.com/q/122243/35351
"""
# If the last digit is 5 or larger, round up.
if int(f[-1]) >= 5:
r_up_down = 'ROUND_UP'
else:
r_up_down = 'ROUND_DOWN'

return Decimal.quantize(Decimal(f), Decimal(f[:-n]), rounding=r_up_down)

def round_to_n(x, n=1):
"""
Round float to n significant figures.

>>> round_to_n(31.51)
30.0
>>> round_to_n(1.532)
2.0
>>> round_to_n(2156.23)
2000.0
>>> round_to_n(156.53, 3)
157.0
>>> round_to_n(0.00235, 4)
0.00235
>>> round_to_n(0.66, 1)
0.7
>>> round_to_n(0.075)
0.08
>>> round_to_n(0.075, 2)
0.075
"""

if x == 0.:
x_r = 0.
elif 0. < abs(x) < 1.:
# Count number of decimal places.
nx = len(str(x).split('.')[1])
print 'n, nx:', n, nx
if n >= nx:
# Keep all decimals.
x_r = x
elif n < nx:
# Decimal part of the float.
f1 = str(x).split('.')[1]
# Number of significant digits in float.
nd = len(f1.lstrip('0'))
# Number of leading zeroes after the decimal dot.
n0 = len(f1) - nd
print 'n0, nd:', n0, nd
if n < nd:
# New float with no leading zeroes.
x1 = '0.' + f1.lstrip('0')[:n+1]
print 'x1:', x1
# Round float.
x2 = format_5(x1, nd-(n+1))
print 'x2:', x2
if n0 > 0:
# Reconstruct float.
x_r = float('0.' + '0'*n0 + str(x2).split('.')[1])
else:
x_r = float('0.' + str(x2).split('.')[1])
else:
x_r = x
else:
pass

return x_r

for f in [0., 0.01354, 0.00015, 0.25, 0.0075]:  # floats_5(10)
print 'float:', f
new_f = round_to_n(f, 1)
print 'new_f:', new_f, '\n'``````