E
E
Eugene Ordinary2017-01-13 12:26:55
Programming
Eugene Ordinary, 2017-01-13 12:26:55

What is the best way to define a table function with a sparse scope?

The function argument takes values ​​that are very far from each other. For example, x = 2, 10, 100, 2000,...
You need to define a table function for these values.
There are two options.
Define a long array

const int func[2001] = {0, 0, f(2), ...., f(100), ....., f(2000)};

or define a function
int func(int x)
{
  switch( x )
  {
    case 2: return f(2); break;
    case 100: return f(100); break;
    case 2000: return f(2000); break;
    ...
  }
}

Which option is better and faster?
upd. For example, I gave more numbers. In fact, the values ​​are up to 100, and the total values ​​are 10-20.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
M
Mercury13, 2017-01-13
@Mercury13

If the arguments are up to 100, the function is known in advance and is unchanged - ignore everything and make it a simple array. That's right, with a jump table, a switch is arranged inside. Everything I write below is for general development.
This is called "sparse array" (sparse array)
1. Hash table (std::unordered_map).
Advantage: available "in the box", very fast.
Disadvantage: Eats a lot of memory.
2. I also use this mechanism.

template <class T>
class ChunkMap
{
public:
    // Data access
    //------------------------------------------------------------------------//
    /// @return  data at index t, or empty value
    T get(size_t t) const;

    //------------------------------------------------------------------------//
    /// Sets data at index t (empty value to erase)
    void put(size_t t, T x);

    //------------------------------------------------------------------------//
    /// Erases range [0..maxPlus)
    void eraseTo(size_t aMaxPlus);

    // Info
    size_t nChunks() const { return fChunks.size(); }
    bool isEmpty() const { return fChunks.empty(); }

    //------------------------------------------------------------------------//
    /// @return  the number that is beyond all chunks
    size_t ceil() const;

    //------------------------------------------------------------------------//
    /// @return  actual number of records in the map
    size_t size() const;

    //------------------------------------------------------------------------//
    /// @return  lowest value in the map; (0, empty) if empty
    std::pair<size_t, T> lowerValue() const;

    //------------------------------------------------------------------------//
    /// @return  highest value in the map; (0, empty) if empty
    std::pair<size_t, T> upperValue() const;

    //------------------------------------------------------------------------//
    /// @return  (t1, v), t1 <= t;  (0, empty) if none
    std::pair<size_t, T> lowerOrEq(size_t t) const;

    template <class Body> void loop(const Body& r) const;
    template <class Body> void loopFrom(size_t aMin, const Body& r) const;

    //------------------------------------------------------------------------//
    ///  Loops all data. Body is bool-convertible.
    ///  Return true → go on.
    ///  Return false → stop and return false.
    template <class Body> bool loopBool(const Body& r) const;

    void clear() { fChunks.clear(); }

    constexpr static T emptyValue() { return std::numeric_limits<T>::max(); }
    static bool isEmptyValue(const T& x) { return (x == emptyValue()); }

    constexpr static unsigned chunkSize() { return Chunk::SIZE; }

private:
    struct Chunk
    {
        enum { SIZE = 8 };
        Fix1d<T, SIZE> data;   // мой шаблон, массив фиксированного размера с проверкой на выход за границы

        Chunk();
        bool isEmpty() const;
        std::pair<size_t, T> lowerValue(size_t aKey) const;
        std::pair<size_t, T> upperValue(size_t aKey) const;
    };
    typedef std::map<size_t, Chunk> Chunks;
    Chunks fChunks;
};

You can do it on unordered_map if you want, but I need lowerOrEq().
Benefit: Saves memory if there are multiple values ​​side by side.
Disadvantage: more memory consumption (not much).
3. Here is another implementation in Java.
https://android.googlesource.com/platform/framewor...
Benefit: Serious memory savings.
Disadvantages: when the array is large (thousands of filled elements), access speed decreases. High waste disposal costs.

A
Alexander Taratin, 2017-01-13
@Taraflex

total values ​​10-20.

If function f can be made constexpr , then I am for switch
For compactness, it is not necessary to put break after return.
If not, then for a long array.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question