来自Python tutorial:
不幸的是,大多数小数部分不能完全表示为 二进制分数。结果是,一般来说,十进制 您输入的浮点数仅由二进制近似 实际存储在机器中的浮点数。
我想知道如何检查给定的小数部分是否完全表示为Python float
。例如,0.25
可以恰好表示0.1
可以&#t; t:
>>> 0.1 + 0.1 + 0.1 == 0.3
False
>>> 0.25 + 0.25 + 0.25 == 0.75
True
答案 0 :(得分:3)
在那页上:
在今天的大多数机器上,使用二进制来近似浮点数 分数使用前面的53位开头的分子 最重要的一点,分母作为两个权力。
因此,对于小数部分可以精确表示为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
答案 1 :(得分:3)
您可以使用fractions
module检查是否可以表示给定的分数:
from fractions import Fraction
def can_be_represented(num, den):
f = Fraction(num, den)
return Fraction.from_float(float(f)) == f
因为浮点数使用二进制分数,所以很快就会发现这可以简化为检查一个2的幂的分母:
def can_be_represented(num, den):
f = Fraction(num, den)
return f.denominator & (f.denominator - 1) == 0
但是,这不会对分子进行任何边界检查,通过与sys.float_info
中的信息进行比较来添加边界检查:
import sys
def can_be_represented(num, den):
f = Fraction(num, den)
return (
# denominator is a power of 2
f.denominator & (f.denominator - 1) == 0 and
# numerator exponent can be represented
f.numerator.bit_length() <= sys.float_info.max_exp and
# numerator significant bits can be represented without loss
len(format(f.numerator, 'b').rstrip('0')) <= sys.float_info.mant_dig
)
以上版本测试:
上述优化但不易阅读的版本是:
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)
)
答案 2 :(得分:1)
在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]]
和
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]
当然它不是Python,但它是相同的底层浮点,所以不应该那么难翻译......