现在再来研究参数是整数的情况。
首先研究整数大于sys.float_info.max的情况。
>>>float(int("17976931348623157"+"0"*(308-16))) #最大整数
1.7976931348623157e+308
>>>float(int("17976931348623158"+"0"*(308-16)))
1.7976931348623157e+308
>>>float(int("17976931348623159"+"0"*(308-16)))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float
>>>float("17976931348623159"+"0"*(308-16))
inf
>>>float(int("1"+"0"*309))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float
>>>float("1"+"0"*309)
inf
从上面的结果中可知:如果浮点数大到已不能用sys.float_info.max来表示,就会抛出OverflowError异常,这个与字符串直接转换不一样(直接转换是inf)。
练习题1:下面的运算如果不抛出异常,请写出结果。拷贝运行验证。
>>>float(int("-17976931348623157"+"0"*(308-16)))
?
>>>float(-int("17976931348623158"+"0"*(308-16)))
?
>>>float(int("-17976931348623159"+"0"*(308-16)))
?
>>>float("-17976931348623159"+"0"*(308-16))
?
>>>float(-int("10"+"0"*308))
?
>>>float("-10"+"0"*308)
?
这样,在最大忠实数(9007199254740991)和最大整数(17976931348623157000...292个...000)之间的整数在转换时不会抛出异常,但可能会有精度损失。
由于尾数的最大位数是53,那么以二进制来算,64位浮点数的最大精度是53。如果一个整数转为二进制后,从0位开始,从左到右,如果最后一个1的位置已超过52,那么这个数在转换后就会失去部分精度。
>>>num = int("1011"+"01"*26,2)
>>>num
51040795776865621
>>>float_num = float(num)
>>>float_num
5.1040795776865624e+16
>>>new_num = int(float_num)
>>>new_num
51040795776865624
>>>bin(num)
'0b10110101010101010101010101010101010101010101010101010101'
>>>bin(new_num)
'0b10110101010101010101010101010101010101010101010101011000'
例1 以二进制计算精度,整数12345678901987654320转为浮点数后失去多少精度。
分析:把未转换和转换的数都转化为二进制字符串,用strip('0')消除后面的‘0’,长度相减就是。
程序代码(文本代码附录1):
运行结果:
练习题2:随机生成一个十进制十九位的整数,测试转浮点数后的精度损失。
例2 计算浮点数字符串“1.988744783456335472”,用float()转为浮点数后的二进制精度损失。
分析:与整数的精度损失相同,忽略小数点,转整数后计算。
程序代码(文本代码附录2):
运行结果:
练习题3:计算浮点数字符串“2.925294167395742728”,用float()转为浮点数后的二进制精度损失。
可见,超过sys.float_info.dig(15)位的整数转浮点数后多数情况会有精度损失。
调用方式4:普通对象参数,float(objNum)。
优先查找对象参数中的__float__()方法,如果__float__()方法没定义,则查找__index__()方法,如果都没定义,就抛出TypeError异常。
程序代码(文本代码附录3):
运行结果:
练习题4:写出下面程序的打印结果,拷贝源代码(附录4)验证。
附录1:
#损失二进制精度计算
num=12345678901987654320 #原整数
float_num = float(num) #转为浮点数
new_num = int(float_num) #转回整数
s1=bin(num) #原整数转二进制序列
s2=bin(new_num)
print(num)
print(s1)
print(new_num)
print(s2)
s1=s1.strip('0') #去后面的0
s2=s2.strip('0')
pd=len(s1)-len(s2) #精度差
print("精度损失:", pd)
附录2:
#浮点字符串转换精度损失
strNum='1.988744783456335472' #原浮点数字符串
new_strNum=strNum.replace(".","") #去小数点
num = int(new_strNum) #
float_num = float(num) #转为浮点数
d_float_num = float(strNum) #直转浮点数
print(float_num)
print(d_float_num)
new_num = int(float_num) #转回整数
s1=bin(num) #原整数转二进制序列
s2=bin(new_num)
print(num)
print(s1)
print(new_num)
print(s2)
s1=s1.strip('0') #去后面的0
s2=s2.strip('0')
pd=len(s1)-len(s2) #精度差
print("精度损失:", pd)
附录3:
#浮点数对象
class Default:
pass
class FloatFun:
def __float__(self):
return 1.
class IndexFun:
def __index__(self):
return 2
class IFFun:
def __index__(self):
return 2
def __float__(self):
return 1.
print(float(FloatFun()))
print(float(IndexFun()))
print(float(IFFun()))
print(float(Default()))
附录4:
#浮点数对象练习题
class FTest:
def __init__(self,num):
self.num=num
def __index__(self):
return self.num+1
def __float__(self):
return self.num-1.
print(float(FTest(10)))