private double doFunction(int beg, int end) {
    int argbeg;

    for (argbeg = beg; argbeg <= end && expression.charAt(argbeg) != '('; argbeg++) {;
    }

    String fncnam = expression.substring(beg, argbeg).trim();
    ArgParser fncargs = new ArgParser(argbeg, end);
    FunctionHandler fnchdl = null;

    try {
      if ((fnchdl = pureFunctions.get(fncnam)) != null) {
        return fnchdl.evaluateFunction(fncnam, fncargs);
      } else if ((fnchdl = impureFunctions.get(fncnam)) != null) {
        isConstant = false; // impure functions cannot be guaranteed to be constant
        return fnchdl.evaluateFunction(fncnam, fncargs);
      }
      fncargs = null; // suppress check for too many fncargs
    } catch (ArithmeticException thr) {
      fncargs = null;
      throw thr;
    } catch (NoSuchMethodError thr) {
      fncargs = null;
      throw exception(beg, "Function not supported in this JVM: \"" + fncnam + "\"");
    } catch (UnsupportedOperationException thr) {
      fncargs = null;
      throw exception(beg, thr.getMessage());
    } catch (Throwable thr) {
      fncargs = null;
      throw exception(beg, "Unexpected exception parsing function arguments", thr);
    } finally {
      if (fncargs != null) {
        if (fncargs.hasNext()) {
          throw exception(fncargs.getIndex(), "Function has too many arguments");
        }
        offset = fncargs.getIndex();
      }
    }
    throw exception(beg, "Function \"" + fncnam + "\" not recognized");
  }