【问题标题】:AND Gate with delayed inputs in C#在 C# 中具有延迟输入的与门
【发布时间】:2010-07-28 16:05:47
【问题描述】:

我正在尝试实现一个具有多个输入的布尔与门。每个输入都有一个整数来标识它。输入信号随机到达,并存储在门中(因此它不是纯与门,而是具有延迟输入的门)。只有当所有输入信号都到达时,门才会触发。
注意:到达同一输入的 2 个信号不计为两个。

我想我会创建一个字典来存储输入,当刺激到达时,更新该特定输入的 ID 键的值,然后更新所有值。如果结果为 1,则触发门并将字典的所有值重置为 0,然后再次等待。

我的方法听起来有些不对劲,我觉得必须有一些更优雅和高性能的东西(.Net)。

【问题讨论】:

    标签: .net boolean


    【解决方案1】:

    我可能有点离题,但这看起来像 Rx Framework 非常适合。有了这个,你就转向了一种纯粹的反应式编程形式,你可以声明在收到所有输入之前不会发送你的输出。对于外部消费者,您的门将用作IObservable<bool>,这在某种程度上相当于IEnumerable<bool>。任何观察者都只会看到一个输出枚举,这些输出在接收输入时发生延迟。

    这里的主要好处是您可以链接 observables。因此,如果您想将 AND 门的输出链接到 OR 门的输入,只需一行代码即可完成。对我来说,Rx 是对电路如何工作进行建模的完美框架,因为每个 observable 的结果都会在下一个 observable 的输入中发挥作用。

    要开始使用,我建议您在 Channel9 上查看series of videos

    【讨论】:

      【解决方案2】:

      如果输入 ID 是连续的,您可以使用 bool[] 而不是字典。

         bool[] inputs = new bool[10];
      
         void SetInput(int id, bool val)
         {
             inputs[id] = val;
         }
      
         bool trigger()
         {
              return inputs.All(b => b);
         }
      
         void reset()
         {
              Array.Clear(input, 0, inputs.Length);
         }
      

      【讨论】:

        【解决方案3】:

        对我来说似乎没有必要存储输入信息。 每当信号到达时,只需检查它是否为零,确保结果为零。如果是一个,什么都不做。然后你只需要检查是否所有的输入信号都到了。

        【讨论】:

          【解决方案4】:

          已编辑:

          哦,我现在明白了,“多个”是指“超过两个”,没有整数标识符,输入行有.好的,让我们重新开始。

          您真的需要存储输入吗?如果任何输入为false,则输出为false,因此只要您至少有一个(或两个,如果您愿意)输入为true,并且直到您得到一个输入是false

          哦,但是您说“到达同一输入的两个信号不算作两个”。为了强制执行此操作,您必须跟踪(但不一定存储)输入。这才是真正的归结。

          所以真正的问题是:如何在 C# 中有效地存储(和检索)一个稀疏的整数数组?

          当您谈论稀疏数组时,字典(哈希表)无疑是显而易见的选择。但是在这种情况下,您只需要为每个条目提供一个布尔值,而Dictionary<int, bool> 确实有些浪费。

          输入行 ID 的最大范围是多少?是 [int.MinValue, int.MaxValue],还是在更易于管理的范围内?如果标识符的最大范围相对较小,您可能需要查看System.Collections.BitArraySystem.Collections.Specialized.BitVector32

          如果您使用这些位集合之一,您有两种选择:

          1. 使用两个 BitArrays/BitVector32s:一个用于存储输入值,另一个用于存储信号是否已到达该线路。
          2. 仅使用一个 BitArray/BitVector32。使用它来存储信号是否已到达给定行,并保留一个单独的bool 值,该值将与每个新输入相乘。此选项无法将一行上的 false 输入重置为同一行上的 true 输入。

          假设 32 行或更少的输入行,上面选项 1 的有效BitVector32 实现将是这样的:

          class AndGate{
              BitVector32 activeLines;
              BitVector32 inputValues;
          
              public void Reset(){
                  activeLines[-1] = inputValues[-1] = false; 
              }
              public void Input(int line, bool value){
                  if(line < 0 || line > 31)
                      throw new ArgumentOutOfRangeException("line");
          
                  activeLines[1 << line] = true;
                  inputValues[1 << line] = value;
              }
              public bool GetOutput(bool reset){
                  bool rtn = activeLines.Data == inputValues.Data;
                  if(reset)
                      Reset();
                  return rtn;
              }
          }
          

          如果您需要超过 32 行,那么使用 BitArray 的等效实现将是类似的,只是 GetOutput 会更复杂且效率更低。你最好使用BitVector32s(或普通的int/uints)滚动你自己的BitArray等价物。

          EDIT2:

          鉴于 OP 的反对意见,我只能假设预期的线路 ID 在 [int.MinValue, int.MaxValue] 中,并且线路可以从 false 切换到 true。如果情况确实如此,那么像我上面概述的那样密集的实现是不切实际的。

          所以我们回到Dictionary&lt;,&gt;。但是,我们仍然可以对 Dictionary&lt;int, bool&gt; 进行一些优化。

          1. 一种是改用SortedList&lt;,&gt;。如果可能给出大量输入,SortedList&lt;,&gt; 将使用显着Dictionary&lt;,&gt; 少的内存。

            例如,在Dictionary&lt;int, bool&gt; 中,每个条目将使用至少 17 字节的内存。 SortedList&lt;int, bool&gt; 只会使用 5 个。

            最大的缺点1SortedList&lt;,&gt; 添加新条目通常比向Dictionary&lt;,&gt; 添加条目要慢得多,因为其他条目的键比较大于添加的条目必须向下移动以便为新条目腾出空间。我建议使用预期输入进行分析,以比较 SortedList&lt;,&gt;Dictionary&lt;,&gt; 之间的内存使用情况和 CPU 烟雾。

          2. 另一个优化是将我上面提到的BitVector32方法与Dictionary&lt;,&gt;/SortedList&lt;,&gt;结合起来。这可能2可以防止大量浪费空间来存储 8 位布尔值,以及存储大量键和(如果适用)哈希表开销。

          以下是允许这两个概念的示例实现:

          class AndGate{
          
              struct AndEntry{
                  BitVector32 activeLines;
                  BitVector32 inputValues;
          
                  public bool Output{get{return activeLines.Data == inputValues.Data;}}
          
                  public void Input(int line, bool value){
                      activeLines[1 << line] = true;
                      inputValues[1 << line] = value;
                  }
              }
          
              IDictionary<int, AndEntry> entries;
          
              public AndGate(bool useSortedList){
                  if(useSortedList)
                      entries = new SortedList<int, AndEntry>();
                  else entries = new Dictionary<int, AndEntry>();
              }
          
              public void Reset(){entries.Clear();}
          
              public bool Input(int line, bool value){
                  AndEntry entry;
                  entries.TryGetValue(line / 32, out entry);
                  /* no need to handle the not found case, since AndEntry is a struct */
          
                  entry.Input(line & 31, value);
                  entries[line / 32] = entry;
              }
          
              public bool GetOutput(bool reset){
                  bool rtn = true;
                  foreach(AndEntry value in entries.Values)
                      if(!value.Output){
                          rtn = false;
                          break;
                      }
          
                  if(reset)
                      Reset();
                  return rtn;
              }
          }
          

          请记住,这些优化的唯一好处是使用更少的内存。这仅在您期望 许多 输入时才重要。 “很多”的确切含义很难确定,但对于简单的Dictionary&lt;int, bool&gt; 实现,将每个条目称为 20 个字节(以考虑开销)。因此,将您愿意使用的内存量除以 20。这就是“许多”。但要注意 CPU 和内存之间的权衡。

          1 在有人天真地争论排序列表相对于哈希表的真正缺点之前(Dictionary&lt;,&gt; 的实现方式)是排序列表中的查找速度较慢哈希表,不要。 “但是在排序列表中查找是 O(log N),而在哈希表中只有 O(1)”,他们会说。哎呀,吓坏了。一方面,哈希表可能会降级到 O(N),而排序列表总是 O(log N)。对于两个,即使你有十亿个项目,30 个整数比较(就像在这种情况下一样)也不会花费那么多。对于哈希表开销,许多人惊讶地发现排序列表在查找时优于哈希表的频率。

          2 同样,这取决于您的输入。如果lineID &amp; ~31 不经常重叠(所以大多数AndEntry 对象最终只存储一行),那么这个解决方案将使用更多 内存,而不是更少。相反,如果 lineID 中的其他一些 27 位集合倾向于重叠,那么 Input() 中的不同掩码会更有效。

          【讨论】:

          • 在运行时无法确定输入的数量。您必须使用动态结构来保存输入的值,同时跟踪这些输入的标识,以遵守“到达同一输入的 2 个信号不算作两个”的规则。
          • 我没有对输入的数量做出任何假设。但我确实问过他们的最小和最大标识符是什么。我发布的BitVector32 代码适用于任意数量的输入,只要该数字为 32 或更少。 :) 您期望的实际上限是多少?除非您的标识符是任意长度的,否则您可以识别的任何内容都有可能值的上限。
          • 另外,您是否需要输入才能从false 切换到true?如果答案为“否”,则存在比答案为“是”更简单的解决方案。
          猜你喜欢
          • 1970-01-01
          • 2013-07-25
          • 2017-10-25
          • 1970-01-01
          • 2013-10-21
          • 1970-01-01
          • 2010-12-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多