Reputation: 1532
Floating Point = 11.0000123456789
I want to round the above floating point number to 11.00001235. So I want the base portion of the float rounded to 4 digits while ignoring and preserving the leading zeros and adding back in the significand at the end.
I have the following, it is short and sweet but feels a little bit like a work around.
import decimal
decimal.getcontext().prec = 4
significand, base = str(11.0000123456789).split('.')
fp = significand + str(decimal.Decimal('.' + base) + 0)[1:] # I need to add 0 here for it to work
print(fp)
I can't really find an answer to my specific question. I want to know what the most pythonic way of achieving this is or if what I have is decent enough. It feels a little shoddy to me.
Edit: the number of leading zeros is unknown and I chose four for the example. So I don't think string formatting will work.
Upvotes: 2
Views: 632
Reputation: 31
An issue with @Rotem's answer is that it won't account for all leading 0s (number between 0-1), this small edit fixes that.
def round_to_N_ignoring_leading_zeros(ending_values_to_keep, number):
"""
rounds the number off to N trailing decimals, ignoring leading values (including 0)
1.000016 -> 1.00001600
0.000016 -> 0.00001600
11.0000123456789 -> 11.00001235
:param ending_values_to_keep:
:param number:
:return:
"""
import re
altered = False
if number < 1:
altered = True
number += 1
regex = r"0[1-9]"
float_part = str(number).split(".")[1]
float_limiter = re.search(regex, float_part).start() if float_part.startswith("0") else -1
number -= 1
return eval(f'{number:2.{float_limiter + 1 + ending_values_to_keep}f}')
Upvotes: 0
Reputation: 769
Edit: for an unknown number of 0's I don't see a better alternative than
import re
some_float = 11.00001203456789
how_many_to_keep = 4
regex = r"0[1-9]"
float_part = str(some_float).split(".")[1]
float_limiter = re.search(regex,float_part).start() if float_part.startswith("0") else -1
print(f'{some_float:2.{float_limiter+1+how_many_to_keep}f}')
Which is evaluating the number of 0 in real time using the expression float_limiter+1+how_many_to_keep
, and use as a the format parameter. this has gotten a bit ugly but now returns the correct answer on all cases. The output is
11.00001235
Upvotes: 1
Reputation: 8566
I think this is the most pythonic way to solve your problem. Try this,
>>> import re
>>>
>>> float_val = 11.0000123456789
>>> keep_places = 4
>>>
>>> regEX = f'[0-9]+\.[0]+{"[0-9]" * keep_places}'
>>> expected_val = re.search(regEX, str(float_val)).group()
>>>
>>> print(expected_val)
'11.00001234'
The easiest way is create the Regular expression operations and this is how I use it to solve your question. Let's break it into 4 parts.
[0-9]+
\.
[0]+
[0-9] * keep_places
(1). [0-9]
mean select only one digit in between 0 and 9. We need multiple digit before the decimal point. That's why we add [0-9]+
. If you don't have any integers before the decimal point, then add *
instead of +
, it check zero or more occurrences. If you're using +
mean you must have one or more values.
(2). .
this dot is a special character to select any character except newline character from the given string. We need to capture decimal point which also a dot. If our string has these kind of special characters(in our case a decimal point) we use \
to match those characters. That's why we use \.
, it now can match our decimal point.
(3). [0]+
, this will match all the zeros in our string.
(4). [0-9] * keep_places
, this is just a string multiplication. For this question keep_places
is 4
which mean we get this kind of output [0-9][0-9][0-9][0-9]
. But in Regular expression operations, it select only four digit which each digit in between 0 and 9. One more thing, for this question it doesn't matter you're using [0-9]
or [1-9]
. Because we already capture zeros, it start to find other integers from 1
.
If you print regEX
, all togeather you'll see [0-9]+\.[0]+[0-9][0-9][0-9][0-9]
kind of string. It matches <any_number><dot><all_zeros_before_the__non_zero_integer><4_digit_after_last_zero>
type of pattern only. You can test this expression online.
Upvotes: 2