void test_nans() {

    const char *nans[] = {
        "0/0",
        "1%0",
        "1%(1%0)",
        "(1%0)%1",
    };

    int i;
    for (i = 0; i < sizeof(nans) / sizeof(const char *); ++i) {
        const char *expr = nans[i];

        int err;
        const double r = te_interp(expr, &err);
        lequal(err, 0);
        lok(r != r);

        te_expr *n = te_compile(expr, 0, 0, &err);
        lok(n);
        lequal(err, 0);
        const double c = te_eval(n);
        lok(c != c);
        te_free(n);
    }
}
TEST(tinyexpr_suite, testNask)
{
     int error;

     const double ecx1 = te_interp("512*1024/4", &error);
     CHECK(!std::isnan(ecx1));
     CHECK_EQUAL(131072, ecx1);

     const double ecx2 = te_interp("512/4", &error);
     CHECK(!std::isnan(ecx2));
     CHECK_EQUAL(128, ecx2);

     const double dw = te_interp("8*3-1", &error);
     CHECK(!std::isnan(dw));
     CHECK_EQUAL(23, dw);
}
TEST(tinyexpr_suite, testInt)
{
     int error;

     /* Returns 10. */
     const double a = te_interp("(5+5)", 0);
     CHECK_EQUAL(10, a);

     /* Returns 10, error is set to 0. */
     const double b = te_interp("(5+5)", &error);
     CHECK_EQUAL(10, b);
     CHECK_EQUAL(0, error);

     /* Returns NaN, error is set to 4. */
     const double c = te_interp("(5+5", &error);
     CHECK(std::isnan(c));
     CHECK_EQUAL(4, error);
}
void test_syntax() {
    test_case errors[] = {
        {"", 1},
        {"1+", 2},
        {"1)", 2},
        {"(1", 2},
        {"1**1", 3},
        {"1*2(+4", 4},
        {"1*2(1+4", 4},
        {"a+5", 1},
        {"A+5", 1},
        {"Aa+5", 1},
        {"1^^5", 3},
        {"1**5", 3},
        {"sin(cos5", 8},
    };


    int i;
    for (i = 0; i < sizeof(errors) / sizeof(test_case); ++i) {
        const char *expr = errors[i].expr;
        const int e = errors[i].answer;

        int err;
        const double r = te_interp(expr, &err);
        lequal(err, e);
        lok(r != r);

        te_expr *n = te_compile(expr, 0, 0, &err);
        lequal(err, e);
        lok(!n);

        if (err != e) {
            printf("FAILED: %s\n", expr);
        }

        const double k = te_interp(expr, 0);
        lok(k != k);
    }
}
Esempio n. 5
0
/// Evaluate math expressions.
static int evaluate_expression(const wchar_t *cmd, parser_t &parser, io_streams_t &streams,
                               math_cmd_opts_t &opts, wcstring &expression) {
    UNUSED(parser);

    int retval = STATUS_CMD_OK;
    te_error_t error;
    std::string narrow_str = wcs2string(expression);
    // Switch locale while computing stuff.
    // This means that the "." is always the radix character,
    // so numbers work the same across locales.
    char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL));
    setlocale(LC_NUMERIC, "C");
    double v = te_interp(narrow_str.c_str(), &error);

    if (error.position == 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.
        const char *error_message = NULL;
        if (std::isinf(v)) {
            error_message = "Result is infinite";
        } else if (std::isnan(v)) {
            error_message = "Result is not a number";
        } else if (std::abs(v) >= kMaximumContiguousInteger) {
            error_message = "Result magnitude is too large";
        }
        if (error_message) {
            streams.err.append_format(L"%ls: Error: %s\n", cmd, error_message);
            streams.err.append_format(L"'%ls'\n", expression.c_str());
            retval = STATUS_CMD_ERROR;
        } else {
            streams.out.append(format_double(v, opts));
            streams.out.push_back(L'\n');
        }
    } else {
        streams.err.append_format(L"%ls: Error: %ls\n", cmd, math_describe_error(error).c_str());
        streams.err.append_format(L"'%ls'\n", expression.c_str());
        streams.err.append_format(L"%*ls%ls\n", error.position - 1, L" ",L"^");
        retval = STATUS_CMD_ERROR;
    }
    setlocale(LC_NUMERIC, saved_locale);
    free(saved_locale);
    return retval;
}
void test_results() {
    test_case cases[] = {
        {"1", 1},
        {"1 ", 1},
        {"(1)", 1},

        {"pi", 3.14159},
        {"atan(1)*4 - pi", 0},
        {"e", 2.71828},

        {"2+1", 2+1},
        {"(((2+(1))))", 2+1},
        {"3+2", 3+2},

        {"3+2+4", 3+2+4},
        {"(3+2)+4", 3+2+4},
        {"3+(2+4)", 3+2+4},
        {"(3+2+4)", 3+2+4},

        {"3*2*4", 3*2*4},
        {"(3*2)*4", 3*2*4},
        {"3*(2*4)", 3*2*4},
        {"(3*2*4)", 3*2*4},

        {"3-2-4", 3-2-4},
        {"(3-2)-4", (3-2)-4},
        {"3-(2-4)", 3-(2-4)},
        {"(3-2-4)", 3-2-4},

        {"3/2/4", 3.0/2.0/4.0},
        {"(3/2)/4", (3.0/2.0)/4.0},
        {"3/(2/4)", 3.0/(2.0/4.0)},
        {"(3/2/4)", 3.0/2.0/4.0},

        {"(3*2/4)", 3.0*2.0/4.0},
        {"(3/2*4)", 3.0/2.0*4.0},
        {"3*(2/4)", 3.0*(2.0/4.0)},

        {"asin sin .5", 0.5},
        {"sin asin .5", 0.5},
        {"ln exp .5", 0.5},
        {"exp ln .5", 0.5},

        {"asin sin-.5", -0.5},
        {"asin sin-0.5", -0.5},
        {"asin sin -0.5", -0.5},
        {"asin (sin -0.5)", -0.5},
        {"asin (sin (-0.5))", -0.5},
        {"asin sin (-0.5)", -0.5},
        {"(asin sin (-0.5))", -0.5},

        {"log10 1000", 3},
        {"log10 1e3", 3},
        {"log10 1000", 3},
        {"log10 1e3", 3},
        {"log10(1000)", 3},
        {"log10(1e3)", 3},
        {"log10 1.0e3", 3},
        {"10^5*5e-5", 5},

#ifdef TE_NAT_LOG
        {"log 1000", 6.9078},
        {"log e", 1},
        {"log (e^10)", 10},
#else
        {"log 1000", 3},
#endif

        {"ln (e^10)", 10},
        {"100^.5+1", 11},
        {"100 ^.5+1", 11},
        {"100^+.5+1", 11},
        {"100^--.5+1", 11},
        {"100^---+-++---++-+-+-.5+1", 11},

        {"100^-.5+1", 1.1},
        {"100^---.5+1", 1.1},
        {"100^+---.5+1", 1.1},
        {"1e2^+---.5e0+1e0", 1.1},
        {"--(1e2^(+(-(-(-.5e0))))+1e0)", 1.1},

        {"sqrt 100 + 7", 17},
        {"sqrt 100 * 7", 70},
        {"sqrt (100 * 100)", 100},

        {"1,2", 2},
        {"1,2+1", 3},
        {"1+1,2+2,2+1", 3},
        {"1,2,3", 3},
        {"(1,2),3", 3},
        {"1,(2,3)", 3},
        {"-(1,(2,3))", -3},

        {"2^2", 4},
        {"pow(2,2)", 4},

        {"atan2(1,1)", 0.7854},
        {"atan2(1,2)", 0.4636},
        {"atan2(2,1)", 1.1071},
        {"atan2(3,4)", 0.6435},
        {"atan2(3+3,4*2)", 0.6435},
        {"atan2(3+3,(4*2))", 0.6435},
        {"atan2((3+3),4*2)", 0.6435},
        {"atan2((3+3),(4*2))", 0.6435},

    };


    int i;
    for (i = 0; i < sizeof(cases) / sizeof(test_case); ++i) {
        const char *expr = cases[i].expr;
        const double answer = cases[i].answer;

        int err;
        const double ev = te_interp(expr, &err);
        lok(!err);
        lfequal(ev, answer);

        if (err) {
            printf("FAILED: %s (%d)\n", expr, err);
        }
    }
}