C# 中具有延迟输入的 AND 门
我正在尝试实现一个具有多个输入的布尔与门。每个输入都有一个整数来标识它。输入信号随机到达,并存储在门中(因此它不是纯与门,而是具有延迟输入的门)。只有当所有输入信号都到达时,门才会触发。
注意:到达同一输入的 2 个信号不算作两个。
我想我应该创建一个字典来存储输入,当刺激到达时,更新该特定输入的 Id Key 的值,然后对所有值进行 AND 运算。如果结果为 1,则触发门并将字典的所有值重置为 0,然后再次等待。
我的方法听起来有些不对劲,我有一种感觉,一定有更优雅和更高性能的东西(.Net)。
I am trying to implement a boolean AND gate with multiple inputs. Each input has an integer identifying it. Input signals arrive randomly, and are stored at the gate (so it's not a pure AND gate, but one with delayed inputs). Only when all the input signals have arrived, does the gate fire.
Note: 2 signals arriving at the same input do not count as two.
I figured I'd create a Dictionary which will store the inputs, and when stimulus arrives, update the Value for that particular input's Id Key, then AND all values. If the result is 1, then fire the gate and reset all Values of the Dictionary to 0 and wait again.
Something doesn't sound right with my approach, and I have a feeling there must be something more elegant and performant (.Net).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可能有点偏离基础,但这看起来像是 Rx 框架 非常适合。这样,您就可以转向纯粹的反应式编程,您可以声明在收到所有输入之前不会发送输出。对于外部消费者来说,您的门将充当
IObservable
,这在某种程度上相当于IEnumerable
。任何观察者都只是看到输出的枚举,这些输出的发生延迟于输入的接收方式。这里的主要好处是您可以链接可观察量。因此,如果您想将“与”门的输出链接到“或”门的输入,只需一行代码即可完成。对我来说,Rx 是对电路如何工作进行建模的完美框架,因为每个可观测值的结果都会在下一个可观测值的输入中发挥作用。
首先,我建议您观看 Channel9 上的系列视频。
I may be a bit off base, but this looks like something the Rx Framework would be well suited for. With this, you move to a purely reactive form of programming, where you can declare that your output not be sent until all inputs are received. To the outside consumer, your gate would function as an
IObservable<bool>
, which is somewhat equivalent to anIEnumerable<bool>
. Any observer simply sees an enumeration of outputs, which occur in delay to how the inputs are received.The main benefit here is that you can chain observables. So, if you want to chain the output of an AND gate to the input of an OR gate, you can do that with a single line of code. To me, Rx is the perfect framework for modeling how an electrical circuit would work, since the results of each observable play a role in the input to the next observable.
To get started, I'd recommend viewing the series of videos on Channel9.
如果输入 ID 是连续的,您可以使用 bool[] 而不是字典。
If the input ID are sequencial, you could probably use a bool[] instead of a dictionary.
存储输入信息对我来说似乎没有必要。
每当信号到达时,只需检查它是否为零,确保结果为零。如果是之一,则无需执行任何具体操作。然后你只需要检查所有的输入信号是否已经到达。
Storing the input information seems unnecessary to me.
Whenever a signal arrives just check if it is zero make sure the result will be zero. If it is one, do nothing specific. Then you just need to check if all the input signals have arrived.
编辑:
哦,我现在明白了,“多个”的意思是“两个以上”,并且值没有整数标识符,输入行。 可以。好吧,让我们重新开始吧。
您真的需要存储输入吗?如果任何输入为
false
,则输出为false
,因此只要您至少有一个(或两个,如果您更喜欢)为true
的输入,直到您获得false
的输入。哦,但是你说“到达同一输入的两个信号不算作两个”。为了强制执行此操作,您必须跟踪(但不一定存储)输入。这才是真正的原因。
所以真正的问题是:如何在 C# 中有效地存储(和检索)整数的稀疏数组?
每当您谈论稀疏数组时,字典(哈希表)无疑是显而易见的选择。但在这种情况下,每个条目只需要一个布尔值,而
Dictionary
确实有点浪费。输入线路 ID 的最大范围是多少?是 [
int.MinValue
、int.MaxValue
] 还是更易于管理的范围内的值?如果标识符的最大范围相对较小,您可能需要查看 System.Collections.BitArray 或 System.Collections.Specialized.BitVector32。如果您使用这些位集合之一,则有两种选择:
bool
值,该值将与每个新输入进行与运算。此选项无法将一行上的false
输入重置为同一行上的true
输入。假设输入行数为 32 或更少,上述选项 1 的高效
BitVector32
实现将如下所示:如果您需要超过 32 行,则使用
BitArray
进行等效实现将类似,只是GetOutput
会更复杂且效率更低。您最好使用 BitVector32(或普通的 int/uint)来滚动自己的 BitArray 等效项。EDIT2:
鉴于OPs反对,我只能假设预期的行ID在[
int.MinValue
,int.MaxValue
]中,并且行可以从false
切换到true
。如果情况确实如此,那么像我上面概述的那样的密集实现是不切实际的。所以我们回到了
Dictionary<,>
。然而,我们仍然可以对Dictionary
进行一些优化。一种方法是使用
SortedList<,>
。如果可以给出大量输入,SortedList<,>
将比Dictionary<,>
使用显着更少的内存.例如,在
Dictionary
中,每个条目将使用至少 17 字节的内存。SortedList
将仅使用 5。最大的缺点1是向
SortedList<,>
添加新条目通常比向Dictionary<,>添加条目慢得多, >
,因为其键值大于所添加条目的其他条目必须向下移动,以便为新条目腾出空间。我建议使用预期输入进行分析,以比较SortedList<,>
和Dictionary<,>
之间的内存使用情况和 CPU 消耗。另一个优化是将我上面提到的
BitVector32
方法与Dictionary<,>
/SortedList<,>
相结合。这可能2可以防止因存储 8 位布尔值以及存储大量键和(如果适用)哈希表开销而浪费大量空间。允许这两个概念的示例实现如下:
请记住,这些优化的唯一好处是使用更少的内存。仅当您期望许多输入时这才重要。 “许多”的确切含义很难确定,但对于简单的
Dictionary
实现,将其称为每个条目 20 个字节(以考虑开销)。因此,将您愿意使用的内存量除以 20。这就是“多”。但要注意 CPU 和内存之间的权衡。<子>
1 之前有人天真地认为排序列表相对于哈希表(这就是
Dictionary<,>
的实现方式)的真正缺点是查找速度较慢。排序列表与哈希表,不要。他们会说,“但是在排序列表中查找的时间复杂度为 O(log N),而在哈希表中查找的时间复杂度仅为 O(1)”。哎哟--de-freakin-do。其一,哈希表可能会降级为 O(N),而排序列表始终为 O(log N)。对于两个人来说,即使您有 10 亿个项目,30 次整数比较(在本例中就是如此)也不会花费那么多。由于哈希表开销,许多人惊讶地发现排序列表在查找方面优于哈希表的频率。2 同样,这取决于您的输入。如果
lineID & ~31
不会经常重叠(因此大多数AndEntry
对象最终只存储一行),那么此解决方案将使用更多内存,而不是更少。相反,如果 lineID 中的其他 27 位集合倾向于重叠,则Input()
中的不同掩码会更有效。EDITED:
Oh, I get it now, by "multiple" you meant "more than two", and the values don't have integer identifiers, the input lines do. Okay, let's start over.
Do you really need to store the inputs? If any input is
false
, the output isfalse
, so just outputtrue
as long as you have at least one (or two, if you prefer) inputs that aretrue
and until you get an input that isfalse
.Oh, but you said "two signals arriving at the same input do not count as two." In order to enforce this, you have to track (but not necessarily store) the inputs. This is what it really comes down to.
So the real question is: How do I efficiently store (and retrieve) a sparse array of integers in C#?
A dictionary (hash table) certainly is the obvious choice whenever you're talking about sparse arrays. But in this case, you only need a boolean for each entry, and a
Dictionary<int, bool>
is indeed somewhat wasteful.What is the max range of input line IDs? Is it [
int.MinValue
,int.MaxValue
], or something in a more manageable range? If the maximum range of identifiers is relatively small, you might want to look intoSystem.Collections.BitArray
orSystem.Collections.Specialized.BitVector32
.If you use one of these bit collections, you have two choices:
bool
value that will be anded with each new input. This option doesn't afford resetting afalse
input on a line to atrue
input on the same line.Assuming 32 or fewer input lines, an efficient
BitVector32
implementation of option 1 above would be something like this:If you need more than 32 lines, then an equivalent implementation with
BitArray
would be similar, except thatGetOutput
would be more complicated and less efficient. You might be better off rolling your ownBitArray
equivalent usingBitVector32
s (or plainint
/uint
s).EDIT2:
Given the OPs objection, I can only assume that expected line IDs are in [
int.MinValue
,int.MaxValue
], and that lines may be switched fromfalse
totrue
. If this is indeed the case, a dense implementation such as what I've outlined above is not practical.So we're back to
Dictionary<,>
. There are, however, still a couple of optimizations we can make overDictionary<int, bool>
.One is to use
SortedList<,>
, instead. If a very large number of inputs may be given, aSortedList<,>
will use significantly less memory than aDictionary<,>
.For example, in a
Dictionary<int, bool>
, each entry would use at least 17 bytes of memory.SortedList<int, bool>
would use just 5.The biggest disadvantage1 is that adding a new entry to a
SortedList<,>
is generally significantly slower than adding an entry to aDictionary<,>
, because other entries whose keys compare greater than the added entry must be shifted down to make room for the new entry. I would recommend profiling with expected inputs to compare both memory usage and CPU smokage betweenSortedList<,>
andDictionary<,>
.The other optimization is to combine the
BitVector32
approach I mentioned above with aDictionary<,>
/SortedList<,>
. This potentially2 prevents a lot of wasted space from storing a boolean value in 8 bits, and of storing lots of keys and (if applicable) hash table overhead.A sample implementation, allowing both of these concepts, follows:
Keep in mind that the only benefit to these optimizations is to use less memory. This only matters if you expect many inputs. What exactly "many" means is hard to peg down, but call it 20 bytes for each entry (to account for overhead) for the simple
Dictionary<int, bool>
implementation. So divide the amount of memory you're willing to use by 20. This is what "many" is. But beware of the trade-off between CPU and memory.1 Before somebody naïvely argues that the real disadvantage to a sorted list over a hash table (which is how
Dictionary<,>
is implemented) is that lookups are slower in a sorted list versus a hash table, don't. "But lookups are O(log N) in a sorted list, and only O(1) in a hash table", they will say. Whoop-de-freakin-do. For one, hash tables potentially degrade to O(N), whereas a sorted list is always O(log N). For two, even if you have a billion items, 30 integer comparisons (as it would be in this case) just don't cost that much. What with hash table overhead, many people are surprised to find out how often sorted lists outperform hash tables on lookup.2 Again, it depends on your inputs. If
lineID & ~31
doesn't frequently overlap (so mostAndEntry
objects end up storing only one line) then this solution will use more memory, not less. If instead, some other set of 27 bits within lineID tended to overlap, then different masks inInput()
would be more effective.