public float[] calculate(float[] x) {

        // check the cache in case we've already made the calculation.
        String colourKey = calculateColourKey(x);
        if (resultCache.containsKey(colourKey)) {
            return resultCache.get(colourKey);
        }

        // setup the lexer stream
        InputStream content = new ByteArrayInputStream(functionContent.getBytes());
        Lexer lex = new Lexer();
        lex.setInputStream(content);

        // parse/evaluate the type 4 functions with the input value(s) x.
        try {
            lex.parse(x);
        } catch (IOException e) {
            logger.log(Level.WARNING, "Error Processing Type 4 definition", e);
        }

        // get the remaining number on the stack which are the return values.
        Stack stack = lex.getStack();

        // length of output array
        int n = range.length / 2;
        // ready output array
        float y[] = new float[n];

        // pop remaining items off the stack and apply the range bounds.
        for (int i = 0; i < n; i++) {
            y[i] = Math.min(Math.max((Float) stack.elementAt(i),
                    range[2 * i]), range[2 * i + 1]);
        }
        // add the new value to the cache.
        resultCache.put(colourKey, y);
        return y;
    }