如何确定小数部分是否可以精确地表示为Python浮点?

如何确定小数部分是否可以精确地表示为Python浮点?,python,floating-point,floating-accuracy,Python,Floating Point,Floating Accuracy,从Python中: 不幸的是,大多数小数不能精确地表示为 二元分数。结果是,一般来说,十进制 您输入的浮点数仅由二进制近似 实际存储在机器中的浮点数 我想知道如何检查给定的小数部分是否精确地表示为Pythonfloat。例如,0.25可以精确表示,而0.1不能: >>> 0.1 + 0.1 + 0.1 == 0.3 False >>> 0.25 + 0.25 + 0.25 == 0.75 True 就在这一页上: 在今天的大多数机器上,浮点数是用二进制近似的

从Python中:

不幸的是,大多数小数不能精确地表示为 二元分数。结果是,一般来说,十进制 您输入的浮点数仅由二进制近似 实际存储在机器中的浮点数

我想知道如何检查给定的小数部分是否精确地表示为Python
float
。例如,
0.25
可以精确表示,而
0.1
不能:

>>> 0.1 + 0.1 + 0.1 == 0.3
False
>>> 0.25 + 0.25 + 0.25 == 0.75
True
就在这一页上:

在今天的大多数机器上,浮点数是用二进制近似的 使用以 最高有效位,分母为二的幂

因此,对于精确表示为
float
的十进制分数,它必须是分母为2的幂的分数:

>>> 1/10 + 1/10 + 1/10 == 3/10  # 0.1 + 0.1 + 0.1
False
>>> 1/4 + 1/4 + 1/4 == 3/4      # 0.25 + 0.25 + 0.25
True
您可以使用检查是否可以表示给定分数:

from fractions import Fraction

def can_be_represented(num, den):
    f = Fraction(num, den)
    return Fraction.from_float(float(f)) == f
因为浮点数使用二进制分数,所以您很快就会发现,这可以简化为检查二次幂的分母:

def can_be_represented(num, den):
    f = Fraction(num, den)
    return f.denominator & (f.denominator - 1) == 0
但是,这不会对分子进行任何边界检查,请通过比较以下信息添加边界检查:

导入系统 可以表示def(数字、数据): f=分数(数值,单位) 返回( #分母是2的幂 f、 分母和(f.分母-1)==0和 #分子指数可以表示
f、 numerator.bit_length()在Squeak Smalltalk中,您可以找到以下方法:

Fraction>>isAnExactFloat
    "Answer true if this Fraction can be converted exactly to a Float"
    ^ denominator isPowerOfTwo
        and: ["I have a reasonable significand: not too big"
            numerator highBitOfMagnitude <= Float precision
                and: ["I have a reasonable exponent: not too small"
                    Float emin + denominator highBitOfMagnitude <= Float precision]]
Fraction>>isAnExactFloat
“如果此分数可以精确转换为浮点,则回答true”
^分母isPowerOfTwo
和:[“我有一个合理的含义:不太大”
分子高比特数是下一个实浮点数
“如果此整数可以精确转换为浮点,则回答true”
|h|

(h:=自高比特数)如果它是2的幂的一小部分?我更新了我的答案,通过测试命名器是否适合浮点的指数和分数二进制表示形式,来涵盖Python的具体浮点实现。在哪里缺少这些比特,以及删除“已接受”标记的原因可能是什么?:-)如果目标是检查某些东西是否可以表示为Python浮点(而不是简单地用任意精度的二进制浮点表示),那么检查分母是否是二的幂是不够的:还需要检查分子是否有适当的边界(并且避免下溢和溢出)对于一个简单的反例,考虑案例<代码> 10 ** 23 < /代码> @ @马克迪克金森:对,所以简化不适用。我现在添加了分子长度和移位距离的边界检查。分子的大小必须小于2 ^ 53,指数必须在范围内。(在非规范的情况下可能改变分子的最大值)。问题似乎是关于一个充分条件,这个答案提供的必要条件有点弱。
def can_be_represented(num, den,
                      _mexp=sys.float_info.max_exp,
                      _mdig=sys.float_info.mant_dig):
    f = Fraction(num, den)
    num, den = f.numerator, f.denominator
    numbl = num.bit_length()
    return (
        # denominator is a power of 2
        den & (den - 1) == 0 and
        # numerator exponent can be represented
        numbl <= _mexp and
        # numerator significant bits can be represented without loss
        (numbl <= _mdig or num << numbl - _mdig >> numbl - _mdig == num)
    )
Fraction>>isAnExactFloat
    "Answer true if this Fraction can be converted exactly to a Float"
    ^ denominator isPowerOfTwo
        and: ["I have a reasonable significand: not too big"
            numerator highBitOfMagnitude <= Float precision
                and: ["I have a reasonable exponent: not too small"
                    Float emin + denominator highBitOfMagnitude <= Float precision]]
Integer>>isAnExactFloat
    "Answer true if this Integer can be converted exactly to a Float"
    | h |
    (h := self highBitOfMagnitude) <= Float precision
        ifTrue: [^ true].
    ^ h - 1 <= Float emax
        and: [h - self abs lowBit < Float precision]