四舍五入除以2的幂

问题描述

| 我正在从教科书中实现量化算法。我的工作很正常,除了四舍五入时出现一个错误。这是教科书必须说的:   可以通过将偏移量和右移p位位置来对“ 0”进行舍入除法 现在,我对正确的转变有所了解,但是他们在谈论什么偏移呢? 这是我的示例代码:
def scale(x,power2=16):
    if x < 0:
        return -((-x) >> power2)
    else:
        return x >> power2
def main():
    inp = [ 12595827,-330706,196605,-387168,-274244,377496,-241980,-545272,-196605,24198,193584,104858,424683,-40330,41944 ]
    expect = [ 192,-5,3,-6,-4,5,-3,-8,1,6,0 ]
    actual = map(scale,inp)
    for i in range(len(expect)):
        if actual[i] == expect[i]:
            continue
        print \'inp: % 8d expected: % 3d actual: % 3d err: %d\' % (inp[i],expect[i],actual[i],expect[i] - actual[i])
if __name__ == \'__main__\':
    main()
我正在检查是否有负输入,因为将负整数移位似乎与实现有关。 我的输出:
inp:   196605 expected:   3 actual:   2 err: 1
inp:  -387168 expected:  -6 actual:  -5 err: -1
inp:  -196605 expected:  -3 actual:  -2 err: -1
inp:   196605 expected:   3 actual:   2 err: 1
inp:   193584 expected:   3 actual:   2 err: 1
教科书中提到的偏移量是多少,如何使用它来消除此错误?     

解决方法

班次将被截断。移位是二进制运算符进行操作。我在这里用方括号表示基数:
196605[10] = 101111111111111111[2]
101111111111111111[2] >> 16[10] = 10[2] = 2[10]
要进行正确的舍入,您需要在进行移位之前添加一半的除数。
101111111111111111[2] + 1000000000000000[2] >> 16[10] = 110111111111111111[2] >> 16[10] = 11[2] = 3[10]
    ,将p移位可除以2 ^ p向下舍入(截断)。 如果要除以2 ^ p但四舍五入到最接近的整数,请执行以下操作:
shift-right by (p-1)
add 1
shift-right 1
在您的代码中:
def scale(x,power2=16):
    if x < 0:
        return -((((-x) >> (power2-1)) + 1) >> 1)
    else:
        return ((x >> (power2-1)) + 1) >> 1
    ,令人怀疑的是,您的算法实际上不是四舍五入的,而是截断除法。更重要的是,您的教科书中也有错误。因此,即使您修复算法,也不会获得预期的结果。 为了确认结果实际上有缺陷,您可以尝试使用正确的基于浮点数的舍入除法函数运行代码:
def scale(x,power2=16):
    divider = float(1<<power2)
    result = round(x/divider)
    return result
但是我们得到以下错误:
inp:   377496 expected:   5 actual:   6 err: -1
inp:  -241980 expected:  -3 actual:  -4 err: 1
inp:   104858 expected:   1 actual:   2 err: -1
inp:   -40330 expected:   0 actual:  -1 err: 1
inp:    41944 expected:   0 actual:   1 err: -1
通过计算舍入取整的正确结果,我们可以确认这些期望实际上是错误的:
377496 / 65536 = 5,7601 -> should round to 6
104858 / 65536 = 1,600 -> should round to 2
-241980 / 65536 = -3,692 -> should round to -4
104858 / 65536 = 1,600 -> should round to 2
-40330 / 65536 = -0,6154 -> should round to -1
41994 / 65536 = 0,641 -> should round to 1
因此,如果您真正想要的是四舍五入的除法,则期望值列表应为:
expect = [ 192,-5,3,-6,-4,6,-8,-3,2,-1,1 ]
    ,“预期”答案与可能的四舍五入方法之一(向下,最接近,向上)不一致,在考虑负股息带来的复杂性之前,从正股息中可以明显看出这一点。
dividend  exp  float div
   24198    0   0.3692322 DN
   41944    0   0.6400146 D
  104858    1   1.6000061 D
  193584    3   2.9538574  NU
  196605    3   2.9999542  NU
  377496    5   5.7601318 D
  424683    6   6.4801483 DN
12595827  192 192.1970673 DN
因此,下降得到8分中的6分,最接近得到5分,上升仅2分。 什么教科书?现在是“名字\'n \'耻辱”的时间! 经过进一步实验后更新: 如果在将截断除以65536之前添加了8192,则会得到“预期”结果。 (512,...,32768)中的2的其他幂没有相同的效果。 将其描述为增加偏移量以使向下取整偏向有点不幸。 重写:该对象将四舍五入为NEAREST整数,但会偏向零(较小的绝对整数)。四舍五入到最接近的值可以通过在截断除法之前加32768来完成。使用比32768小的“偏移”可获得所需的偏置效果。如果偏移量是2的幂,例如2 ** k,则可以通过以下方式完成:移位k位,加1,移位16-k位。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...