【问题标题】:Fastest way to check if a number has the 'digit' zero anywhere in it?检查数字中是否有“数字”零的最快方法?
【发布时间】:2012-04-05 15:01:21
【问题描述】:

检查一个数字中是否有数字“0”的最快方法是什么?

我需要开发一种快速的方法,因为我必须在 $20$ 秒内对接近 $10^9$ 的数字执行这些检查。

将零转换为字符串后是否可以搜索?

【问题讨论】:

  • 这对于stackoverflow来说可能是一个更好的问题,因为“最快”的方式将取决于你的数字是如何存储的,你的编译器和CPU的细节等等,这些都不是真正的数学问题。
  • 您的数字有多大也非常相关;如果它们很小,那么表查找可以很好地工作。或者,您可以对前几位数字使用除以 10 算法,然后一旦数字很小,就在您的表格中查找。
  • @NateEldredge:或者分块进行,例如除以 1000。
  • 你想要 0 在以 10 为底的表示中,还是在以 2 为底的表示中,还是什么? n 保证在基数 n 表示中具有 0,因此您可以非常快速地检查所有 10^9 个数字:子程序 check(n) Return True
  • 我要把这个问题迁移到stackoverflow。此处问题下方将显示一个链接,您可以按照该链接转到问题的新位置。如果您需要帮助在 stackoverflow 上关联帐户,您可以标记您的问题以引起版主注意,那里的人会提供帮助。

标签: algorithm


【解决方案1】:

除以 $2$ 的幂以外的数字将进行相同次数的运算,无论数字是多少。因此,不要重复将 $x$ 除以 $10$ 并针对 $0$ 测试每个余数,而是考虑重复将 $x$ 除以 $10^6$(例如)并根据 $[0, 10^6) 上的查找表测试每个余数美元。如果余数包含内部零,则查找表应该说“是”,如果它不包含零,则应该说“否”,如果余数只有初始零,则应该说“可能”(在这种情况下,检查 $x$ 当前是否为非零并返回“是”或“否”)。

【讨论】:

  • 除了从查找表中受益匪浅之外,问题的并行性也令人尴尬。虽然不幸的是 MMX 和 SSE 都没有提供向量整数除法指令,但始终存在并发性。
  • +1 用于查找表。根据设备架构,除法可能非常昂贵。
  • $10^6$ 可能不是最佳选择,您需要将其放入处理器的缓存中。此外,如果您想多次除数,则可能值得考虑使用乘法(例如,参见 this)。
【解决方案2】:

如果您可以编写汇编程序或强制编译器进行整数除法,请重复执行整数除法 $10$,直到余数为 $0$ 或被除数为 $0$。如果是余数,则有一个“$0$”数字。如果是股息,则没有“$0$”数字。

【讨论】:

  • 既然我已经发布了,我发现这本质上是 Jack Maney 提出的算法。
【解决方案3】:

二进制零:如果有零位,(~x) 将非零。我猜你不关心二进制数。

如果您的数据以字符串开头,请保持原样。如果不是,请不要转换为字符串然后检查。到字符串的转换比检测零位所需的工作更多。这可能是特定于语言的。在 c 或汇编中,转换将比您自己的检测算法慢。

例如,如果您将基数为 10 的数字存储为整数(如在 c 中),您可以创建一个包含 1000 个条目的查找表。 Lookup[100] = 1, Lookup[123] = 0 等。然后您必须将输入数字除以 1000 而不是 10。余数是查找索引。这可能比除以 10 快 3 倍。一个小的查找表将适合缓存。表太大,由于 ram 太慢,您将获得性能损失。在 c 中,无符号整数可能比有符号整数除法更快,因为优化器可能会采取一些捷径。

最后,为此考虑多个线程。

【讨论】:

    【解决方案4】:

    我需要开发一种快速方法,因为我必须在 20 秒内对近 109 个数字执行这些检查。

    啊,编程问题。

    将零转换为字符串后是否可以搜索?

    如果您提供给输入的所有内容都是单独一行的数字,并且没有前导零或尾随零,那么 /0/ 就可以了。但是,是的,字符串将是最快的。对于混合中包含零或非数字的更复杂的表示,那么您可以将这个正则表达式用于整数:

    /^[1-9]+0[0-9]*$|^0$/
    

    这需要一个非前导零的数字,或者是数字零。它还假设整数。

    $ cat numbers
        375
        391
        940
        493
        566
        804
        800
        453
        726
        527
        428
        77
        984
        510
        795
        077
        0
    
        $ egrep '^[1-9]+0[0-9]*$|^0$' numbers
    940
    804
    800
    510
    0
    

    如果十进制数字是固定宽度的,则可能会更具挑战性。如果不是,则在两个括号中添加一个句点就足够了,除非您的小数以“0.nnn”而不是“.nnn”开头。告诉我你的号码,我会给你正确的解决办法。

    【讨论】:

    • "但是是的,字符串是最快的。" [需要引用]。将数字转换为字符串然后检查零 - 更不用说使用正则表达式来做到这一点 - 肯定不会是最快的。
    【解决方案5】:

    这里有一些 Mathematica 代码,数字中的每个数字除一。

    n = 34560116; d = IntegerLength[n]; m = 0; x = 1;  
    While[d >= x, If[m == (k = Mod[n, 10^(x++)]), Break[], m = k]];
    If[d >= x, Print["First zero found at: ", 10^(x - 2)]];
    
    First zero found at: 1000
    

    【讨论】:

      猜你喜欢
      • 2014-07-12
      • 2018-05-04
      • 2021-04-27
      • 2013-08-12
      • 2016-08-02
      • 1970-01-01
      • 2011-02-05
      • 1970-01-01
      相关资源
      最近更新 更多