Constantinius
Constantinius

Reputation: 35059

Easy way of finding decimal places

Is there an easy way or integrated function to find out the decimal places of a floating point number?

The number is parsed from a string, so one way is to count the digits after the . sign, but that looks quite clumsy to me. Is there a possibility to get the information needed out of a float or Decimal object?

Upvotes: 106

Views: 156390

Answers (16)

Ashok Kmr
Ashok Kmr

Reputation: 49

converting list item to decimal number.

storing converted decimal in another variable using tuple method.

using tuple type to split the point values from decimal(d),

(example) tuple splits the decimal input three sections,like this,

 DecimalTuple(sign=0, digits=(1, 0, 0), exponent=0) 

to get the exponent from tuple using .exponent.

directly storing e=d.as_tuple().exponent, not good method.

use abs absolute function to retrieve exponent value

import decimal
    
mylist=["100","23.0","45.650","56.00","500.70000"]

for item in mylist:
    print(item)
    d = decimal.Decimal(item)
    e=abs(d.as_tuple().exponent) 
    if e==0:
        print(f"{item} has no decimal places")
    elif e==1:
            print(f"{item} has 1 decimal place")
    elif e==2:
            print(f"{item} has 2 decimal place")
    elif e==3:
            print(f"{item} has 3 decimal place")
    else:
            print(f"{item} is has many decimal places")

Upvotes: 0

nialloc
nialloc

Reputation: 852

Easiest way to do it quick

precision = lambda x: len(str(x).split('.')[1])

obviously watch the types!

I needed this as I need to dynamically round a range of big and small numbers.

>>> precision = lambda x: tuple(len(p) for p in str(x).split('.'))
>>> precision(123.345345)
(3, 6)

Upvotes: 4

senderle
senderle

Reputation: 150987

To repeat what others have said (because I had already typed it out!), I'm not even sure such a value would be meaningful in the case of a floating point number, because of the difference between the decimal and binary representation; often a number representable by a finite number of decimal digits will have only an infinite-digit representation in binary.

In the case of a decimal.Decimal object, you can retrieve the exponent using the as_tuple method, which returns a namedtuple with sign, digits, and exponent attributes:

>>> d = decimal.Decimal('56.4325')
>>> d.as_tuple().exponent
-4

>>> d = decimal.Decimal('56.43256436')
>>> d.as_tuple().exponent
-8

>>> d = decimal.Decimal(str(56.4325))
>>> d.as_tuple().exponent
-4

The negation of the exponent is the number of digits after the decimal point, unless the exponent is greater than 0.

Upvotes: 131

kure
kure

Reputation: 21

This will help you ;)

import decimal

def find_decimals(value):
    return (abs(decimal.Decimal(str(value)).as_tuple().exponent))

# Floats
print (find_decimals(123.45678))
print (find_decimals(0.00001))

# Scientific Notation
print (find_decimals(1e-05))

# Strings
print (find_decimals('123.45678'))
print (find_decimals('0.00001'))
print (find_decimals('1e-05'))

Output:

5
5
5
5
5
5

Upvotes: 2

Philosophy
Philosophy

Reputation: 1

turn it to a string, loop within it until you meet a period then subtract i+1 from the length of str

d = ['45.08']
n=len(d[0])
for i in range(n):
    if d[0][i]=='.':
        dp= n-1-i
        break
print (dp)
output = 2 (int)

Upvotes: 0

user19006133
user19006133

Reputation:

The way it works is to convert the input decimal to characters, when it detects ".", it will add the following decimal to decimals, and finally return its length

def decimal(obj):
    is_point = False
    decimals = []
    for get_float in str(obj):
        if is_point:
            decimals.append(get_float)
        if get_float == ".":
            is_point = True
    return len(decimals)

when i use it

print(decimal(1.32))
>> 2

Upvotes: 0

Ganesh
Ganesh

Reputation: 1

x = 1.2345

x_string = (str(x))

x_string_split = x_string.split('.')

x_string_split_decimal = x_string_split[1]

print(x_string_split_decimal)

print(len(x_string_split_decimal))

Upvotes: -1

nicolas.leblanc
nicolas.leblanc

Reputation: 630

Here's what worked for me:

string_value = "1234.1111"
exponent = (-len(string_value.rpartition(".")[-1])
            if "." in citem.toll_free_pricing else 0)
print(exponent)
# prints "-4"


string_value = "1234"
exponent = (-len(string_value.rpartition(".")[-1])
            if "." in citem.toll_free_pricing else 0)
print(exponent)
# prints "0"

Here's how the code is "broken-down":

string_value = "1234.1111"

if "." in citem.toll_free_pricing:

    tuple_value = string_value.rpartition(".")
    print(tuple_value)
    # prints "('1234', '.', '1111')"

    decimals = tuple_value[-1]
    print(decimals)
    # prints "1111"

    decimal_count = len(decimals)
    print(decimal_count)
    # prints "4"

    exponent = -decimal_count
    print(exponent)
    # prints "-4"

else:
    print(0)

Upvotes: 0

user3535147
user3535147

Reputation: 113

    from math import log10
    my_number = 3.1415927

    int(log10(float(str(my_number)[::-1])))+1

The way it works is that log10(number)+1 will give us the number of digits to the LEFT of the decimal place.

If we were to REVERSE the digits then the digits on the left would have previously been on the RIGHT.

    # Reverse the string
    any_string[::-1]

Upvotes: 1

mawall
mawall

Reputation: 175

In case you only need to find the decimal place of the most significant digit, ie. the leftmost one, another primitive solution would be:

fraction = 0.001
decimal_places = int(f'{fraction:e}'.split('e')[-1])

This makes use of the scientific notation (m x 10^n), which already provides the number of decimal places in form of the power (n) of 10, to which the coefficient (m) is raised, ie. -3, derived from 1.000000e-03 for the above example.

An important difference to Decimal(str(fraction)).as_tuple().exponent is that the scientific notation will always only consider the most significant digit for the exponent n, similar to Decimal().adjusted(), whereas Decimal().as_tuple().exponent returns the exponent of the least significant digit.

String formatting to scientific notation can of course also only handle floats and no strings, thus any floating point arithmetic issues persist. However, for many use cases the above might be sufficient.

Upvotes: 9

Alexander
Alexander

Reputation: 10386

"the number of decimal places" is not a property a floating point number has, because of the way they are stored and handled internally.

You can get as many decimal places as you like from a floating point number. The question is how much accuracy you want. When converting a floating point number to a string, part of the process is deciding on the accuracy.

Try for instance:

1.1 - int(1.1)

And you will see that the answer is:

0.10000000000000009

So, for this case, the number of decimals is 17. This is probably not the number you are looking for.

You can, however, round the number to a certain number of decimals with "round":

round(3.1415 - int(3.1415), 3)

For this case, the number of decimals is cut to 3.

You can't get "the number of decimals from a float", but you can decide the accuracy and how many you want.

Converting a float to a string is one way of making such a decision.

Upvotes: 18

George
George

Reputation: 166

The fastest way I found for calc digits after decimal point and rounding the number is

Calculate digits:

a=decimal.Decimal('56.9554362669143476');
lenstr = len(str(a).split(".")[1])

Calc, check and rounding:

a=decimal.Decimal('56.9554362669143476');
a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)

Comparison:

$ python2 -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); round(float(a),5) if a.as_tuple().exponent < -5 else float(a)'
10000 loops, best of 3: 32.4 usec per loop
$ python -mtimeit 'import decimal; a=decimal.Decimal('56.9554362669143476'); a = round(float(a),5) if len(str(a).split(".")[1]) > 5 else float(a)'
100000 loops, best of 3: 16.7 usec per loop

Upvotes: 11

J&#233;r&#233;my JOKE
J&#233;r&#233;my JOKE

Reputation: 281

I needed something like this and i tested some of these, the fastest i found out was :

str(number)[::-1].find('.')

Because of the floating point issue all the modulo ones gave me false results even with Decimal(number) (note that i needed this in a script to fix prices of an entire db)

len(str(Decimal(str(number))) % Decimal(1))) - 2

The need to put a string into Decimal is quite uneasy when we have floats or something like.

Here is my "bench" : https://repl.it/FM8m/17

Upvotes: 7

Spencer Rathbun
Spencer Rathbun

Reputation: 14900

The decimal library is for working with decimal numbers, like in Accounting. It doesn't inherently have a function to return the number of decimal places. This is especially a problem when you realize that the context it runs under sets it at whatever the user wants.

If you get a string, you can convert to decimal, but this will either tack on zeros to get you to your accuracy, or use the rounding setting to truncate it.

Your best bet would probably bet splitting on the dot in your string and counting the number of chars in the resulting substring.

Upvotes: 4

Mark Ransom
Mark Ransom

Reputation: 308206

Since Python floating point numbers are internally represented as binary rather than decimal, there's really no shortcut other than converting to decimal. The only built-in way to do that is by converting to a string. You could write your own code to do a decimal conversion and count the digits, but it would be a duplication of effort.

Upvotes: 1

jkerian
jkerian

Reputation: 17016

If you know you're not going to have parsing issues (or if you're letting python itself or some other library handle that for you, hopefully handling localization issues)... just parse it and use modf. The return value is a pair of values, one of which is the integral part, the other is the fractional part.

Upvotes: 1

Related Questions