如何确定小数部分是否可以精确地表示为Python浮点?
从Python中: 不幸的是,大多数小数不能精确地表示为 二元分数。结果是,一般来说,十进制 您输入的浮点数仅由二进制近似 实际存储在机器中的浮点数 我想知道如何检查给定的小数部分是否精确地表示为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 就在这一页上: 在今天的大多数机器上,浮点数是用二进制近似的
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]