奇怪?为什么 floor((n + t - 1) / t) 比 ceil(n / t) 更高效?(因为没有浮点转换带来的性能损耗)

为什么 (n + t - 1) // t 比 ceil(n / t) 更高效?

导言

在刷leetcode的时候,发现了用 (n + t - 1) / t替换ceil(n/t)从而带来的性能优化

原理:(因为没有浮点转换带来的性能损耗)

在处理数组分块、分页计算等场景时,我们经常需要计算向上取整的除法。例如,将长度为103的数组分成长度为10的块,需要计算ceil(103/10)=11

常见的实现方式有两种:

  1. 直接向上取整:math.ceil(n / t)
    • math.ceil(103/10)=11
  2. 整数运算模拟:(n + t - 1) // t(这里//表示纯整数除法)
    • (103+10-1)//t=11

虽然结果相同,但后者在多数情况下更高效(因为没有浮点转换带来的性能损耗)。

数学原理(太妙啦啦啦啦啦啦啦啦啦)

偏移量设计

选择t-1作为偏移量的原因:

  1. 当n能被t整除时​(余数r=0):

    • n = k*t
    • (n + t - 1) // t = (k*t + t - 1) // t = k + (t-1)//t = k(正确)
  2. 当n不能被t整除时​(余数r≥1):

    • n = k*t + r
    • (n + t - 1) // t = (k*t + r + t - 1) // t = k + (r + t - 1)//t = k + 1(正确)

示例验证

# 整除情况
(4 + 2 - 1) // 2 = 5 // 2 = 2  # 等同于ceil(4/2)
# 非整除情况
(5 + 2 - 1) // 2 = 6 // 2 = 3  # 等同于ceil(5/2)

性能分析

ceil(n / t)的问题

大多数语言在实现这个函数的时候,内部都会使用强制浮点运算

  1. 强制浮点运算​:

    • 整数→浮点转换
    • 浮点除法
    • 浮点取整

强制浮点运算会带来性能损耗

(n + t - 1) // t的优势

这里的//在python中表示纯整数除法

sum = (103+10-1)//10 = 11

在java或者C/C++中只要类型是int,计算除法的时候就会触发纯整数除法

int sum = (103+10-1)/10 = 11
  1. 纯整数运算​:

    • 直接使用CPU整数除法指令
    • 无类型转换开销

更稳定不受浮点精度限制,需要纯整数运算支持,例如下面的语言

语言特性差异

语言推荐写法原因
C/C++/Java(n + t - 1) / t整数除法直接截断
Python(n + t - 1) // t//避免浮点运算
JavaScript/TSMath.ceil(n / t)JS和TS中的所有除法都是浮点运算,使用Math.ceil可读性优先
高性能场景(n + t - 1) >> k (t=2^k)位运算最快

建议

  1. 优先考虑整数运算​:

    • 在支持整数除法的语言中使用(n + t - 1) // t
  2. 可读性与性能平衡​:

    • 在JS/TS等语言中,Math.ceil的可读性更佳
  3. 特殊场景优化​:

    • 当除数为2的幂次时,可用位运算进一步优化
  4. 避免过早优化​:

    • 非性能关键路径可优先考虑代码可读性

总结

(n + t - 1) // t通过巧妙的数学设计,在多数编程语言中实现了:

  • 更高效的纯整数运算
  • 避免浮点转换开销
  • 更好的大数稳定性

6666666666666666666

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值