Python Decimal too many digits - python

I tried creating a temperature converter below:
from decimal import *
getcontext().prec = 10
celsius = Decimal(12)
fahrenheit = celsius*9/5+32
kelvin = celsius+Decimal(273.15)
romer = celsius*21/40+Decimal(7.5)
When converted to a string, fahrenheit returns 53.6 and romer returns 13.8, both with no additional decimal places. However, kelvin returns 285.1500000. (This isn't even 285.1500001). How do I make sure it returns just enough places, i.e. 285.15? I assume it is not a problem with adding floating decimals because romer is fine.

Do simple
from decimal import *
getcontext().prec = 10
celsius = Decimal(12)
fahrenheit = celsius*9/5+32
kelvin = round(celsius+Decimal(273.15), 2) #if you need more then 2 digit replace 2 with other number
romer = celsius*21/40+Decimal(7.5)

To make it simple, you can use the built in round() function. It takes in two params, the number required to be rounded and the number of decimals to be rounded.
kelvin = round(celsius+Decimal(273.15), 2)
Here 285.1500000 will be rounded to 2 decimal place 285.15. Other method like str.format(), trunc(), round_up(), etc are also available.

You might be able to use str.format(). For example:
formatted_kelvin = "{:.2f}". format(kelvin)
So, if you printed this, it would print only 2 decimal places.

Related

Python Single Decimal

When I enter this code the answer ends with 2 characters behind the decimal. How do I make this only have 1 number behind it?
tempature=float(input("Enter the temp(F):"))
formant_tempature = f"{tempature:2f}"
print(round(((int(tempature)-32)*5/9)+273.15,2))
When you used round function you have specified that you want two decimal places. Just replace 2 with a number 1.
print(round(((int(tempature)-32)*5/9)+273.15,1))
You are using the string formatting operator for that ( formant_tempature = f"{tempature:2f}" )
What about formant_tempature = f"{tempature:1f}"
Like if you want it to display 5 decimals, just change it to f"{tempature:5f}"
And so on.
And for the round method, change 2 to 1.
I'm not sure why you'd do any math just to present this rounded, when you can simply use an f-string to specify outputting the temperature with a single decimal place precision.
>>> temperature = 43.8934
>>> print(f"Temperature is {temperature:.1f} degrees")
Temperature is 43.9 degrees
>>> print(f"Temperature is {temperature * 1.8 + 32:.1f} degrees farenheit")
Temperature is 111.0 degrees farenheit

How do I make a float only show a certain amount of decimals

I have a float that has 16 decimal places, but I want it to be capped at 6, and if I ever get a float that has less than 6 decimals, I want it to add 0s until it has 6.
i.e.:
1.95384240549 = 1.953842
3.12 = 3.120000
I'm trying to generate a value based on a certain amount of demand an object has. Thanks!
To round to a certain amount of decimals you can use round()
Example:
round(1.95384240549,6) > 1.953842
And for more 0's after the decimal place you can use format():
format(3.12, '.6f') > '3.120000'
Note this is of type string
Read more here:
Rounding syntax
Format syntax
A bit more complex than the previous answer, but more consistent.
import math
def truncate(number, digits) -> float:
places = len(str(number)[str(number).find("."):])
if places > 6:
stepper = 10.0 ** digits
return math.trunc(stepper * number) / stepper
else:
return str(number) + "0"*(6 - places)
Examples: truncate(3.12 , 6) returns 3.120000 and truncate(1.95384240549, 6) returns 1.953842

Python increment float by smallest step possible predetermined by its number of decimals

I've been searching around for hours and I can't find a simple way of accomplishing the following.
Value 1 = 0.00531
Value 2 = 0.051959
Value 3 = 0.0067123
I want to increment each value by its smallest decimal point (however, the number must maintain the exact number of decimal points as it started with and the number of decimals varies with each value, hence my trouble).
Value 1 should be: 0.00532
Value 2 should be: 0.051960
Value 3 should be: 0.0067124
Does anyone know of a simple way of accomplishing the above in a function that can still handle any number of decimals?
Thanks.
Have you looked at the standard module decimal?
It circumvents the floating point behaviour.
Just to illustrate what can be done.
import decimal
my_number = '0.00531'
mnd = decimal.Decimal(my_number)
print(mnd)
mnt = mnd.as_tuple()
print(mnt)
mnt_digit_new = mnt.digits[:-1] + (mnt.digits[-1]+1,)
dec_incr = decimal.DecimalTuple(mnt.sign, mnt_digit_new, mnt.exponent)
print(dec_incr)
incremented = decimal.Decimal(dec_incr)
print(incremented)
prints
0.00531
DecimalTuple(sign=0, digits=(5, 3, 1), exponent=-5)
DecimalTuple(sign=0, digits=(5, 3, 2), exponent=-5)
0.00532
or a full version (after edit also carries any digit, so it also works on '0.199')...
from decimal import Decimal, getcontext
def add_one_at_last_digit(input_string):
dec = Decimal(input_string)
getcontext().prec = len(dec.as_tuple().digits)
return dec.next_plus()
for i in ('0.00531', '0.051959', '0.0067123', '1', '0.05199'):
print(add_one_at_last_digit(i))
that prints
0.00532
0.051960
0.0067124
2
0.05200
As the other commenters have noted: You should not operate with floats because a given number 0.1234 is converted into an internal representation and you cannot further process it the way you want. This is deliberately vaguely formulated. Floating points is a subject for itself. This article explains the topic very well and is a good primer on the topic.
That said, what you could do instead is to have the input as strings (e.g. do not convert it to float when reading from input). Then you could do this:
from decimal import Decimal
def add_one(v):
after_comma = Decimal(v).as_tuple()[-1]*-1
add = Decimal(1) / Decimal(10**after_comma)
return Decimal(v) + add
if __name__ == '__main__':
print(add_one("0.00531"))
print(add_one("0.051959"))
print(add_one("0.0067123"))
print(add_one("1"))
This prints
0.00532
0.051960
0.0067124
2
Update:
If you need to operate on floats, you could try to use a fuzzy logic to come to a close presentation. decimal offers a normalize function which lets you downgrade the precision of the decimal representation so that it matches the original number:
from decimal import Decimal, Context
def add_one_float(v):
v_normalized = Decimal(v).normalize(Context(prec=16))
after_comma = v_normalized.as_tuple()[-1]*-1
add = Decimal(1) / Decimal(10**after_comma)
return Decimal(v_normalized) + add
But please note that the precision of 16 is purely experimental, you need to play with it to see if it yields the desired results. If you need correct results, you cannot take this path.

Simple way to round floats when printing

I am working on a project where it has to take user inputs and do calculations.
What I am aiming for is the print to appear as
Inform the customer they saved 0.71 today
Not
Inform the customer they saved 0.7105000000000001 today
Is there something I can put into the same line of code with the print function to have it be rounded? Or do I have to modify each variable.
I can post my code if requested.
You can use the builtin round() function and float formatting:
>>> print "{0:0.2f}".format(round(x, 2))
0.71
Some Notes:
{0.2f} will format a float to 2 decimal places.
round(x, 2) will round up to 2 decimal places.
Side Note: round() is really necessary IHMO if you want to "round" the number before "display". It really depends on what you're doing!
round() is return the floating point value number rounded to ndigits digits after the decimal point. which takes as first argument the number and the second argument is the precision
no = 0.7105000000000001
print round(no, 2)
second solution:
print "%.2f" % 0.7105000000000001
use decimal instead of round()
from decimal import *
print(round(8.494,2)) # 8.49
print(round(8.495,2)) # 8.49
print(round(8.496,2)) # 8.5
print(Decimal('8.494').quantize(Decimal('.01'), rounding=ROUND_HALF_UP)) #8.49
print(Decimal('8.495').quantize(Decimal('.01'), rounding=ROUND_HALF_UP)) #8.50
print(Decimal('8.496').quantize(Decimal('.01'), rounding=ROUND_HALF_UP)) #8.50

How to print floating point numbers as it is without any truncation in python?

I have some number 0.0000002345E^-60. I want to print the floating point value as it is.
What is the way to do it?
print %f truncates it to 6 digits. Also %n.nf gives fixed numbers. What is the way to print without truncation.
Like this?
>>> print('{:.100f}'.format(0.0000002345E-60))
0.0000000000000000000000000000000000000000000000000000000000000000002344999999999999860343602938602754
As you might notice from the output, it’s not really that clear how you want to do it. Due to the float representation you lose precision and can’t really represent the number precisely. As such it’s not really clear where you want the number to stop displaying.
Also note that the exponential representation is often used to more explicitly show the number of significant digits the number has.
You could also use decimal to not lose the precision due to binary float truncation:
>>> from decimal import Decimal
>>> d = Decimal('0.0000002345E-60')
>>> p = abs(d.as_tuple().exponent)
>>> print(('{:.%df}' % p).format(d))
0.0000000000000000000000000000000000000000000000000000000000000000002345
You can use decimal.Decimal:
>>> from decimal import Decimal
>>> str(Decimal(0.0000002345e-60))
'2.344999999999999860343602938602754401109865640550232148836753621775217856801120686600683401464097113374472942165409862789978024748827516129306833728589548440037314681709534891496105046826414763927459716796875E-67'
This is the actual value of float created by literal 0.0000002345e-60. Its value is a number representable as python float which is closest to actual 0.0000002345 * 10**-60.
float should be generally used for approximate calculations. If you want accurate results you should use something else, like mentioned Decimal.
If I understand, you want to print a float?
The problem is, you cannot print a float.
You can only print a string representation of a float. So, in short, you cannot print a float, that is your answer.
If you accept that you need to print a string representation of a float, and your question is how specify your preferred format for the string representations of your floats, then judging by the comments you have been very unclear in your question.
If you would like to print the string representations of your floats in exponent notation, then the format specification language allows this:
{:g} or {:G}, depending whether or not you want the E in the output to be capitalized). This gets around the default precision for e and E types, which leads to unwanted trailing 0s in the part before the exponent symbol.
Assuming your value is my_float, "{:G}".format(my_float) would print the output the way that the Python interpreter prints it. You could probably just print the number without any formatting and get the same exact result.
If your goal is to print the string representation of the float with its current precision, in non-exponentiated form, User poke describes a good way to do this by casting the float to a Decimal object.
If, for some reason, you do not want to do this, you can do something like is mentioned in this answer. However, you should set 'max_digits' to sys.float_info.max_10_exp, instead of 14 used in the answer. This requires you to import sys at some point prior in the code.
A full example of this would be:
import math
import sys
def precision_and_scale(x):
max_digits = sys.float_info.max_10_exp
int_part = int(abs(x))
magnitude = 1 if int_part == 0 else int(math.log10(int_part)) + 1
if magnitude >= max_digits:
return (magnitude, 0)
frac_part = abs(x) - int_part
multiplier = 10 ** (max_digits - magnitude)
frac_digits = multiplier + int(multiplier * frac_part + 0.5)
while frac_digits % 10 == 0:
frac_digits /= 10
scale = int(math.log10(frac_digits))
return (magnitude + scale, scale)
f = 0.0000002345E^-60
p, s = precision_and_scale(f)
print "{:.{p}f}".format(f, p=p)
But I think the method involving casting to Decimal is probably better, overall.

Categories