float random.uniform to 4 decimal places in python - python

I am having problem rounding floating value to a decimal number greater than 1.
def float_generator(size=6, chars = 6):
return random.uniform(size,chars)
and i tried
target.write(str(float_generator(7,3)))
the above returns random float to 1 decimal num like 1.2222 , 1.333333
I want to generate 7 decimal and 3 points as illustrated in the 7,3
i tried rounding off below. It round up the points instead .
target.write(str(format(float_generator(7,3),'.3f')))
Please how do i achieve 12345432.123 instead of 1.222343223 ? Any help would be appreciated.

You could use decimal and random to return a Decimal object if you want fine-tuned control of decimal places:
import random, decimal
digits = list('0123456789')
def float_generator(size = 6, chars = 6):
base_str = ''.join(random.choice(digits) for i in range(size))
dec_str = ''.join(random.choice(digits) for i in range(chars))
return decimal.Decimal(base_str + '.' + dec_str)
>>> float_generator(7,3)
Decimal('4768087.977')
Decimal objects can be fed to float:
>>> float(decimal.Decimal('4768087.977'))
4768087.977
If you always want a float, you can replace the last line of the function by:
return float(decimal.Decimal(base_str + '.' + dec_str))

here is a solution for you:
import random
def float_generator(size = 6, chars = 6):
return round(random.uniform(10**(size-1),10**(size)), chars)
call it:
float_generator(7,3)
output example:
2296871.988
or better:
float_generator = lambda size, chars: round(random.uniform(10**(size-1),10**(size)), chars)
call it the same way.

Related

How to get precise last digit in python decimal module

I'm trying to create a program that finds the nth digit on the square root of 2 by using the decimal module
√2 = 1.414213(5)6237309504880168872420969807856967187537694…
if the user requests the 8th digit, the program generates 8 digits of √2 (1.4142135) and print the last digit (5)
nth_digit_of_sqrt_of_2 = 8 # i wanna find the 8th digit of √2
expected_sqrt_of_2 = "14142135" # 5 first digits of √2 (no decimal point)
expected_answer = 5 # the last digit
but what actually happens:
from decimal import Decimal, getcontext
getcontext().prec = nth_digit_of_sqrt_of_2 # set precision to 5 digits
decimal_sqrt_of_2 = Decimal('2').sqrt()
decimal_sqrt_of_2 = str(decimal_sqrt_of_2).replace('.', '') # convert to string and remove decimal point
print(decimal_sqrt_of_2)
# actual_sqrt_of_2 = 14142136
# actual_answer = 6
I tried using ROUND_DOWN and ROND_FLOOR but doesn't seems to work either
You can try this :
from decimal import Decimal, getcontext
nth_digit_of_sqrt_of_2 = 8
getcontext().prec = nth_digit_of_sqrt_of_2 + 1 # set precision to n+1 digits
decimal_sqrt_of_2 = Decimal('2').sqrt()
decimal_sqrt_of_2 = str(decimal_sqrt_of_2).replace('.', '') # convert to string and remove decimal point
print(int(str(decimal_sqrt_of_2)[nth_digit_of_sqrt_of_2 - 1]))
You can get the digits by using:
def digit(n):
from decimal import Decimal
return str(Decimal('2').sqrt()).replace('.', '')[n-1]
digit(8)
#'5'
digit(7)
#'3'
digit(9)
#'6'
Edit: If you want more digits you can customize your own function.
def sqrut(x, digits):
x = x * (10**(2*digits))
prev = 0
next = 1 * (10**digits)
while prev != next:
prev = next
next = (prev + (x // prev)) >> 1
return str(next)
suppose you want 1000 digits in squareroot of 2 you can get by
print(sqrut(2, 1000))
'14142135623730950488016887242096980785696718753769480731766797379907324784621070388503875343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079896872533965463318088296406206152583523950547457502877599617298355752203375318570113543746034084988471603868999706990048150305440277903164542478230684929369186215805784631115966687130130156185689872372352885092648612494977154218334204285686060146824720771435854874155657069677653720226485447015858801620758474922657226002085584466521458398893944370926591800311388246468157082630100594858704003186480342194897278290641045072636881313739855256117322040245091227700226941127573627280495738108967504018369868368450725799364729060762996941380475654823728997180326802474420629269124859052181004459842150591120249441341728531478105803603371077309182869314710171111683916581726889419758716582152128229518488472'
Now, if you want 8th digit then:
print(sqrut(2, 1000)[8-1])
#'5'
#9th digit then:
print(sqrut(2, 1000)[9-1])
#'6'
#nth digit then:
print(sqrut(2, 1000)[n-1])

Find least significant digit in a double in Python

I have a lot of financial data stored as floating point doubles and I'm trying to find the least significant digit so that I can convert the data to integers with exponent.
All the data is finite, e.g. 1234.23 or 0.0001234 but because it's stored in doubles it can be 123.23000000001 or 0.00012339999999 etc
Is there an easy or proper approach to this or will I just have to botch it?
You have a couple of options,
Firstly and most preferably, use the stdlib Decimal, not builtin float
This fixes most errors related to floats but not the infamous 0.1 + 0.2 = 0.3...4
from decimal import Demical
print(0.1 + 0.2) # 0.30000000000000004
print(Decimal(0.1) + Decimal(0.2)) # 0.3000000000000000166533453694
An alternative option if that isn't possible, is setting a tolerance for number of repeated digits after the decimal point.
For example:
import re
repeated_digit_tolerance = 8 # Change to an appropriate value for your dataset
repeated_digit_pattern = re.compile(r"(.)\1{2,}")
def longest_repeated_digit_re(s: str):
match = repeated_digit_pattern.search(s)
string = match.string
span = match.span()
substr_len = span[1] - span[0]
return substr_len, string
def fix_rounding(num: float) -> float:
num_str = str(num)
pre_dp = num_str[:num_str.index(".")]
post_dp = num_str[num_str.index(".") + 1:]
repetition_length, string = longest_repeated_digit_re(post_dp)
if repetition_length > repeated_digit_tolerance:
shortened_string = string[:repeated_digit_tolerance-1]
return float(".".join([pre_dp, shortened_string]))
print(0.1 + 0.2) # 0.30000000000000004
print(0.2 + 0.4) # 0.6000000000000001
print(fix_rounding(0.1 + 0.2)) # 0.3
print(fix_rounding(0.2 + 0.4)) # 0.6
It's perfectly functioning code but Decimal is practially always the better option of the two, even if it wont do 0.1 + 0.2 correctly.
Here is my botch using strings. It works adequately at the moment for what I need but I haven't fully tested it.
print (int_sci_notation(0.1+0.2)) will return a tupple (3,-1)
def int_sci_notation(decimal_value):
#decimal value is finite value stored in double precision
#convert to scientific string (cannot prevent E notation so force all numbers to E notation)
tostr = format(decimal_value, ".14E")
#get exponent from string
if tostr[-3] == '-':
exp = -int(tostr[-2:])
else:
exp = int(tostr[-2:])
#get significant figures as an integer
frac = tostr[1:-4].strip('0')
sf = tostr[0]+frac[1:]
#return the integer 'mantissa' and the exponent
return int(sf), -int(len(sf)-1-exp)

Print pi to a number of decimal places

One of the challenges on w3resources is to print pi to 'n' decimal places. Here is my code:
from math import pi
fraser = str(pi)
length_of_pi = []
number_of_places = raw_input("Enter the number of decimal places you want to
see: ")
for number_of_places in fraser:
length_of_pi.append(str(number_of_places))
print "".join(length_of_pi)
For whatever reason, it automatically prints pi without taking into account of any inputs. Any help would be great :)
The proposed solutions using np.pi, math.pi, etc only only work to double precision (~14 digits), to get higher precision you need to use multi-precision, for example the mpmath package
>>> from mpmath import mp
>>> mp.dps = 20 # set number of digits
>>> print(mp.pi)
3.1415926535897932385
Using np.pi gives the wrong result
>>> format(np.pi, '.20f')
3.14159265358979311600
Compare to the true value:
3.14159265358979323846264338327...
Why not just format using number_of_places:
''.format(pi)
>>> format(pi, '.4f')
'3.1416'
>>> format(pi, '.14f')
'3.14159265358979'
And more generally:
>>> number_of_places = 6
>>> '{:.{}f}'.format(pi, number_of_places)
'3.141593'
In your original approach, I guess you're trying to pick a number of digits using number_of_places as the control variable of the loop, which is quite hacky but does not work in your case because the initial number_of_digits entered by the user is never used. It is instead being replaced by the iteratee values from the pi string.
For example the mpmath package
from mpmath import mp
def a(n):
mp.dps=n+1
return(mp.pi)
Great answers! there are so many ways to achieve this. Check out this method I used below, it works any number of decimal places till infinity:
#import multp-precision module
from mpmath import mp
#define PI function
def pi_func():
while True:
#request input from user
try:
entry = input("Please enter an number of decimal places to which the value of PI should be calculated\nEnter 'quit' to cancel: ")
#condition for quit
if entry == 'quit':
break
#modify input for computation
mp.dps = int(entry) +1
#condition for input error
except:
print("Looks like you did not enter an integer!")
continue
#execute and print result
else:
print(mp.pi)
continue
Good luck Pal!
Your solution appears to be looping over the wrong thing:
for number_of_places in fraser:
For 9 places, this turns out be something like:
for "9" in "3.141592653589793":
Which loops three times, one for each "9" found in the string. We can fix your code:
from math import pi
fraser = str(pi)
length_of_pi = []
number_of_places = int(raw_input("Enter the number of decimal places you want: "))
for places in range(number_of_places + 1): # +1 for decimal point
length_of_pi.append(str(fraser[places]))
print "".join(length_of_pi)
But this still limits n to be less than the len(str(math.pi)), less than 15 in Python 2. Given a serious n, it breaks:
> python test.py
Enter the number of decimal places you want to see: 100
Traceback (most recent call last):
File "test.py", line 10, in <module>
length_of_pi.append(str(fraser[places]))
IndexError: string index out of range
>
To do better, we have to calculate PI ourselves -- using a series evaluation is one approach:
# Rewrite of Henrik Johansson's (Henrik.Johansson#Nexus.Comm.SE)
# pi.c example from his bignum package for Python 3
#
# Terms based on Gauss' refinement of Machin's formula:
#
# arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ...
from decimal import Decimal, getcontext
TERMS = [(12, 18), (8, 57), (-5, 239)] # ala Gauss
def arctan(talj, kvot):
"""Compute arctangent using a series approximation"""
summation = 0
talj *= product
qfactor = 1
while talj:
talj //= kvot
summation += (talj // qfactor)
qfactor += 2
return summation
number_of_places = int(input("Enter the number of decimal places you want: "))
getcontext().prec = number_of_places
product = 10 ** number_of_places
result = 0
for multiplier, denominator in TERMS:
denominator = Decimal(denominator)
result += arctan(- denominator * multiplier, - (denominator ** 2))
result *= 4 # pi == atan(1) * 4
string = str(result)
# 3.14159265358979E+15 => 3.14159265358979
print(string[0:string.index("E")])
Now we can take on a large value of n:
> python3 test2.py
Enter the number of decimal places you want: 100
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067
>
This is what I did, really elementary but works (max 15 decimal places):
pi = 22/7
while True:
n = int(input('Please enter how many decimals you want to print: '))
if n<=15:
print('The output with {} decimal places is: '.format(n))
x = str(pi)
print(x[0:n+2])
break
else:
print('Please enter a number between 0 and 15')
As this question already has useful answers, I would just like to share how i created a program for the same purpose, which is very similar to the one in the question.
from math import pi
i = int(input("Enter the number of decimal places: "))
h = 0
b = list()
for x in str(pi):
h += 1
b.append(x)
if h == i+2:
break
h = ''.join(b)
print(h)
Thanks for Reading.
Why not just use:
import numpy as np
def pidecimal(round):
print(np.round(np.pi, round))

drop trailing zeros from decimal

I have a long list of Decimals and that I have to adjust by factors of 10, 100, 1000,..... 1000000 depending on certain conditions. When I multiply them there is sometimes a useless trailing zero (though not always) that I want to get rid of. For example...
from decimal import Decimal
# outputs 25.0, PROBLEM! I would like it to output 25
print Decimal('2.5') * 10
# outputs 2567.8000, PROBLEM! I would like it to output 2567.8
print Decimal('2.5678') * 1000
Is there a function that tells the decimal object to drop these insignificant zeros? The only way I can think of doing this is to convert to a string and replace them using regular expressions.
Should probably mention that I am using python 2.6.5
EDIT
senderle's fine answer made me realize that I occasionally get a number like 250.0 which when normalized produces 2.5E+2. I guess in these cases I could try to sort them out and convert to a int
You can use the normalize method to remove extra precision.
>>> print decimal.Decimal('5.500')
5.500
>>> print decimal.Decimal('5.500').normalize()
5.5
To avoid stripping zeros to the left of the decimal point, you could do this:
def normalize_fraction(d):
normalized = d.normalize()
sign, digits, exponent = normalized.as_tuple()
if exponent > 0:
return decimal.Decimal((sign, digits + (0,) * exponent, 0))
else:
return normalized
Or more compactly, using quantize as suggested by user7116:
def normalize_fraction(d):
normalized = d.normalize()
sign, digit, exponent = normalized.as_tuple()
return normalized if exponent <= 0 else normalized.quantize(1)
You could also use to_integral() as shown here but I think using as_tuple this way is more self-documenting.
I tested these both against a few cases; please leave a comment if you find something that doesn't work.
>>> normalize_fraction(decimal.Decimal('55.5'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55.500'))
Decimal('55.5')
>>> normalize_fraction(decimal.Decimal('55500'))
Decimal('55500')
>>> normalize_fraction(decimal.Decimal('555E2'))
Decimal('55500')
There's probably a better way of doing this, but you could use .rstrip('0').rstrip('.') to achieve the result that you want.
Using your numbers as an example:
>>> s = str(Decimal('2.5') * 10)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
25
>>> s = str(Decimal('2.5678') * 1000)
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
2567.8
And here's the fix for the problem that #gerrit pointed out in the comments:
>>> s = str(Decimal('1500'))
>>> print s.rstrip('0').rstrip('.') if '.' in s else s
1500
Answer from the Decimal FAQ in the documentation:
>>> def remove_exponent(d):
... return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5.00'))
Decimal('5')
>>> remove_exponent(Decimal('5.500'))
Decimal('5.5')
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')
Answer is mentioned in FAQ (https://docs.python.org/2/library/decimal.html#decimal-faq) but does not explain things.
To drop trailing zeros for fraction part you should use normalize:
>>> Decimal('100.2000').normalize()
Decimal('100.2')
>> Decimal('0.2000').normalize()
Decimal('0.2')
But this works different for numbers with leading zeros in sharp part:
>>> Decimal('100.0000').normalize()
Decimal('1E+2')
In this case we should use `to_integral':
>>> Decimal('100.000').to_integral()
Decimal('100')
So we could check if there's a fraction part:
>>> Decimal('100.2000') == Decimal('100.2000').to_integral()
False
>>> Decimal('100.0000') == Decimal('100.0000').to_integral()
True
And use appropriate method then:
def remove_exponent(num):
return num.to_integral() if num == num.to_integral() else num.normalize()
Try it:
>>> remove_exponent(Decimal('100.2000'))
Decimal('100.2')
>>> remove_exponent(Decimal('100.0000'))
Decimal('100')
>>> remove_exponent(Decimal('0.2000'))
Decimal('0.2')
Now we're done.
Use the format specifier %g. It seems remove to trailing zeros.
>>> "%g" % (Decimal('2.5') * 10)
'25'
>>> "%g" % (Decimal('2.5678') * 1000)
'2567.8'
It also works without the Decimal function
>>> "%g" % (2.5 * 10)
'25'
>>> "%g" % (2.5678 * 1000)
'2567.8'
I ended up doing this:
import decimal
def dropzeros(number):
mynum = decimal.Decimal(number).normalize()
# e.g 22000 --> Decimal('2.2E+4')
return mynum.__trunc__() if not mynum % 1 else float(mynum)
print dropzeros(22000.000)
22000
print dropzeros(2567.8000)
2567.8
note: casting the return value as a string will limit you to 12 significant digits
Slightly modified version of A-IV's answer
NOTE that Decimal('0.99999999999999999999999999995').normalize() will round to Decimal('1')
def trailing(s: str, char="0"):
return len(s) - len(s.rstrip(char))
def decimal_to_str(value: decimal.Decimal):
"""Convert decimal to str
* Uses exponential notation when there are more than 4 trailing zeros
* Handles decimal.InvalidOperation
"""
# to_integral_value() removes decimals
if value == value.to_integral_value():
try:
value = value.quantize(decimal.Decimal(1))
except decimal.InvalidOperation:
pass
uncast = str(value)
# use exponential notation if there are more that 4 zeros
return str(value.normalize()) if trailing(uncast) > 4 else uncast
else:
# normalize values with decimal places
return str(value.normalize())
# or str(value).rstrip('0') if rounding edgecases are a concern
You could use :g to achieve this:
'{:g}'.format(3.140)
gives
'3.14'
This should work:
'{:f}'.format(decimal.Decimal('2.5') * 10).rstrip('0').rstrip('.')
Just to show a different possibility, I used to_tuple() to achieve the same result.
def my_normalize(dec):
"""
>>> my_normalize(Decimal("12.500"))
Decimal('12.5')
>>> my_normalize(Decimal("-0.12500"))
Decimal('-0.125')
>>> my_normalize(Decimal("0.125"))
Decimal('0.125')
>>> my_normalize(Decimal("0.00125"))
Decimal('0.00125')
>>> my_normalize(Decimal("125.00"))
Decimal('125')
>>> my_normalize(Decimal("12500"))
Decimal('12500')
>>> my_normalize(Decimal("0.000"))
Decimal('0')
"""
if dec is None:
return None
sign, digs, exp = dec.as_tuple()
for i in list(reversed(digs)):
if exp >= 0 or i != 0:
break
exp += 1
digs = digs[:-1]
if not digs and exp < 0:
exp = 0
return Decimal((sign, digs, exp))
Why not use modules 10 from a multiple of 10 to check if there is remainder? No remainder means you can force int()
if (x * 10) % 10 == 0:
x = int(x)
x = 2/1
Output: 2
x = 3/2
Output: 1.5

How to format a float with a maximum number of decimal places and without extra zero padding?

I need to do some decimal place formatting in python. Preferably, the floating point value should always show at least a starting 0 and one decimal place. Example:
Input: 0
Output: 0.0
Values with more decimal places should continue to show them, until it gets 4 out. So:
Input: 65.53
Output: 65.53
Input: 40.355435
Output: 40.3554
I know that I can use {0.4f} to get it to print out to four decimal places, but it will pad with unwanted 0s. Is there a formatting code to tell it to print out up to a certain number of decimals, but to leave them blank if there is no data? I believe C# accomplishes this with something like:
floatValue.ToString("0.0###")
Where the # symbols represent a place that can be left blank.
What you're asking for should be addressed by rounding methods like the built-in round function. Then let the float number be naturally displayed with its string representation.
>>> round(65.53, 4) # num decimal <= precision, do nothing
'65.53'
>>> round(40.355435, 4) # num decimal > precision, round
'40.3554'
>>> round(0, 4) # note: converts int to float
'0.0'
Sorry, the best I can do:
' {:0.4f}'.format(1./2.).rstrip('0')
Corrected:
ff=1./2.
' {:0.4f}'.format(ff).rstrip('0')+'0'[0:(ff%1==0)]
From trial and error I think :.15g is what you want:
In: f"{3/4:.15g}"
Out: '0.75'
In f"{355/113:.15g}"
Out: '3.14159292035398'
(while f"{3/4:.15f}" == '0.750000000000000')
>>> def pad(float, front = 0, end = 4):
s = '%%%s.%sf' % (front, end) % float
i = len(s)
while i > 0 and s[i - 1] == '0':
i-= 1
if s[i - 1] == '.' and len(s) > i:
i+= 1 # for 0.0
return s[:i] + ' ' * (len(s) - i)
>>> pad(0, 3, 4)
'0.0 '
>>> pad(65.53, 3, 4)
'65.53 '
>>> pad(40.355435, 3, 4)
'40.3554'

Categories