简体   繁体   中英

Print floating point numbers with variable precision

I want to print floating point numbers which contain variable precision.

I have multiple numbers such as:

0.634564644534135499
0.0005462007746487777
0.028820785252590582
0.0018751147995774936
0.0075146048125540816
0.00046670455

I want to get the same numbers as output using print. I know that the number of decimal places can be fixed using print("{:.19f}".format(0.0005462007746487777)) but I don't want to make the number of decimal places fixed. Since different numbers will have different decimal places

Code

#!/usr/bin/env python3
 
number_1=0.634564644534135499
number_2=0.0005462007746487777
number_3=0.028820785252590582
number_4=0.0018751147995774936
number_5=0.0075146048125540816
number_6=0.00046670455

print("Number 1: ",number_1)
print("Number 2: ",number_2)
print("Number 3: ",number_3)
print("Number 4: ",number_4)
print("Number 5: ",number_5)
print("Number 6: ",number_6)

Actual Output:

Number 1:  0.6345646445341355
Number 2:  0.0005462007746487777
Number 3:  0.028820785252590582
Number 4:  0.0018751147995774936
Number 5:  0.0075146048125540816
Number 6:  0.00046670455

Required Output:

Number 1: 0.634564644534135499
Number 2: 0.0005462007746487777
Number 3: 0.028820785252590582
Number 4: 0.0018751147995774936
Number 5: 0.0075146048125540816
Number 6: 0.00046670455

What I don't understand is why Number 2 (which has higher precision) is being printed correctly but Number 1 losses its precision?

Fundamentally what you require is not possible with float objects, which are basically wrappers around C-doubles, so 64-bit floating point numbers.

There are several things going on here. There is the fundamental problem with mapping a decimal literal input in your source code:

0.634564644534135499

To an actual machine representation, which is not decimal, but binary.

Due to the inherent constraints of the 64-bit floating point format, multiple decimal inputs will be mapped to the same underlying representation:

>>> 0.634564644534135499 == 0.6345646445341355
True

Which is actually neither of those, the exact decimal is actually:

>>> import decimal
>>> decimal.Decimal(0.6345646445341355)
Decimal('0.6345646445341355246227976749651134014129638671875')
>>> decimal.Decimal(0.634564644534135499)
Decimal('0.6345646445341355246227976749651134014129638671875')

What is actually printed when you naively print(some_float) is going to be a representation which is guaranteed to map back to the same float that produced it if you enter it as a float decimal literal. In fact, since Python 3.1 CPython uses David Gray's algorithm for finding the shortest such representation that preserves the value.

So, as is often the case when encountering troubles due to the inherent limitation of float , try using decimal.Decimal . Remember, the input should be a string . The following script:

import decimal
number_1 = decimal.Decimal('0.634564644534135499')
number_2 = decimal.Decimal('0.0005462007746487777')
number_3 = decimal.Decimal('0.028820785252590582')
number_4 = decimal.Decimal('0.0018751147995774936')
number_5 = decimal.Decimal('0.0075146048125540816')
number_6 = decimal.Decimal('0.00046670455')

print("Number 1: ",number_1)
print("Number 2: ",number_2)
print("Number 3: ",number_3)
print("Number 4: ",number_4)
print("Number 5: ",number_5)
print("Number 6: ",number_6)

Prints:

Number 1:  0.634564644534135499
Number 2:  0.0005462007746487777
Number 3:  0.028820785252590582
Number 4:  0.0018751147995774936
Number 5:  0.0075146048125540816
Number 6:  0.00046670455

So here's a reference image of a number in general (taken off of the web from this link https://www.log2base2.com/number-system/float-to-binary-conversion.html ): 任何浮点数

Python uses each bit to store the integral part and the fractional part and uses 64 bits to store a floating point value. So if the integral part(absolute value) is high, it then it automatically means that the fractional part will have lesser bits for storage.

In the examples provided by you, since each value has integral part of 0, then the comparison can be done entirely on the fractional part.

So for this case, we will just look at the values that are in the fractional parts.

In the first example (0.634564644534135499) the number of values after the decimal point although are lesser than in the second case (0.0005462007746487777), but the number of bits required are more in the first case than in the second case. So the value stored will be rounded off to ensure that the number of bits are as per the requirement in python.

So to change this, one way that I can think of is to store the values within quotes in the form of a string. It will work, but assuming that you'll be getting the data from elsewhere, not sure if this is very good:

number_1="0.634564644534135499"
# number_3=0.028820785252590582
# number_4=0.0018751147995774936
# number_5=0.0075146048125540816
# number_6=0.00046670455

print("Number 1: ",number_1)
# print("Number 2: ",number_2)

Another way is to use decimal.Decimal('0.634564644534135499'). In case I haven't answered your doubt, as to why does it happen that way let me know please, I'll try and explain better.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM