首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Python中交错两个十进制数字

在Python中交错两个十进制数字
EN

Stack Overflow用户
提问于 2020-10-08 14:09:45
回答 1查看 188关注 0票数 0

我感兴趣的是一个高效的Python--实现所谓的‘交错函数’f,它在(0,1)中取两个数字a,b,并交错它们的十进制数,即

f(a,b) := 0.a1 b1 a2 b2 a3 b3 .其中a= 0.a1 a2 a3.B= 0.b1 b2 b3.是a,b的十进制表示。

从数学上讲,函数f是从(0,1)x(0.1)到(0,1)的一对一映射.

您能建议如何在Python中有效地实现这个映射,以保持它是一对一的吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-10-11 12:56:17

对于一个有效的实现,需要确保实现两件事:大O符号的最小渐近复杂度和有效的计算运算符,避免重复或其他不必要的计算。

考虑到这个问题,不太可能用一个与输入数的长度不成线性的算法来解决这个问题。就运算符而言,考虑到我们使用十进制格式,我们很难从一些按位(二进制)计算中获益。因此,我们可能是最好的一般数学操作。

使用浮子

第一个简单的实现将尝试在浮点数上执行函数:

代码语言:javascript
运行
复制
def interleave_float(a: float, b: float) -> float:
    a_rest = a
    b_rest = b
    result = 0
    dst_pos = 1.0  # position of written digit
    while a_rest != 0 or b_rest != 0:
        dst_pos /= 10  # move decimal point of write
        a_rest *= 10  # move decimal point of read
        result += a_rest // 1 * dst_pos
        a_rest %= 1  # remove current digit

        dst_pos /= 10
        b_rest *= 10
        result += dst_pos * (b_rest // 1)
        b_rest %= 1

    return result

然而,一个简单的测试显示了一个问题-- 浮点算法固有的有限精度,它在浮点数之后已经扭曲了16-17位数字:

代码语言:javascript
运行
复制
>>> a = 0.987654321
>>> b = 0.1234567890123456789
>>> print(a)
0.987654321
>>> print(f"{b:.20}")  # formatted to show higher precision
0.12345678901234567737
>>> print(f"Float:  {interleave_float(a, b):.50}")
Float:  0.91827364554637280757987127799424342811107635498047

使用十进制

克服精度问题的一个常见方法是使用decimal.Decimal定点十进制算法的python实现。

代码语言:javascript
运行
复制
from decimal import Decimal, getcontext
getcontext().prec = 50  # increase number precision

def interleave_fixed(a: Decimal, b: Decimal) -> Decimal:
    a_rest = a
    b_rest = b
    result = 0
    dst_pos = Decimal(1)
    while a_rest != 0 or b_rest != 0:
        dst_pos *= Decimal(0.1)
        a_rest *= 10  # move decimal point
        result += a_rest // 1 * dst_pos
        a_rest %= 1  # remove current digit

        dst_pos *= Decimal(0.1)
        b_rest *= 10
        result += dst_pos * (b_rest // 1)
        b_rest %= 1

    return result

这似乎对b更有效,但不幸的是,这也会导致结果中相同数字的不精确。计算后上下文中的不精确标志也表示了这种不精确性:

代码语言:javascript
运行
复制
>>> print(getcontext())
Context(prec=50, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow])
>>> a = Decimal(".987654321")
>>> b = Decimal(".1234567890123456789")
>>> print(a)
0.987654321
>>> print(b)
0.1234567890123456789
>>> print(f"Fixed:  {interleave_fixed(a, b)}")
Fixed:  0.91827364554637287146771953200668367263491993253785
>>> print(getcontext())
Context(prec=50, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, FloatOperation, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])

使用str

另一种不应由于精度而施加限制的方法(这是您自己提出的)是使用字符串进行语法处理:

代码语言:javascript
运行
复制
def interleave_str(a: str, b: str) -> str:
    result = "0."
    src_pos = 2  # position of read digit
    while len(a) > src_pos or len(b) > src_pos:
        result += a[src_pos] if len(a) > src_pos else "0"

        result += b[src_pos] if len(b) > src_pos else "0"

        src_pos += 1

    return result[:-1] if result.endswith("0") else result

如果有,移除变黄0

该算法不进行验证,因此需要由您来决定要添加什么。然而,测试这提供了所需的精度:

代码语言:javascript
运行
复制
>>> a = "0.987654321"
>>> b = "0.1234567890123456789"
>>> print(a)
0.987654321
>>> print(b)
0.1234567890123456789
>>> print(f"String: {interleave_str(a, b)}")
String: 0.91827364554637281900010203040506070809

...but,您能对结果字符串做些什么?或者再把它转换成十进制?这取决于你想如何使用结果。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64264332

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档