I'd like to automatically round numbers to x significant figures, but only their fractional part.
Desired output:
123 >>> 123.00
123.123 >>> 123.12
1.12 >>> 1.12
0.1 >>> 0.10
0.1234 >>> 0.12
0.01234 >>> 0.012
0.0001254 >>> 0.00013
I'm trying to achieve the most simple solution.
I've figured out such a solution:
def round_to_frac_sigfig(num, sigfigs):
sigfig_pos = int(floor(log10(abs(num))))
if sigfig_pos >= 0:
formatter = "{:.%df}" % sigfigs
return formatter.format(num)
else:
ndigits = -sigfig_pos + sigfigs - 1
formatter = "{:.%df}" % ndigits
return formatter.format(num)
If you don't care about the trailing zeros, here's a shorter solution:
def round_to_frac_sigfig(num, sigfigs):
sigfig_pos = int(floor(log10(abs(num))))
if sigfig_pos >= 0:
return round(num, sigfigs)
else:
return round(num, -sigfig_pos + sigfigs - 1)
Related
I have the following code and result and I would need each number to be rounded to the first decimal but the lowest one ex: 7.166666666666667 to be 7.1 and not 7.2
I have tried with round_down but it still rounds up
for x in range(0, 9):
income_visits=(income_euro[x]/visits[x])
print(income_visits)
7.166666666666667
7.0
7.666666666666667
11.0
0.1111111111111111
11.333333333333334
162.0
55.0
9.0
here's a little function that does it for you:
def round_down(n, decimals=0):
multiplier = 10 ** decimals
return math.floor(n * multiplier) / multiplier
make sure to import the math library.
example usage:
print(round_down(1.7777, 1))
print(round_down(1.7777, 2))
print(round_down(1.7777, 3))
output:
1.7
1.77
1.777
Here is the solution. Try this..
number = YOUR_NUMBER
float(str(int(number)) + '.' + str(number-int(number))[2:3])
>>> number = 7.166666666666667
>>> print( float(str(int(number)) + '.' + str(number-int(number))[2:3]) )
7.1
>>>
>>> number = 7.116666666666667
>>> print( float(str(int(number)) + '.' + str(number-int(number))[2:3]) )
7.1
>>>
>>> number = 7.196666666666667
>>> print( float(str(int(number)) + '.' + str(number-int(number))[2:3]) )
7.1
>>>
>>> number = 7.096666666666667
>>> print( float(str(int(number)) + '.' + str(number-int(number))[2:3]) )
This could also work.
num = 7.166666666667
print(int(num*10)/10)
What this does is it takes the number (i.e. 7.1666...) multiplies it by 10(71.666...) that way when an integer is taken from it, it returns a whole number (71), then it divides again to get just one decimal place (7.1). Hope this helps.
import struct
def print_binary(number_string):
bin = ""
if "." in number_string:
number_string = float(number_string)
bin += bin(struct.unpack('!i',struct.pack('!f', number_string)))
else:
num = int(number_string)
bin += "{0:b}".format(num)
print(bin)
I'm having trouble with converting a number with a decimal in it to binary (my if statement)
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
I get an error when it gets up to 12.4
I used recursion. But there can be a recursion limit on some value here.
Here is the method I used by hand.
Fractional Part = .6875 in base 10
.6875*2 equals 1.375 whole number is 1
.375*2 equals 0.75 whole number is 0
.75*2 equals 1.5 whole number is 1
.5*2 equals 1.0 whole number is 1
Hence .6875D = .1011 in base 2
However, think about the value 12.4. It will go forever!
.4*2 = .8
.8*2 = 1.6
.6*2 = .2
.2*2 = .4
... and so on
So we have to set a limit in our recursion calculation. I made it 10. Although this does not sound like a lot, see how accurate it is.
My input of 12.4 returns 1100.0110011001 which is equal to 12.3994140625
Pretty close, feel free to play with that number, take the ceiling of it, etc.
Here is the code:
def get_integer_part(pre_decimal_string):
# special case of negative 0 being a prefix "-0.6"
if pre_decimal_string == "-0":
return "-0"
else:
num = int(pre_decimal_string)
return "{0:b}".format(num)
def get_decimal_part(post_decimal_string, string_builder, recurse):
recurse += 1
post_decimal_value = float("." + post_decimal_string)
if post_decimal_value == 0 or recurse > 10:
return string_builder
else:
temp_mult_str = str(post_decimal_value * 2)
temp_mult_split = temp_mult_str.split(".")
string_builder += temp_mult_split[0]
return get_decimal_part(temp_mult_split[1], string_builder, recurse)
def print_binary(number_string):
# handle case of no preceding 0 ".3" or
if number_string[0] == ".":
number_string = "0" + number_string
# handle case of no preceding 0 and is negative
if number_string[0:2] == "-.":
number_string = "-0" + number_string[1:]
if "." in number_string:
str_split = number_string.split(".")
print(get_integer_part(str_split[0]) + "." + str(get_decimal_part(str_split[1], "", 0)))
else:
print(get_integer_part(number_string))
test_values = "0 1234 -1234 12.4 0.6 -12.4 -0.6 -1234567890.123456789".split()
print(test_values)
for each in test_values:
print_binary(each)
# special cases
print_binary("-.7")
print_binary(".67")
Here is the final output:
0
10011010010
-10011010010
1100.0110011001
0.1001100110
-1100.0110011001
-0.1001100110
-1001001100101100000001011010010.0001111110
-0.1011001100
0.1010101110
Although I would have done this differently, I kept your code and format as much as possible to make it easiest for you to learn.
Can Python disable or not used the rounding off a float?
This is my sample
value = 6.30 * 75.73
value:
477.099
I want only to get the value 477.09 without rounding it off.
You can convert to a string and using string split, append just the last 2 digits of the number
num = 477.097
strnum = str(int(num)) + str(num).split(".")[1][:2]
What you want is called truncating, which is notoriously difficult with float values because of the way they are stored.
If you are doing this for the value itself, you can do this;
value = 6.30 * 75.73
value = (( value * 100 ) // 1) * .01
print(value)
This will print
477.09000000000003
which is equivalent to 477.09 for math calculations.
If you are doing this to display the value, then you can convert to a string and just cut off the last digit that you have. Or, if you don't know how many digits there are after the decimal point, you can get the index of the ".", and cut everything that is 2 after that point, as so:
value = 6.30 * 75.73
val_str = str(value)
rounded_str = val_str[:val_str.index('.') + 3]
This will print
477.09
convert value to string(if value an integer then the code will still work, because before the conversion to a string we convert to a float):
value = = 6.30 * 75.73
value_str = str(float(value))
'{:.2f}'.format(float(value_str[:value_str.index('.') + 3]))
Possibly this? (takes about 100 nanoseconds independent of number of digits)
** note, this does not work for negative numbers as written, so it's of limited use.
value = 6.30 * 75.73
print value
print value - value % 0.01
477.097
477.09
does it really truncate?
value = 1./3.
print value - 0.33333333 # see the leftovers
3.333333331578814e-09
print value - value % 0.01
0.33
print (value - value % 0.01) - 0.33 # no leftovers
0.0
(value - value % 0.01) == 0.33
True
You can try this hack with round:
>>> 6.30 * 75.73
>>> 477.099
>>> DIGITS = 2
>>> round(6.30 * 75.73 - 5.0 * 10**(-DIGITS-1), DIGITS)
>>> 477.09
I would like to use the Decimal() data type in python and convert it to an integer and exponent so I can send that data to a microcontroller/plc with full precision and decimal control. https://docs.python.org/2/library/decimal.html
I have got it to work, but it is hackish; does anyone know a better way? If not what path would I take to write a lower level "as_int()" function myself?
Example code:
from decimal import *
d=Decimal('3.14159')
t=d.as_tuple()
if t[0] == 0:
sign=1
else:
sign=-1
digits= t[1]
theExponent=t[2]
theInteger=sign * int(''.join(map(str,digits)))
theExponent
theInteger
For those that havent programmed PLCs, my alternative to this is to use an int and declare the decimal point in both systems or use a floating point (that only some PLCs support) and is lossy. So you can see why being able to do this would be awesome!
Thanks in advance!
You could do this :
[ This is 3 times faster than the other methods ]
d=Decimal('3.14159')
list_d = str(d).split('.')
# Converting the decimal to string and splitting it at the decimal point
# If decimal point exists => Negative exponent
# i.e 3.14159 => "3", "14159"
# exponent = -len("14159") = -5
# integer = int("3"+"14159") = 314159
if len(list_d) == 2:
# Exponent is the negative of length of no of digits after decimal point
exponent = -len(list_d[1])
integer = int(list_d[0] + list_d[1])
# If the decimal point does not exist => Positive / Zero exponent
# 3400
# exponent = len("3400") - len("34") = 2
# integer = int("34") = 34
else:
str_dec = list_d[0].rstrip('0')
exponent = len(list_d[0]) - len(str_dec)
integer = int(str_dec)
print integer, exponent
Performance testing
def to_int_exp(decimal_instance):
list_d = str(decimal_instance).split('.')
if len(list_d) == 2:
# Negative exponent
exponent = -len(list_d[1])
integer = int(list_d[0] + list_d[1])
else:
str_dec = list_d[0].rstrip('0')
# Positive exponent
exponent = len(list_d[0]) - len(str_dec)
integer = int(str_dec)
return integer, exponent
def to_int_exp1(decimal_instance):
t=decimal_instance.as_tuple()
if t[0] == 0:
sign=1
else:
sign=-1
digits= t[1]
exponent = t[2]
integer = sign * int(''.join(map(str,digits)))
return integer, exponent
Calculating the time taken for 100,000 loops for both methods :
ttaken = time.time()
for i in range(100000):
d = Decimal(random.uniform(-3, +3))
to_int_exp(d)
ttaken = time.time() - ttaken
print ttaken
Time taken for string parsing method : 1.56606507301
ttaken = time.time()
for i in range(100000):
d = Decimal(random.uniform(-3, +3))
to_int_exp1(d)
ttaken = time.time() - ttaken
print ttaken
Time taken for convertion to tuple then extract method : 4.67159295082
from functools import reduce # Only in Python 3, omit this in Python 2.x
from decimal import *
d = Decimal('3.14159')
t = d.as_tuple()
theInteger = reduce(lambda rst, x: rst * 10 + x, t.digits)
theExponent = t.exponent
Get the exponent directly from the tuple as you were:
exponent = d.as_tuple()[2]
Then multiply by the proper power of 10:
i = int(d * Decimal('10')**-exponent)
Putting it all together:
from decimal import Decimal
_ten = Decimal('10')
def int_exponent(d):
exponent = d.as_tuple()[2]
int_part = int(d * (_ten ** -exponent))
return int_part, exponent
from decimal import *
d=Decimal('3.14159')
t=d.as_tuple()
digits=t.digits
theInteger=0
for x in range(len(digits)):
theInteger=theInteger+digits[x]*10**(len(digits)-x)
Kind of like this question, but in reverse.
Given a string like 1, 1/2, or 1 2/3, what's the best way to convert it into a float? I'm thinking about using regexes on a case-by-case basis, but perhaps someone knows of a better way, or a pre-existing solution. I was hoping I could just use eval, but I think the 3rd case prevents that.
maybe something like this (2.6+)
from fractions import Fraction
float(sum(Fraction(s) for s in '1 2/3'.split()))
I tweaked James' answer a bit.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
num, denom = frac_str.split('/')
try:
leading, num = num.split(' ')
whole = float(leading)
except ValueError:
whole = 0
frac = float(num) / float(denom)
return whole - frac if whole < 0 else whole + frac
print convert_to_float('3') # 3.0
print convert_to_float('3/2') # 1.5
print convert_to_float('1 1/2') # 1.5
print convert_to_float('-1 1/2') # -1.5
http://ideone.com/ItifKv
Though you should stear clear of eval completely. Perhaps some more refined version of:
num,den = s.split( '/' )
wh, num = num.split()
result = wh + (float(num)/float(den))
Sorry, meant to be num.split not s.split, and casts. Edited.
I see there are already several good answers here, but I've had good luck with this. It also has the benefit that it will tolerate non-fraction strings if you're parsing mixed sets of data, so there's no need to check if it's a fraction string or not upfront.
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
try:
num, denom = frac_str.split('/')
except ValueError:
return None
try:
leading, num = num.split(' ')
except ValueError:
return float(num) / float(denom)
if float(leading) < 0:
sign_mult = -1
else:
sign_mult = 1
return float(leading) + sign_mult * (float(num) / float(denom))
>>> convert_to_float('3')
3.0
>>> convert_to_float('1/4')
0.25
>>> convert_to_float('1 2/3')
1.6666666666666665
>>> convert_to_float('-2/3')
-0.6666666666666666
>>> convert_to_float('-3 1/2')
-3.5
That might be a dirty workaround, but you could convert spaces to a + sign to solve the 3rd case (or to a - if your fraction is negative).
def fractionToFloat(fraction):
num = 0
mult = 1
if fraction[:1] == "-":
fraction = fraction[1:]
mult = -1
if " " in fraction:
a = fraction.split(" ")
num = float(a[0])
toSplit = a[1]
else:
toSplit = fraction
frac = toSplit.split("/")
num += float(frac[0]) / float(frac[1])
return num * mult
It can also handle "2 1/1e-8", "-1/3" and "1/5e3".
This implementation avoids using eval and works on pre-2.6 versions of Python.
# matches a string consting of an integer followed by either a divisor
# ("/" and an integer) or some spaces and a simple fraction (two integers
# separated by "/")
FRACTION_REGEX = re.compile(r'^(\d+)(?:(?:\s+(\d+))?/(\d+))?$')
def parse(x):
i, n, d = FRACTION_REGEX.match(x).groups()
if d is None: n, d = 0, 1 # if d is None, then n is also None
if n is None: i, n = 0, i
return float(i) + float(n) / float(d)
To test:
>>> for x in ['1', '1/2', '1 2/3']: print(repr(parse(x)))
...
1.0
0.5
1.6666666666666665
Depending on what syntax you want to support for your fractions, eval('+'.join(s.split())) (with true division in place -- i.e., Python 3 or from __future__ import division in Python 2 -- might work. It would cover all the cases you mention, in particular.
>>> s="1/2"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.5
>>> s="3/5"
>>> eval('/'.join(map(str,map(float,s.split("/")))))
0.59999999999999998