python-浮点数,复数,分数以及小数 通过前两章的学习相信都对整数以及内存表示有了清晰的认知这篇我们来谈谈除整数以外的数字。1浮点数python不像C/C或者Java那样把浮点数分为单精度和双精度在python中浮点定义很简单就是带小数点的数就是浮点数而且浮点的实现方式和C语言双精度是一样的。看如下代码a 1. b 1.45 c 3.4e-10 d 4e6 e 4.0e5 print(a{0},b{1},c{2},d{3},e{4}.format( a,b,c,d,e)) #输出a1.0,b1.45,c3.4e-10,d4000000.0,e400000.0这段代码很好的说明了浮点数的书写形式a说明如果数字后面带个点即便是点后面没有别的数字了这也是个浮点数cde都是采用科学计数的方式通过打印的d的值可以看出即便书写没有小数但是打印的值还是带了小数这说明只要是采用科学技术法这个数就是浮点数。观察这个c很奇怪它的打印形式和书写形式一模一样这是和python的打印方式有关如果这个小数位数后面超过3个0那么就会用科学计数法打印出来。例如c3.4e-4则会打印0.00034如果是c3.4e-5则打印3.4e-5这是个很有趣的细节。看一下下面这个代码片段a 0.1 0.1 0.1 - 0.3 print(a{}.format(a))#a5.551115123125783e-17是不是对结果有点惊讶按照我们的思路应还是0.0才对。实际上这说明浮点数在内存中的表示是不精确的所以才会出现这种似是而非的情况所以我们在对浮点数计算的时候要相当小心尤其是两个相同的值相减的情况结果可能不是0。说到这里就引出了我们接下来要说的两个类型分数和小数。2分数相信大家都不是九年制义务教育漏网之鱼说到分数那肯定是耳熟能详。但是在代码的世界分数和我们想象的可能有点不同。看下下面这段代码a 1/3这个是分数么看着很像其实1/3只是个表达式在python3.0之后这个值表示真除结果是0.3333333333333333这还是个浮点数。其实要书写分数没那么简单我们需要引用一个模块franctions看如下代码from fractions import Fraction a Fraction(1, 3) b Fraction(2, 6) c a b d c a print(a{0},b{1},c{2},d{3}.format(a, b, c, d)) #结果a1/3,b1/3,c2/3,d1这段代码引入了一个Fraction类这个类需要两个参数第一个是分子第二个是分母我们看打印出的结果是不是和我们想象的一样我们发现分数类型可以相加其实加减乘除也都可以这是因为python对操作符进行了重载后续的学习中我们会学习如何重载操作符。学过Java的人都知道java不允许用户重载操作符但是学过C对这个并不陌生因为C也允许重载操作符。另外Fraction还支持字符串浮点数作为参数例如Fraction(.25)会打印出1/4。分数精确表示数固然很有意义但是在实际运用的过程中像0.1 0.1 0.1 - 0.3 这种事情会真的发生而且用分子和分母表示数可能只是在数学计算中现实中我们可能更喜欢直接用0.1这样的形式例如这个蔬菜0.3元一斤我们有三个0.1元最后是不是要找钱计算机就会根据这个公式0.1 0.1 0.1 - 0.3来计算需不需要找零如果按照浮点数计算得到非零的值这显然是不合适的。这就引出了我们另外一个类型小数。3小数小数也需要引用python的一个模块decimal我们知道到浮点数的精度不是固定的所以才会导致0.1 0.1 0.1 - 0.3 结果不为零的情况而小数的精度是固定的所以计算不会出现我们意料之外的情况。看一下下面这段代码from decimal import Decimal a Decimal(0.1) Decimal(0.1) Decimal(0.1) - Decimal(0.3) print(a {}.format(a)) #结果print(a {}.format(a))首先我们用decimal引入Decimal类这个类需要一个字符串作为参数我们看最后的打印结果是0.0这是因为上面的表达式都是保留一位小数这个精度是1计算的结果精度也是1所以我们得到了我们想要的结果。 但是Decimal的精度会根据情况扩展如下面代码所示from decimal import Decimal a Decimal(0.10) Decimal(0.1) Decimal(0.1) - Decimal(0.3) print(a {}.format(a)) #结果a 0.00精度变成了2这说明小数精度会扩展成精度最大的那个小数的精度。再看下面这个情况from decimal import Decimal a Decimal(1) / Decimal(7) print(a {}.format(a)) #结果a 0.1428571428571428571428571429这一看是不是有点摸不着头脑这其实也合理因为1/7本身就是除不尽的上面说小数的精度会扩展因为除不尽所以最后实际上是表示了最大的精度但是这个和浮点数的非固定精度还是不同的看如下代码from decimal import Decimal a Decimal(1) / Decimal(7) Decimal(1) / Decimal(7) Decimal(1) / Decimal(7) - \ Decimal(1) / Decimal(7) - Decimal(1) / Decimal(7) - Decimal(1) / Decimal(7) b 0.1 0.1 0.1 - 0.1 - 0.1 - 0.1 print(a {0},b {1}.format(a, b)) #结果a 0E-28,b 2.7755575615628914e-17a的结果是0E-28这个是不是有点熟悉为什么是-28呢上面的代码1/7的时候我们看到的结果a 0.1428571428571428571428571429这个精度就是28位所以根据上面我们说小数会扩展精度所以这个结果也是28位的精度虽然其结果就是0而对于b用浮点数来计算发现是非0的数这个再次验证小数的精度是固定的而浮点数的精度不是固定的。那么有时候我们不想要这么大的精度怎么办呢看如下代码import decimal from decimal import Decimal a Decimal(1)/Decimal(7) decimal.getcontext().prec 4 b Decimal(1)/Decimal(7) print(a {0},b {1}.format(a, b)) #结果a 0.1428571428571428571428571429,b 0.1429可以看出将精度设置为4的时候b保留了四位小数而且是通过四舍五入的形式。有时候我们只是对某段代码想自定义精度出了这个代码片段又想恢复默认的精度一种方法就是再把之前的精度设置为回去通过之前的代码知道默认的精度是28所以可以将prec设置为28即可但是有时候我们不想这么麻烦可以通过上下文管理器来做。如下面代码所示import decimal from decimal import Decimal with decimal.localcontext() as cx: cx.prec 4 b Decimal(1)/Decimal(7) a Decimal(1)/Decimal(7) print(a {0},b {1}.format(a, b))这段代码我们只是稍稍的调整了一下顺序将变量a的赋值放在了下面我们通过with语句使得精度的设置只在with的语句块中生效这样a的精度还是默认的精度关于with这里不展开说了后面我会专门说这个。4复数复数其实就是一个实部虚部目前来看还我还没有遇到到需要用复数运算的场景这里就简单的介绍下请看下面的代码a 1 2j b a * a print(a{0},b{1}.format(a, b)) #结果a(12j),b(-34j)上面代码定义了一个复数a其中实部为1虚部为2j其中j是代表虚部的标志b是a和a的乘积这个和数学上的运算是一样的这里就不再说了。到这里我们就完成了浮点数小数分数以及复数的介绍。这些类型包括前面所讲的类型之间是如何运算的呢以及这些类型有什么关键字和类来表示呢下一章我们再详细谈这个问题。