【问题标题】:Round a x float to y with a reduced mantissa (significant) floating point使用减少的尾数(有效)浮点将 x 浮点数舍入到 y
【发布时间】:2019-01-10 16:37:30
【问题描述】:

我想了解如何舍入例如具有 23 位的 IEEE float32 并减少尾数(即 20,19)。 Python 中的逐步解决方案是可取的。

【问题讨论】:

  • stackoverflow.com/questions/46093123/… 可能是一个有用的起点
  • 你想要这样的东西吗? 1.00 --> '1' 1.20 --> '1.2' 1.23 --> '1.23' 1.234 --> '1.23' 1.2345 --> '1.23'
  • 您想要纯 Python 的答案还是可以使用 numpy 模块(在第一条评论链接中接受的答案中使用的常用第三方模块)?
  • 您是在问如何将有效数字的 24 位缩减为 20 位,如何决定是向上舍入还是向下舍入?或者,给定 Python 中的浮点值,如何提取有效数字,然后用修改后的值构造一个新的浮点值?或者只是如何实现一个将有效数舍入为 20 位的函数?这些是不同的问题。首先是关于指定功能。第二个是关于操纵 Python 实体。第三个可以通过 Veltkamp-Dekker 分裂完成,无需直接操作有效数字。

标签: python math floating-point


【解决方案1】:

这是一个仅使用基本 Python 和标准 math 模块的答案。

from math import frexp, ldexp

def roundbits(fval, nbits):
    """Return the floating-point value `fval` rounded to `nbits` bits
    in the significand."""
    significand, exponent = frexp(fval)
    scale = 2.0 ** nbits
    newsignificand = round(significand * scale) / scale
    return ldexp(newsignificand, exponent)

这里是解释。要将值舍入到其浮点表示的有效位中的nbits 位,首先获取有效位的位,然后对其进行缩放,使最高有效位紧随小数点之后,其他位紧随其后。这就是frexp 函数的作用。接下来,将该有效位乘以2**nbits,将我们想要的位数放在小数点之前,将不需要的位数放在小数点之后。 (对于nbits 的合理值,该比例值和乘法都将精确完成。)然后我们将该值四舍五入为最接近的整数,从而删除不需要的位。然后将该值除以2**nbits,它将最高有效位移回小数点之后。最后,使用新的有效数和旧的指数生成一个浮点数——这就是ldexp 函数所做的。

这个例程保持简单,所以它忽略了一些边缘情况。如果所需位数为负数、零或大于 Python 可以存储在其浮点值中的位数怎么办? Python 通常使用 double 类型,即整个浮点数使用 64 位,有效位使用 53 位(显式存储 52),但这并不能保证。我会把错误检查留给你。

如果你用

测试这个例程
for n in range(1, 52):
    print(n, roundbits(pi, n))

使用pi,二进制到53位,

11.00100100001111110110101010001000100001011010001100001000110100

结果是

1 4.0
2 3.0
3 3.0
4 3.25
5 3.125
6 3.125
7 3.15625
8 3.140625
9 3.140625
10 3.140625
11 3.140625
12 3.1416015625
13 3.1416015625
14 3.1416015625
15 3.1416015625
16 3.1416015625
17 3.1416015625
18 3.1415863037109375
19 3.1415939331054688
20 3.1415939331054688
21 3.141592025756836
22 3.1415929794311523
23 3.141592502593994
24 3.1415927410125732
25 3.1415926218032837
26 3.1415926814079285
27 3.141592651605606
28 3.141592651605606
29 3.141592651605606
30 3.1415926553308964
31 3.1415926534682512
32 3.1415926534682512
33 3.1415926534682512
34 3.141592653701082
35 3.1415926535846666
36 3.1415926535846666
37 3.1415926535846666
38 3.1415926535846666
39 3.1415926535919425
40 3.1415926535883045
41 3.1415926535901235
42 3.1415926535901235
43 3.1415926535896688
44 3.141592653589896
45 3.1415926535897825
46 3.1415926535897825
47 3.1415926535897825
48 3.1415926535897967
49 3.1415926535897967
50 3.141592653589793
51 3.141592653589793

【讨论】:

  • 这是一个有趣的想法,但我想知道它是否真的总是按照作者的意愿行事,即是否可以保证 round 步骤将完全删除所有不需要的位(例如不会在尾数末尾留下一些其他垃圾)?
  • @SergGr:我不确定这是否完全符合 OP 的要求,但这确实满足了简短的问题描述。 round 步骤保证会产生一个整数,因此不需要的位肯定会消失。我不确定 OP 是否希望四舍五入到更高的数量级(具有更大的指数),例如 pi 如果只需要一位,则四舍五入到 4 - 但这是最​​合理的事情去做。
猜你喜欢
  • 2012-11-08
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多