【发布时间】:2013-06-28 14:03:24
【问题描述】:
假设我在给定的范围中有一个位置pos,这样:
0 pos 范围
范围内的这个位置可以包含在两种不同的上下文中,一种是范围是整数值,即 pos range 31 sup>,另一个范围是长整数,即最大 pos range 63。如果我想在这些上下文之间移动,我需要将位置缩放到新范围,以便正确地向下舍入到最接近的(长)整数值。所以,从技术上讲,我想做的就是:
pos new = floor( pos old * range新的 / 范围旧的 )
不幸的是,这种直截了当的方法并不能解决问题,因为它要么溢出(如 pos old * range new 可以大到 ~294) 如果我先做乘法或如果我先做除法会给我舍入错误。使用浮点值进行数学运算通常也无济于事,因为它们不能提供足够的精度位,因此也可能导致不正确的舍入(我只有双精度可用)。
我找到了一种从整数范围正确缩放到长整数范围的方法:
public long scaleUp(int oldPos, int oldRange, long newRange) {
return (newRange / oldRange) * oldPos +
(newRange % oldRange) * oldPos / oldRange;
}
这可确保计算在任何时候都不会超出长整数的限制,也不会因过早舍入而降低精度(模数捕获在第一次除法中舍入丢失的部分)。
我现在想弄清楚的是一种反向缩放的方法:
public int scaleDown(long oldPos, long oldRange, int newRange) {
return ??? ;
}
不确定这是否应该比其他功能更困难,但不知何故我没有看到它。
几点说明:
- 我想避免使用浮点运算,因为我总是很难说服自己,由于四舍五入,在某些极不常见的情况下,给定公式确实不可能产生意外结果
- 我宁愿不使用 BigInteger 库
- 虽然这里的代码示例是 Java,但这确实是一个与语言无关的问题
【问题讨论】:
-
它比您想象的更特定于语言:IIRC java 使得使用基本工具(例如计算数字的前导零或获得两个 64- 的 128 位乘积)变得更加困难/低效位整数。甚至可以做无符号算术! (更不用说某些语言内置了任意精度的整数;很难想象 python 实现可能比
p * r // R更好)
标签: integer precision long-integer integer-overflow