Elemente einfuegen in vector bzw. map



  • okay, danke. ich werds mal versuchen. Stattdessen koennte ich auch map<int, X> an Stelle von vector<X> verwenden, oder?



  • Wenn du meinst, daß das einen Vorteil bringt 😉 (der Zugriff auf einen vector<> ist um einiges schneller als bei einer map<>)



  • Ich habs beim vector belassen, am anfang der fill methode ein resize() aufzurufen ist ja nicht soo schwer...

    Jetzt ergibt sich mir allerdings ein anderes Problem. Ich habe mein "Array" wie folgt definiert und gefuellt:

    //lumis.h
    
    typedef map<double, double> P81ToLumiMap;
    typedef vector<P81ToLumiMap> PythiaSetToPL;
    typedef vector<PythiaSetToPL> PVersToSetToPL;
    
    PVersToSetToPL lumis; // == vector< vector< map<double, double> > >
    
    struct LumiFiller
    {
    public:
      LumiFiller() 
      { fill_lumis(); }
    
    private:
     void fill_lumis()
      {    
        lumis.resize(nPytVers);
        for (int v = 0; v < nPytVers; v++)
          { lumis[v].resize(nPytSets); }
    
        // Pythia64
        lumis[P64][DIRECT][1.9] = 68.50;
        lumis[P64][NOMPI][1.9]  = 81.62;
    
        lumis[P64][s000_033_066][1.1] = 1.71;
        lumis[P64][s000_033_066][1.2] = 2.10;
        lumis[P64][s000_033_066][1.3] = 2.51;
        lumis[P64][s000_033_066][1.4] = 2.92;
        lumis[P64][s000_033_066][1.5] = 3.34;
        lumis[P64][s000_033_066][1.6] = 3.73;
        lumis[P64][s000_033_066][1.7] = 4.11;
        // und viele Zeilen mehr in dieser Art
      }
    };
    
    LumiFiller a; //die Definition der Gobalen varibale sorgt uer den Aufruf von fill_lumis()
    

    Wie man sieht habe ich im letzten Block als dritten index doubles in 0.1 er Schritten. Wenn ich jetzt mit Iteratoren mir den ganzen Kram ausgeben lasse, stimmt auch alles perfekt, aber folgendes funktioniert nicht:

    for (double d = 1.1; d <= 1.7; d += 0.1)
      {
        cout << lumis[P64][s000_033_066][d] << endl;
      }
    

    fuer d = 1.1 und 1.2 gibt er noch richtige Werte aus, danach nur noch Nullen. Gibs hier etwas wieder Rundungsfehler oder aehnliches?



  • es ist ein problem mit der genauigkeit von double

    lass dir doch mal die werte die die schleife generiert neben den werten, die die float notation generiert ausgeben - evtl gibt es da kleine unterschiede



  • hm leider kann ich zur Zeit kein setprecision nutzen - irgendwer hat da ne headerdatei zerschossen, der sysadmin sitzt grad dran. Die AUsgabe der Werte hat mir aber nichts neues gebracht, vermutlich sitzen die Rundungsfehler dann irgendwo tiefer. Da ich die aber so und so nicht beheben kann muss ich mir irgendwie anderwitig helfen. Vielleicht ne KLasse schreiben, die intern einen Vector nutzt und die doubles mit 10 multipliziert und auf ints castet. Das sollte dann eigentlich keine Fehler mehr geben oder doch?



  • pumuckl schrieb:

    Gibs hier etwas wieder Rundungsfehler oder aehnliches?

    Stark anzunehmen. Und solange du mit double-Werten arbeitest, wirst du diese Rundungsfehler auch nicht beseitigen können (double ist nicht in der Lage, den Wert 0.1 exakt darzustellen - und wenn du ihn ein paarmal aufaddierst, summieren sich die Rundungsfehler so weit, daß du sie tatsächlich bemerkst).



  • Es ist übrigens kein guter Gedanke ein Objekt register zu nennen! 🙂



  • CStoll schrieb:

    (double ist nicht in der Lage, den Wert 0.1 exakt darzustellen - und wenn du ihn ein paarmal aufaddierst, summieren sich die Rundungsfehler so weit, daß du sie tatsächlich bemerkst).

    Sprich, der Rundungsfehler entsteht ind er Schleife und ich kann auch durch Basteln einer eigenen double-map nichts erreichen. Also doch lieber

    for (int i = 11; i <=17; i++)
    {
      cout << lumis[P64][s000_033_066][i/10.0] << endl;
    }
    

    🙄



  • du könntest versuchen die rundungsfehler zum umgehen (bzw. damit klar zu kommen), indem du dir einen eigenen Datentyp schreibst, der ein double kapselt und vergleiche mit anderen doubles zulässt. Er muss bei vergleichen natürlich eine gewissen toleranz haben.
    Dann kannst du zB sowas machen:

    class MyTolerantDouble
    {
    public:
      MyTolerantDouble(double val) : { m_Val := val; };
    // kopierkosntruktor, zuweisung etc.
    
    public operator==(const MyTolerantDouble&) { /* hier mit Toleranz vergleichen */ };
    };
    
    typedef map<MyTolerantDouble, double> P81ToLumiMap;
    

    Dann kannst du die Toleranz auf einen Wert stellen und dann nochmal versuchen, obs geht. Das is ja grad das tolle an templates, dass die datentypen nur bestimmte anforderungen erfüllen müssen, aber nciht vollkommen fest definiert sind im template.
    Damit könntest du das problem umgehen.



  • pumuckl schrieb:

    CStoll schrieb:

    (double ist nicht in der Lage, den Wert 0.1 exakt darzustellen - und wenn du ihn ein paarmal aufaddierst, summieren sich die Rundungsfehler so weit, daß du sie tatsächlich bemerkst).

    Sprich, der Rundungsfehler entsteht ind er Schleife und ich kann auch durch Basteln einer eigenen double-map nichts erreichen.

    Eventuell könntest du etwas erreichen, wenn du einen eigenen double-Komparator schreibst, der über diese Rundungsfehler hinwegsehen kann. Aber ansonsten ist es wohl das beste, double gar nicht an map<>-Schlüssel einzusetzen.

    Also doch lieber

    for (int i = 11; i <=17; i++)
    {
      cout << lumis[P64][s000_033_066][i/10.0] << endl;
    }
    

    🙄

    Ich bin mir nicht einmal sicher, ob das dein Problem löst oder nur aufschiebt.

    PS: Ist es wirklich nötig, einen direkten Bezug zwischen dem double und dem Zielwert zu haben? Wenn du wirklich nur diese 7 Werte in der map stehen hast, kannst du sie mit einer Transformation (10*x-11) auf den ganzzahligen Bereich 0..6 übersetzen.



  • ich hab "ein bisschen" mehr als diese 7 werte. am ende werden es 2x6x15 Werte sein plus einige wo ich nicht iterieren muss (wie bei lumis[P64][DIRECT] in meinem beispiel oben) Ich habe ueberlegt, statt der double keys int keys zu nehmen, denn es wird bei einer Nachkommastelle bleiben. An Stelle der Map koennte man noch einen vetor nehmen, zu dem man einen offset speichert, damit z.B der Platz fuer index 0-10 nicht sinnlos vergeudet wird, wenn man nur 11-25 belegt...



  • so, vermutlich isses schon zigmal gemacht worden, aber ich hab hier mal einen offsetvector geschrieben. Im Grunde hab ich das ganze interface von std::vector abgepinnt, es wird alles stumpf weitergeleitet abgeshen vom operator[], den Konstruktoren die die Initialisierung dess Offset erlauben und den neuen Methoden offset() und set_offset(n), von denen letztere den Container derart vergoessert/verkleinert, dass a) size() + offset() = const; b) falls n > alter
    offset, fallen die vorderen Elemente weg.
    Zusatzlich habe ich einen Konvertierungsoperator nach vector<T, Allocator> geschrieben, um hin- und herkonvertieren zu ermoeglichen.

    #ifndef offsetvector__
    #define offsetvector__
    
    #include <vector>
    
    template <class T, class Allocator = std::allocator<T> >
    
    class offsetvector
    {
    public:
      typedef std::vector<T, Allocator> stdvec;
    
      typedef typename stdvec::reference         reference;
      typedef typename stdvec::const_reference   const_reference;
      typedef typename stdvec::iterator          iterator;
      typedef typename stdvec::const_iterator    const_iterator;
      typedef typename stdvec::size_type         size_type;
      typedef typename stdvec::difference_type   difference_type;
      typedef typename stdvec::value_type        value_type;
      typedef typename stdvec::allocator_type    allocator_type;
      typedef typename stdvec::pointer           pointer;
      typedef typename stdvec::const_pointer     const_pointer;
      typedef typename stdvec::reverse_iterator  reverse_iterator;
      typedef typename stdvec::const_reverse_iterator 
                                           const_reverse_iterator;
    
      // Constructor and assignment:
    
      explicit offsetvector(const Allocator& a = Allocator())
        : vec_(a), offs_(0) {}
      explicit offsetvector(size_type n, size_type offs = 0, 
    	      const T& value = T(), 
    	      const Allocator& a = Allocator())
        : vec_(n, value, a), offs_(offs) {}
      template<class InputIterator>
      offsetvector(InputIterator first, InputIterator last, size_type offs = 0,
         const Allocator& a = Allocator())
        : vec_(first, last, a), offs_(offs) {}
      offsetvector(const offsetvector<T, Allocator>& orig) 
        : vec_(orig.vec_), offs_(orig.offs_) {}
      offsetvector(const vector<T, Allocator>& orig, size_type offs = 0)
        : vec_(orig), offs_(offs) {}
    
      operator vector<T, Allocator>() { return vec_; }
      ~offsetvector() {}
    
      offsetvector<T, Allocator>& 
      operator=(const offsetvector<T, Allocator>& orig)
      { 
        if (&orig == this) return *this;
        vec_ = orig.vec_; offs_ = orig.offs_;
        return *this;
      }
    
      template<class InputIterator>
      void assign(InputIterator first, InputIterator last, size_type offs = 0)
      { offs_ = offs; vec_.assign(first, last); }
    
      // Iterators:
      iterator begin() { return vec_.begin(); }
      const_iterator begin() const { return vec_.begin(); }
      iterator end() { return vec_.end(); }
      const_iterator end() const { return vec_.end(); }
      reverse_iterator rbegin() { return vec_.rbegin(); }
      const_reverse_iterator rbegin() const { return vec_.rbegin(); }
      reverse_iterator rend() { return vec_.rend(); }
      const_reverse_iterator rend() const { return vec_.rend(); }
    
      //size
      size_type size() const { return vec_.size(); }
      size_type offset() const { return offs_; }
      size_type max_size() const { return vec_.max_size(); }
      void resize(size_type sz, T c = T()) { vec_.resize(sz, c); }
      size_type capacity() const { return vec_.capacity(); }
      bool empty() const { return vec_.empty(); }
      void reserve(size_type n) { vec_.reserve(n); }
    
      // set offset: set start index
      // results in resizing of offsetvector
      void set_offset(size_type n) 
      {
        if (n == offs_) return;
        size_type newsize = offs_ + vec_.size() - n;
        if (newsize <= 0) vec_.clear();
        else
          {
    	stdvec tmp(vec_.rbegin(), vec_.rend());
    	tmp.resize(newsize);
    	vec_.assign(tmp.rbegin(), tmp.rend());
          }
        offs_ = n;
      }
    
      // access
      reference operator[] (size_type n)
      { return vec_[n - offs_]; }
      const_reference operator[] (size_type n) const
      { return vec_[n - offs_]; }
      const_reference at(size_type n) const
      { return vec_.at(n - offs_); }
      reference at(size_type n)
      { return vec_.at(n - offs); }
      reference front() { return vec_.front(); }
      const_reference front() const { return vec_.front(); }
      reference back() { return vec_.back(); }
      const_reference back() const { return vec_.back(); }
    
      void push_back(const T& x) { vec_.push_back(x); }
      void pop_back() { vec_.pop_back(); }
      iterator insert(iterator position, const T& x = T())
      { vec_.insert(position, x); }
      iterator insert(iterator position, size_type n, const T& x = T())
      { return vec_.insert(position, n, x); }
      template<class InputIterator>
      void insert(iterator position, InputIterator first, 
    	      InputIterator last)
      { vec_.insert(position, first, last); }
      iterator erase(iterator position)
      { return vec_.erase(position); }
      iterator erase(iterator first, iterator last)
      { return vec_.erase(first, last); }
      void swap(offsetvector<T, Allocator>& other)
      { 
        size_type tmp = offs_; 
        offs_ = other.offs_; 
        other.offs_ = tmp;
        vec_.swap(other.vec_);
      }
      void clear() { vec_.clear(); }
    
    protected:
      stdvec vec_;
      size_type offs_;
    };
    
    #endif
    

    /edit: einige typos entfernt


Anmelden zum Antworten