gpt4 book ai didi

python - 当转换为 Protobuf/C++ float 时,Python float 何时会失去精度?

转载 作者:太空狗 更新时间:2023-10-30 00:53:17 24 4
gpt4 key购买 nike

我对最小化从 Python 序列化的 protobuf 消息的大小很感兴趣。

Protobuf 有 float (4 字节)和 double (8 字节)。 Python 有一个 float 类型,它实际上是一个 C double,至少在 CPython 中是这样。

我的问题是:给定一个 Python 实例 float , 如果将值分配给 protobuf float,是否有一种“快速”的方法来检查该值是否会丢失精度(或者真的是 C++ float )?

最佳答案

您可以检查将 float 转换为十六进制表示;符号、指数和分数各有一个单独的部分。如果小数仅使用前 6 位十六进制数字(其余 7 位必须为零),并且第 6 位是偶数(因此最后一位设置)将您的 64 位 double float 适合 32 位单精度 float 。指数限制在 -126 到 127 之间的值:

import math
import re

def is_single_precision(
f,
_isfinite=math.isfinite,
_singlepat=re.compile(
r'-?0x[01]\.[0-9a-f]{5}[02468ace]0{7}p'
r'(?:\+(?:1[01]\d|12[0-7]|[1-9]\d|\d)|'
r'-(?:1[01]\d|12[0-6]|[1-9]\d|\d))$').match):
return not _isfinite(f) or _singlepat(f.hex()) is not None or f == 0.0

float.hex() 方法非常快,比通过 struct 或 numpy 的往返更快;您可以在半秒内创建 100 万个十六进制表示:

>>> timeit.Timer('(1.2345678901e+26).hex()').autorange()
(1000000, 0.47934128501219675)

正则表达式引擎也非常快,并且在上面的函数中优化了名称查找,我们可以在大约 1.1 秒内测试 100 万个浮点值:

>>> import random, sys
>>> testvalues = [0.0, float('inf'), float('-inf'), float('nan')] + [random.uniform(sys.float_info.min, sys.float_info.max) for _ in range(2 * 10 ** 6)]
>>> timeit.Timer('is_single_precision(f())', 'from __main__ import is_single_precision, testvalues; f = iter(testvalues).__next__').autorange()
(1000000, 1.1044921400025487)

上面的代码之所以有效,是因为 float 的 binary32 格式为小数分配了 23 位。指数分配给 8 位(有符号)。正则表达式只允许设置前 23 位,并且指数在带符号的 8 位数字的范围内。

另见

但这可能不是您想要的!以 1/3 或 1/10 为例。两者都是需要浮点值近似的值,并且都未通过测试:

>>> (1/3).hex()
'0x1.5555555555555p-2'
>>> (1/10).hex()
'0x1.999999999999ap-4'

您可能不得不采用启发式方法;如果您的十六进制值在分数的前 6 位全为零,或者指数超出 (-126, 127) 范围,则转换为 double 会导致太多损失。

关于python - 当转换为 Protobuf/C++ float 时,Python float 何时会失去精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48505685/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com