In PostgreSQL I'm getting the error:

ERROR: argument for function "exp" too big
SQL state: 22003

I need to write a stored procedude for the Exponential as:

  • If exp(value) throws argument for function "exp" too big
  • then return 0
  • else return exp(value)

Please help me how to process this stored procedure.

有帮助吗?

解决方案

This is what's happening:

regress=# SELECT exp(NUMERIC '6000');
ERROR:  argument for function "exp" too big

You're passing an unrealistically large value to exp(). It's way too big to overflow a float8 (double) and can only be represented as a NUMERIC. Even there, there's a limit, and you hit it when you go above exp(5999).

For hard maths you might want to try PL/R, an in-database embedded version of the R language.

It's hard to say what to do, because you haven't really explained what the query is for, what the inputs to exp are supposed to be, etc.

Returning zero for an exponent that's too big is kind of crazy. Why?


To trap an exception, use BEGIN ... EXCEPTION in PL/PgSQL.

I've written the below function to return NaN ("not a number") instead of zero, as I think returning zero is just downright wrong. Change it if you need to. It might also make a little bit of sense to return NULL.

CREATE OR REPLACE FUNCTION exp_if_possible(numeric) RETURNS numeric as $$
BEGIN
    RETURN exp($1);
EXCEPTION
    WHEN numeric_value_out_of_range THEN
        RETURN 'NaN';
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE;

The error code numeric_value_out_of_range was obtained by looking up the SQLSTATE 22003 you get from the out-of-range exp in Appendix A. PostgreSQL Error Codes in the Pg manual. You'll see a link to it in the documentation about BEGIN ... EXCEPTION.


I initially said that if it's to be done at all it should be done by testing the input, but I think I was wrong about that. There's no guarantee that the limit will be exp(6000), so you're right to use exception handling even though it'll be slow and clumsy. I'll update this response with an exception handling version in a sec.

CREATE OR REPLACE FUNCTION crazy_exp(numeric) RETURNS numeric AS $$
-- exp(6000) and above will throw 'argument for function "Exp" too big
-- For such cases, return zero because [insert explanation here]
SELECT CASE WHEN $1 < 6000 THEN exp($1) ELSE 0 END;
$$ LANGUAGE 'sql' IMMUTABLE;

CREATE OR REPLACE FUNCTION crazy_exp(float8) RETURNS float8 AS $$
-- float8 goes out-of-range above about exp(600)
SELECT CASE WHEN $1 <= 600 THEN exp($1) ELSE 0 END;
$$ LANGUAGE 'sql' IMMUTABLE;

That's massively more efficient than trapping the "out of range" exception in PL/PgSQL, and makes your intent clearer too.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top