簡體   English   中英

與門在C#中的延遲輸入

[英]AND Gate with delayed inputs in C#

我正在嘗試實現具有多個輸入的布爾AND門。 每個輸入都有一個標識它的整數。 輸入信號隨機到達,並存儲在門(因此,它不是純AND門,而是具有延遲輸入的門)。 僅當所有輸入信號都到達時,門才會觸發。
注意:到達同一輸入的2個信號不計為2。

我以為我會創建一個字典來存儲輸入,當刺激到達時,更新該特定輸入的Id鍵的值,然后與所有值相加。 如果結果為1,則觸發門並將“字典”的所有“值”重置為0,然后再次等待。

我的方法聽起來有些不對勁,而且我覺得必須有一些更優雅,更高性能(.Net)的東西。

我可能有點不適應,但這看起來似乎Rx Framework很適合。 這樣,您就可以轉到純粹的反應式編程形式,在其中可以聲明在收到所有輸入之前不發送輸出。 對於外部使用者,您的門將充當IObservable<bool> ,這在某種程度上等效於IEnumerable<bool> 任何觀察者都只會看到輸出的枚舉,這會延遲接收輸入的方式。

這里的主要好處是您可以鏈接可觀察對象。 因此,如果要將“與”門的輸出鏈接到“或”門的輸入,則可以用一行代碼來完成。 對我而言,Rx是用於建模電路工作方式的理想框架,因為每個可觀察值的結果都在下一個可觀察值的輸入中起作用。

首先,建議您在Channel9上觀看一系列視頻

如果輸入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);
   }

對我來說,存儲輸入信息似乎是不必要的。 每當信號到達時,只需檢查其是否為零即可確保結果為零。 如果是一個,則不執行任何特定操作。 然后,您只需要檢查是否所有輸入信號都已到達。

編輯:

哦,我現在明白了,用“多個”表示“兩個以上”,並且沒有整數標識符, 輸入行卻有。 好吧,讓我們重新開始。

您是否真的需要存儲輸入? 如果任何輸入是false ,輸出是false ,所以只要輸出true ,只要你有至少一個(或兩個,如果你喜歡)輸入時true ,直到你得到的輸入是false

哦,但是您說“到達相同輸入的兩個信號不算作兩個。” 為了執行此操作,您必須跟蹤(但不必存儲)輸入。 這才是真正的原因。

因此,真正的問題是: 如何在C#中有效地存儲(和檢索)稀疏的整數數組?

當您談論稀疏數組時,無疑會選擇字典(哈希表)。 但是在這種情況下,每個條目只需要一個布爾值,而Dictionary<int, bool>確實有點浪費。

輸入線路ID的最大范圍是多少? 是[ int.MinValueint.MaxValue ]還是更易於管理的范圍? 如果標識符的最大范圍相對較小,則可能需要查看System.Collections.BitArraySystem.Collections.Specialized.BitVector32

如果使用這些位集合之一,則有兩種選擇:

  1. 使用兩個BitArrays / BitVector32:一個用於存儲輸入值,另一個用於存儲信號是否已到達該行。
  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會更復雜且效率更低。 使用BitVector32或普通int / uint滾動您自己的BitArray等效項可能更好。

編輯2:

鑒於OP的反對意見,我只能假設期望的行ID位於[ int.MinValueint.MaxValue ]中,並且行可以從false切換為true 如果確實如此,那么像我上面概述的那樣密集的實現是不實際的。

現在我們回到Dictionary<,> 但是,我們可以對Dictionary<int, bool>進行一些優化。

  1. 一種方法是使用SortedList<,> 如果可給予非常大的數目的輸入,一個SortedList<,>將使用顯著較少的內存比Dictionary<,>

    例如,在Dictionary<int, bool> ,每個條目將至少使用17個字節的內存。 SortedList<int, bool>僅使用5。

    最大的缺點1是,向SortedList<,>添加新條目通常比向Dictionary<,>添加條目要慢得多,因為其鍵值大於所添加條目的其他條目必須向下移動才能為新條目。 我建議使用預期的輸入進行性能分析,以比較SortedList<,>Dictionary<,>之間的內存使用率和CPU占用率。

  2. 另一個優化是將我上面提到的BitVector32方法與Dictionary<,> / SortedList<,> 這個潛在的 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<int, bool>實現,每個條目都將其稱為20個字節(以解決開銷)。 因此,將您願意使用的內存量除以20。這就是“很多”的意思。 但要注意CPU和內存之間的權衡。

1在有人天真的爭論之前,哈希表上排序列表的真正缺點(這是實現Dictionary<,>方式)的缺點是排序列表中的查找要比哈希表慢。 他們會說:“但是查找是排序列表中的O(log N),而哈希表中只有O(1)”。 哎呀! 例如,哈希表可能降級為O(N),而排序列表始終為O(log N)。 對於兩個而言,即使您有十億個項目,也不需要花費30整數比較(在這種情況下就是這樣)。 對於哈希表的開銷,許多人驚訝地發現排序后的列表在查找時勝過哈希表的頻率。

2同樣,這取決於您的輸入。 如果lineID & ~31不經常重疊(因此大多數AndEntry對象最終只存儲一行),則此解決方案將使用更多的內存,而不是更少。 如果相反,lineID內的其他27個位集傾向於重疊,則Input()不同掩碼將更有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM