06.python中数字:整数、浮点数

Python 中数字:整数、浮点数完全指南

本文档面向零基础新手,详细讲解 整数(int)浮点数(float) 的用法,并说明为什么会出现 0.1 + 0.2 ≠ 0.3 这类现象,以及如何用 decimalfractions 模块解决或避免这类问题。


第一部分:整数(int)

一、整数是什么?

整数 就是没有小数部分的数,可以是正数、负数或零。在 Python 里类型名是 int(integer 的缩写)。

a = 10
b = -5
c = 0
print(type(a), type(b), type(c))   # <class 'int'> <class 'int'> <class 'int'>

二、整数的写法

  • 直接写数字,不能有小数点
  • 可以加正负号
  • 数字中间不能有逗号(如 1,000 在 Python 里是错的,要写 1000
age = 18
count = -100
big = 1000000
zero = 0

三、整数的运算

运算符 含义 示例
+ 加法 10 + 3 → 13
- 减法 10 - 3 → 7
* 乘法 10 * 3 → 30
/ 除法 10 / 3 → 3.333…(结果是 float)
// 整除 10 // 3 → 3(只保留整数部分)
% 取余数 10 % 3 → 1
** 乘方 10 ** 2 → 100

示例:

a, b = 10, 3
print(a + b)    # 13
print(a - b)    # 7
print(a * b)    # 30
print(a / b)    # 3.3333333333333335(注意:结果是浮点数)
print(a // b)   # 3(整除)
print(a % b)    # 1(余数)
print(a ** b)   # 1000(10 的 3 次方)

整除与取余的常见用途:

# 判断奇偶
n = 7
print(n % 2 == 0)   # False,7 是奇数
print(8 % 2 == 0)   # True,8 是偶数

# 取个位、十位
num = 123
ge = num % 10        # 个位 3
shi = num // 10 % 10 # 十位 2
bai = num // 100    # 百位 1
print(ge, shi, bai) # 3 2 1

四、整数的类型转换

int() 可以把其他类型转成整数:

  • 浮点数转整数:直接截断小数部分(不四舍五入)
  • 字符串转整数:字符串必须是“整数的写法”
print(int(3.9))     # 3(截断,不是 4)
print(int(-3.9))    # -3
print(int("100"))   # 100
# print(int("3.14")) # 报错:不能直接转带小数点的字符串
# print(int("abc"))  # 报错:不是合法数字

第二部分:浮点数(float)

五、浮点数是什么?

浮点数 就是带小数点的数,用来表示小数。在 Python 里类型名是 float

x = 3.14
y = -0.5
z = 2.0
print(type(x))   # <class 'float'>

六、浮点数的写法

  • 带小数点:3.140.52.0
  • 科学计数法:1.5e2 表示 1.5×10² = 150.0,2e-3 表示 2×10⁻³ = 0.002
a = 3.14
b = 1.5e2        # 150.0
c = 2e-3         # 0.002
print(a, b, c)   # 3.14 150.0 0.002

七、浮点数的运算

运算符和整数一样:+-*///%**。只要参与运算的数里有浮点数,结果一般是浮点数。

print(10.0 + 3)    # 13.0
print(10 / 3)      # 3.3333333333333335
print(2.5 ** 2)    # 6.25

八、浮点数转整数 / 字符串转浮点数

# 浮点 → 整数(截断)
print(int(3.14))   # 3

# 字符串 → 浮点
print(float("3.14"))   # 3.14
print(float("1.5e2"))  # 150.0

第三部分:为什么 0.1 + 0.2 ≠ 0.3?

九、现象

在 Python 里你会看到:

print(0.1 + 0.1)   # 0.2
print(0.1 + 0.2)   # 0.30000000000000004
print(0.2 + 0.1)   # 0.30000000000000004
print(0.1 + 0.2 == 0.3)   # False

为什么 0.1 + 0.1 得到 0.2,而 0.1 + 0.2 却得到 0.30000000000000004?


十、原因简述(不用记细节,知道“会误差”即可)

  • 电脑用 二进制 存数,而我们写的是 十进制
  • 很多十进制小数(如 0.1、0.2)在二进制里是无限循环小数,无法精确表示。
  • 浮点数只能用有限位来存,所以会四舍五入/截断,产生微小误差。
  • 0.1、0.2 存进去时都已经有微小误差;相加时误差可能“露出来”,所以 0.1 + 0.2 显示成 0.30000000000000004。
  • 0.1 + 0.1 刚好在当前的表示方式下误差被“抵消”或舍入成 0.2,所以看起来是 0.2。

结论: 这不是 Python 的 bug,而是浮点数在计算机里的通病。做金额、精确小数时不要直接用 float,而要用下面说的 decimalfractions


第四部分:方法一 —— 使用 decimal 模块(推荐)

十一、decimal 是什么?

decimal 是 Python 自带的模块,提供 Decimal 类型,用十进制来存和算,可以控制小数位数舍入方式,适合金额、精确小数


十二、基本用法

步骤:

  1. 导入模块:from decimal import Decimal
  2. Decimal(“数字”) 创建数(建议用字符串,避免先把 0.1 变成 float 再转成 Decimal 又把误差带进来)
  3. 之后加减乘除和整数、浮点数类似
from decimal import Decimal

a = Decimal("0.1")
b = Decimal("0.2")
c = a + b
print(c)                    # 0.3
print(c == Decimal("0.3"))  # True
print(c == 0.3)  # False

为什么推荐用字符串?

# 不推荐:用浮点数构造,会把浮点误差带进来
a = Decimal(0.1)
print(a)   # 0.1000000000000000055511151231257827021181583404541015625

# 推荐:用字符串
a = Decimal("0.1")
print(a)   # 0.1

十三、设置小数位数和舍入方式:getcontext()

decimal 模块里的 getcontext() 可以设置精度(有效数字位数)和舍入方式

from decimal import Decimal, getcontext

# 设置保留 2 位小数(用于金额)
getcontext().prec = 6          # 有效数字位数(可选)
getcontext().rounding = "ROUND_HALF_UP"   # 四舍五入(可选)

a = Decimal("1.234")
b = Decimal("2.345")
c = a + b
print(c)   # 3.579

保留固定小数位:quantize()

from decimal import Decimal, ROUND_HALF_UP

price = Decimal("19.567")
# 保留 2 位小数,四舍五入
price = price.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
print(price)   # 19.57

常用舍入模式(了解即可):

  • ROUND_HALF_UP:四舍五入(0.5 向上)
  • ROUND_HALF_DOWN:0.5 向下
  • ROUND_FLOOR:向负无穷取整
  • ROUND_CEILING:向正无穷取整

十四、decimal 示例汇总

示例 1:精确的 0.1 + 0.2

from decimal import Decimal
a = Decimal("0.1")
b = Decimal("0.2")
print(a + b)   # 0.3

示例 2:金额计算(保留 2 位小数)

from decimal import Decimal, ROUND_HALF_UP
单价 = Decimal("19.99")
数量 = 3
总价 = 单价 * 数量
总价 = 总价.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
print("总价:", 总价)   # 总价: 59.97

示例 3:和整数、字符串混用

from decimal import Decimal
a = Decimal("10.5")
b = 2
print(a * b)   # 21.0(Decimal 和 int 可以运算)

第五部分:方法二 —— 使用 fractions 模块(适合分数运算)

十五、fractions 是什么?

fractions 是 Python 自带的模块,提供 Fraction 类型,用分子/分母的方式表示有理数,适合分数运算(如 1/3 + 1/6),结果可以保持为分数形式,避免浮点误差。


十六、Fraction 详细解释

16.1 什么是 Fraction?

Fraction 表示一个分数,即 分子/分母。例如 1/2、1/3、-2/5。
内部会自动约分,所以存储和运算都是精确的分数,不会出现 0.1+0.2 那种误差。

16.2 创建 Fraction

方式一:Fraction(分子, 分母)

from fractions import Fraction
a = Fraction(1, 2)    # 1/2
b = Fraction(3, 4)    # 3/4
print(a)   # 1/2
print(b)   # 3/4

方式二:Fraction(整数)
表示“整数/1”。

c = Fraction(5)      # 5/1,即 5
print(c)   # 5

方式三:Fraction(字符串)
字符串可以是 “1/2″、”0.5″、”3.14” 等。

d = Fraction("1/2")  # 1/2
e = Fraction("0.25") # 1/4
f = Fraction("3.14") # 157/50(自动转成最简分数)
print(d, e, f)

方式四:Fraction(浮点数)Fraction(Decimal)
从浮点数或 Decimal 构造。注意:从 float 构造时,会先把 float 转成分数,可能带有浮点误差。

# 从 float:可能不精确
g = Fraction(0.1)
print(g)   # 3602879701896397/36028797018963968(不是简单的 1/10)

# 从字符串更稳妥
h = Fraction("0.1")
print(h)   # 1/10

小结: 想要精确分数时,优先用 整数分子分母字符串(如 "1/3""0.1"),少用 Fraction(0.1) 这种从 float 构造的方式。

16.3 Fraction 的属性:分子和分母

.numerator.denominator 可以取出分子、分母(都是整数,且已约分到最简)。

from fractions import Fraction
a = Fraction(3, 6)   # 自动约分为 1/2
print(a)             # 1/2
print(a.numerator)   # 1
print(a.denominator) # 2

16.4 Fraction 的运算

支持 +-*/** 等,结果仍是 Fraction(或整数),保持精确。

from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(1, 6)
print(a + b)   # 1/2
print(a - b)   # 1/6
print(a * b)   # 1/18
print(a / b)   # 2

与整数、浮点数运算时,会得到 Fraction 或 float(根据类型提升规则)。

print(Fraction(1, 2) + 1)    # 3/2
print(Fraction(1, 2) + 0.5)   # 1.0(float)

16.5 转成小数或字符串

  • float(Fraction):转成浮点数(可能又有浮点误差)
  • str(Fraction):如 "1/2""3"
from fractions import Fraction
a = Fraction(1, 3)
print(float(a))   # 0.3333333333333333
print(str(a))     # 1/3

16.6 从浮点数构造:Fraction.from_float() / Fraction.from_decimal()

  • Fraction.from_float(x):等价于 Fraction(x),把 float 转成“最接近的”分数,可能分母很大。
  • Fraction.from_decimal(d):从 Decimal 转成 Fraction,若 Decimal 是精确的,Fraction 也精确。
from fractions import Fraction
from decimal import Decimal
# 从 float
f = Fraction.from_float(0.1)
print(f)   # 3602879701896397/36028797018963968
# 从 Decimal(推荐)
d = Decimal("0.1")
f = Fraction.from_decimal(d)
print(f)   # 1/10

十七、Fraction 示例汇总

示例 1:精确的 1/3 + 1/6

from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(1, 6)
print(a + b)   # 1/2

示例 2:避免 0.1 + 0.2 的误差

from fractions import Fraction
a = Fraction("0.1")   # 1/10
b = Fraction("0.2")   # 1/5
c = a + b
print(c)        # 3/10
print(float(c)) # 0.3

示例 3:分数运算后取分子分母

from fractions import Fraction
x = Fraction(7, 12) + Fraction(1, 12)
print(x)              # 2/3
print(x.numerator)    # 2
print(x.denominator)  # 3

第六部分:decimal 和 fractions 怎么选?

场景 建议
金额、价格、保留几位小数 decimal(方便 quantize 控制小数位)
分数运算、比例、精确有理数 fractions(Fraction)
一般科学计算、对误差不敏感 float 即可

可以混用: 例如用 Decimal 算金额,需要时再转成 Fraction 或 float。


第七部分:小结表

类型/模块 用途 注意
int 整数 / 得到 float;// 整除,% 取余
float 小数 有精度误差,金额/精确小数慎用
Decimal 精确十进制小数 建议 Decimal("0.1") 用字符串构造
Fraction 精确分数 建议用 Fraction(1,3)Fraction("0.1"),少用 Fraction(0.1)

为什么 0.1+0.1=0.2 而 0.1+0.2≠0.3?
浮点数用二进制存储,0.1、0.2 无法精确表示,有微小误差;不同组合下误差有时被舍入掉(像 0.2),有时会显示出来(如 0.30000000000000004)。
解决办法: 金额/精确小数用 decimal;分数、比例用 fractions(Fraction)。

发表评论