edesz
edesz

Reputation: 12406

Round floats down in Python to keep one non-zero decimal only

I have a Python list only filled with floats:

list_num = [0.41, 0.093, 0.002, 1.59, 0.0079, 0.080, 0.375]

I need to round this list down to get:

list_num_rounded = [0.4, 0.09, 0.002, 1.5, 0.007, 0.08, 0.3]

Problem: Rounding 1.59 to 1.5 is easy to do. However, my problem is with floats that are less than 1.

Question: Basically, I need to round all floats down so that: if the float is < 1, then the rounded version only contains one non-zero number. Is there a way to do this in Python 2.7?

Attempt: Here is what I have tried:

list_num_rounded = []
for elem in list_num:
    if elem > 0.01 and elem < 0.1:
        list_num_rounded.append(round(elem,2))
    if elem > 0.001 and elem < 0.01:
        list_num_rounded.append(round(elem,3))
    elif elem > 0.1:
        list_num_rounded.append(round(elem,1))

However, this gives:

[0.4, 0.09, 0.002, 1.6, 0.008, 0.08, 0.4]

It is rounding 1.59, 0.79 and 0.375 up, but I need a way to only round down. Is there a way to do this?

The list will not contain negative floats. Only positive floats will be present.

Upvotes: 14

Views: 6637

Answers (4)

Vadim Isakov
Vadim Isakov

Reputation: 51

We solve the problem by identifying the number of zeros until the first decimal in the floating part, and then round using this value.

def round_float(num):
    if not num:
        return num
    current_num = abs(num) * 10
    round_value = 1

    while not (current_num//1):
        current_num *= 10
        round_value +=1

    return round(num, round_value)

Upvotes: 4

rurp
rurp

Reputation: 1446

Given that all of the floats are positive you could convert them to strings and use slicing like this.

def round(num):
    working = str(num-int(num))
    for i, e in enumerate(working[2:]):
        if e != '0':
            return int(num) + float(working[:i+3])

list_num = [0.41, 0.093, 0.002, 1.59, 0.0079, 0.080, 0.375]
new_list = [round(x) for x in list_num]
print new_list

prints

[0.4, 0.09, 0.002, 1.5, 0.007, 0.08, 0.3]

If there could be floats in the list with no non-zero values after the decimal you will need to add a simple check to handle that.

Upvotes: 3

reupen
reupen

Reputation: 571

You could use logarithms to work out how many leading zeroes there are, then you need a way to round down. One way is to use floor like so:

import math

list_num = [0.41, 0.093, 0.002, 1.59, 0.0079, 0.080, 0.375, 0, 10.1, -0.061]


def myround(n):
    if n == 0:
        return 0
    sgn = -1 if n < 0 else 1
    scale = int(-math.floor(math.log10(abs(n))))
    if scale <= 0:
        scale = 1
    factor = 10**scale
    return sgn*math.floor(abs(n)*factor)/factor


print [myround(x) for x in list_num]

Output:

[0.4, 0.09, 0.002, 1.5, 0.007, 0.08, 0.3]

I'm not sure how you want to handle negative numbers and numbers greater than 1, this rounds negative numbers up and numbers greater than 1 to 1dp.

Upvotes: 8

Thomas Baruchel
Thomas Baruchel

Reputation: 7517

Formatting your float numbers to scientific notation can help; then converting back to float types should achieve what you want. Try something like:

eval("%.0e" % (.03))
eval("%.0e" % (.034))
eval("%.0e" % (.0034))

Upvotes: 2

Related Questions