【问题标题】:Decompose a float into mantissa and exponent in base 10 without strings将浮点数分解为以 10 为底的尾数和指数,无需字符串
【发布时间】:2017-07-26 16:00:36
【问题描述】:

Python 库或 numpy 中是否有将浮点数作为输入并返回其十进制科学记数法分解的函数,即尾数和指数?或者是否有一种简单的方法可以在不使用字符串转换或使用 for 循环来确定指数的情况下完成此操作?编写这样一个函数并不难,我只是震惊地发现我在数学、十进制或 numpy 中找不到现有的函数。

例如如果 fexpfman 是给出浮点数的十进制浮点表示的指数和尾数的函数,那么我们希望以下语句都返回 true:

fexp(154.3) == 2.0
fman(154.3) == 1.543
fexp(-1000) == 3.0
fman(-1000) == -1.0

简而言之,这将是math.frexp 的“十进制版本”。

【问题讨论】:

  • 你能给出几种情况下的示例输入和预期输出吗?
  • 那么 frexp 到底有什么问题呢?在我看来,这是最明显的起点。
  • freexp 是否有以 10 为底的选项?
  • 您会接受任何舍入错误吗?不,它没有那个选项。
  • 我在考虑舍入错误,但这有点超出了问题的要点。理想情况下,会有一个函数返回一个浮点表示的数字,该浮点表示与我们期望的数字的浮点表示相匹配,但舍入误差是可以接受的

标签: python


【解决方案1】:

避免字符串转换的一种方法是使用小数实现方法:

from decimal import Decimal

def fexp(number):
    (sign, digits, exponent) = Decimal(number).as_tuple()
    return len(digits) + exponent - 1

def fman(number):
    return Decimal(number).scaleb(-fexp(number)).normalize()

请注意,使用浮点数,如果不四舍五入,就无法计算尾数和指数。原因是floating point numbers are stored as base 2 fractions。例如,154.3 的存储浮点值是 154.30000000000001136868377216160297393798828125。浮点数在控制台中显示为准确的数字,因为(在 CPython 中)they are always rounded when serialized using a hard-coded precision of 17

【讨论】:

  • 我认为这是一种更好的方法,因为它不需要数学运算,而且我们会在脑海中这样做。但是我会修改 fman 以使用与 fexp 类似的方法和 Decimal 包。也就是说,有没有办法在没有字符串或算术的情况下获得它?
  • 就像你说的,只要将值转换为浮点数,就会出现舍入错误。但也许为 fman 创建一个十进制对象,其中符号和数字相同但指数 = len(digits)-1,然后如果需要,我们将该数字转换为浮点数
  • 更新了 fman 以使用 Decimal 类的方法(仍然不完美,但希望更清楚点)。此外,关于精度:只要您使用小数,就不会有任何舍入问题。所以是的,只要你避免浮动,它总是精确的(虽然不如浮动快或节省空间)。
  • 您的粗体陈述在技术上是错误的。所有以 2 为底的数字都可以以 10 为底精确表示(尽管指数意味着浮点数在处理过程中可能使用超过 1000 个数字)
  • @jsalonen 我建议删除关于舍入的注释。在您的示例中,154.3 不粗略地存储在内存中,确切地说是 154.30000000000001136868377216160297393798828125。 Base-2 浮点数不能精确地保存 Base-10 的浮点数,但对于存储 Base-2 的 Base-10 FP 数来说,情况并非如此。原因是简单的算术。每个 2^-N 都可以用 Base-10(0.5、0.25、0.125 等)精确表示,最终结果只是它们的总和。否则很好的答案。由于问题是关于分解浮点数的,因此关于组合它们的声明可能会导致误解。
【解决方案2】:

我希望有更好的答案,但我想出了

from math import floor, log10

def fexp(f):
    return int(floor(log10(abs(f)))) if f != 0 else 0

def fman(f):
    return f/10**fexp(f)

【讨论】:

  • f 相比,sign(f)*abs(f) 可以期待哪些额外功能?
  • 为什么不是简单的return f/10**exp(虽然没有提供exp)?如我所见,那样你就不需要numpy
  • sign(f) * abs(f) == f
  • 0 存在尚未解决的问题。首选的fexp 函数可能会引发错误来处理此问题,而尾数仅为 0
  • @jpm 也获得与math.frexp(0) 相同的行为。
猜你喜欢
  • 2021-10-04
  • 1970-01-01
  • 2018-01-12
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多