【问题标题】:Folding multiple (discrete) operations into one (continuous) operation将多个(离散)操作合并为一个(连续)操作
【发布时间】:2013-05-10 06:13:04
【问题描述】:

举个简单的例子,假设我们要检查 char c 是否是字母数字:

if (48 <= c && c <= 57 ||
    65 <= c && c <= 90 ||
    97 <= c && c <= 122)
{
    // ...
}

6 个操作来确认它

但是,不存在连续函数 f(c) 使得 f(c) > 0 对于字母数字字节值,并且 剩下的?我认为至少有一个:12 次多项式,“适合”12 个点,在 x 轴上下摆动;但也许也存在一个更小次数的函数,甚至是非多项式。这样的公式将“简化”以下操作:

if (f(c) > 0)
{
    // ...
}

这有什么艺术术语吗?(想到了“折叠”这个词,但它不会产生任何相关的搜索结果——只有 Haskell 的折叠概念。)似乎只要我们能够将一组操作的codomain映射到一个粒度足够细的codomain,就可以得到这样的“折叠”。那么,我的问题是:“折叠”可以节省时间吗?或者是否有一些守恒原则迫使计算“折叠”的成本匹配(甚至超过)计算原始的“粗略”操作。

【问题讨论】:

  • 这似乎是一个有趣的理论问题,但与上面的代码(应该非常快)或使用查找表之类的替代方案相比,你确定一个多项式甚至会更快?
  • @templatetypedef - 不,当然,在上面的例子中,查找表会快得多;但我从一个简单的案例开始,扩展到一个更一般的案例,即 codomain 中可能有无限(但可数)点(因此在查找表中不可枚举)。
  • 这是错误。出于内部文档的目的,您应该使用诸如'0''9''A''Z''a''z' 之类的字符常量。您是否希望我们阅读您的代码?那里发生了六个以上的操作。通过从左到右计算运算符,从左到右计算它们:&lt;=&amp;&amp;&lt;=||&lt;=&lt;=&lt;=&lt;=||&lt;=@98765343338@9876534@9. C 不保证将使用 ASCII。相反,可以使用 EBCDIC,在这种情况下,此代码将失败!不要过早地优化,或者这样的代码!只需使用isupperislowerisdigit
  • @undefinedbehaviour - 具有讽刺意味的是,我担心你过早地优化了你的 cmets ;-) 我很欣赏、尊重并完全同意你所说的话,但我实际上并不是在问字母数字的问题,C (我之所以这样标记它是因为我的示例是用 C 语言编写的)、缓存、编译器优化或分析。我的示例旨在阐明我遇到的一个理论问题。也许我不够清楚。
  • 我仍然认为这些 cmets 对您的代码提出了一些好处,以及一些相关点:如果编译器生成代码以 fold 您的示例代码,那么这回答了您的一个问题。

标签: c math optimization discrete-mathematics


【解决方案1】:

多项式与 x 轴相交 6 次,即它有 6 个实根,因此 6 次多项式就足够了。

f(c) = -(c-48)*(c-57)*(c-65)*(c-90)*(c-97)*(c-122)

这当然会浪费时间,做 5 次乘法比 5 次逻辑运算慢得多。此外,&amp;&amp;|| 是短路的,因此您通常不需要全部进行。

【讨论】:

  • 哇,感谢您找到多项式!有趣的。我不认为零点的交叉点就足够了(方向无法确定),但我绝对错了 12 点!但是好吧,显然多项式只会增加复杂性——但它们是微不足道的解决方案——我希望我知道这个的通用术语,以便我可以研究存在哪些方法可以更聪明地“折叠”(例如非多项式)。
  • 您能否详细说明您是如何提出这个多项式的,并且知道它会在根之间上下振荡,而不是(例如,在根处接触 0,然后反射回同一半?)
  • 这实际上是一个精彩而令人大开眼界的答案。它以一种我从未想过的方式解决了一个问题——这种方式可能会为我在未来为类似问题带来更好的解决方案。上面答案的形式也很优雅——准确地展示了它是如何工作的。我印象深刻。
  • @templatetypedef:只有重复的根(例如 (c - 10)^2)会触及 0 并反射回来。我认为这有一个数学理论。
  • 好吧,可能不是那个例子,但我最初的断言是有多种方法来解决同一个问题是有效的。你永远不知道在各种机器上什么是“快”。
【解决方案2】:

在您的特定情况下,最佳形式是:

unsigned u = c;
if (u-48<10 || (u|32)-97<26)

当然,这并没有按照您希望的方式解决问题,而是相同的概念(即 (1) 将针对一个范围的两个比较转换为一个无符号减法和比较,以及 (2) 使用按位或组合多个长度相同且对齐方式匹配的范围检查)通常可以推广到其他情况。

【讨论】:

    【解决方案3】:

    函数isalnum() 不能满足您的需求是否有某些原因?别忘了#include &lt;ctype.h&gt;

    【讨论】:

    • 这是一个很好的评论......但我不确定这是否是一个很好的答案。反正我喜欢+1。
    • 不,对于被问到的理论数学问题,这是一个糟糕的答案。但是,这是一个程序员论坛。
    • 啊,我的实际问题与字母数字无关。但好点;谢谢。我只是举了一个不好的例子。
    • @ElchononEdelson 你认为这个问题应该结束吗?
    • 也许吧。我认为它属于不同的论坛,但我不能说是哪个。
    猜你喜欢
    • 2014-08-10
    • 2013-11-16
    • 2014-12-04
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多