diff --git a/doc_src/math.txt b/doc_src/math.txt index 2a3ea5fbe..9e62272b2 100644 --- a/doc_src/math.txt +++ b/doc_src/math.txt @@ -17,7 +17,7 @@ The following options are available: \subsection return-values Return Values -If the expression is successfully evaluated the return `status` is zero (success) else one. +If the expression is successfully evaluated and doesn't over/underflow or return NaN the return `status` is zero (success) else one. \subsection math-syntax diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index 2764ddd4c..483527ae8 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "tinyexpr.h" @@ -145,7 +146,28 @@ static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_ double v = te_interp(narrow_str.c_str(), &error); if (error.position == 0) { - if (opts.scale == 0) { + // Check some runtime errors after the fact. + // TODO: Really, this should be done in tinyexpr + // (e.g. infinite is the result of "x / 0"), + // but that's much more work. + if (std::isinfinite(v)) { + streams.err.append_format(L"%ls: Error: Result is infinite\n", cmd); + streams.err.append_format(L"'%ls'\n", expression.c_str()); + retval = STATUS_CMD_ERROR; + } else if (std::isnan(v)) { + streams.err.append_format(L"%ls: Error: Result is not a number\n", cmd); + streams.err.append_format(L"'%ls'\n", expression.c_str()); + retval = STATUS_CMD_ERROR; + } else if (v >= LONG_MAX) { + streams.err.append_format(L"%ls: Error: Result is too large\n", cmd); + streams.err.append_format(L"'%ls'\n", expression.c_str()); + retval = STATUS_CMD_ERROR; + } else if (v <= LONG_MIN) { + streams.err.append_format(L"%ls: Error: Result is too small\n", cmd); + streams.err.append_format(L"'%ls'\n", expression.c_str()); + retval = STATUS_CMD_ERROR; + } else if (opts.scale == 0) { + // Normal results streams.out.append_format(L"%ld\n", static_cast(v)); } else { streams.out.append_format(L"%.*lf\n", opts.scale, v);