From 8cc2313ea49e635452b545b3ca9c43e28d1e86cd Mon Sep 17 00:00:00 2001 From: chendotjs Date: Thu, 16 Mar 2017 20:50:10 +0800 Subject: [PATCH 1/2] fix overflow check bug --- tinyexpr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinyexpr.c b/tinyexpr.c index f2a6175..064e482 100755 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -127,7 +127,7 @@ static double fac(double a) {/* simplest version of fac */ unsigned int ua = (unsigned int)(a); unsigned long int result = 1, i = 1; for (i = 1; i <= ua; i++) { - if (ua > ULONG_MAX / result) + if (i > ULONG_MAX / result) return INFINITY; result *= i; } From f11d02f9a90546d1370d93c39533f0d41328b441 Mon Sep 17 00:00:00 2001 From: chendotjs Date: Sun, 26 Mar 2017 22:30:08 +0800 Subject: [PATCH 2/2] add ncr and npr --- test.c | 41 ++++++++++++++++++++++++++++++++++------- tinyexpr.c | 19 ++++++++++++++++++- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/test.c b/test.c index 82611eb..c772950 100644 --- a/test.c +++ b/test.c @@ -214,6 +214,12 @@ void test_nans() { "1%(1%0)", "(1%0)%1", "fac(-1)", + "ncr(2, 4)", + "ncr(-2, 4)", + "ncr(2, -4)", + "npr(2, 4)", + "npr(-2, 4)", + "npr(2, -4)", }; int i; @@ -242,6 +248,12 @@ void test_infs() { "log(0)", "pow(2,10000000)", "fac(300)", + "ncr(300,100)", + "ncr(300000,100)", + "ncr(300000,100)*8", + "npr(3,2)*ncr(300000,100)", + "npr(100,90)", + "npr(30,25)", }; int i; @@ -618,13 +630,28 @@ void test_pow() { void test_combinatorics() { test_case cases[] = { - {"fac(0) ", 1}, - {"fac(0.2) ", 1}, - {"fac(1) ", 1}, - {"fac(2) ", 2}, - {"fac(3) ", 6}, - {"fac(4.8) ", 24}, - {"fac(10) ", 3628800}, + {"fac(0)", 1}, + {"fac(0.2)", 1}, + {"fac(1)", 1}, + {"fac(2)", 2}, + {"fac(3)", 6}, + {"fac(4.8)", 24}, + {"fac(10)", 3628800}, + + {"ncr(0,0)", 1}, + {"ncr(10,1)", 10}, + {"ncr(10,0)", 1}, + {"ncr(10,10)", 1}, + {"ncr(16,7)", 11440}, + {"ncr(16,9)", 11440}, + {"ncr(100,95)", 75287520}, + + {"npr(0,0)", 1}, + {"npr(10,1)", 10}, + {"npr(10,0)", 1}, + {"npr(10,10)", 3628800}, + {"npr(20,5)", 1860480}, + {"npr(100,4)", 94109400}, }; diff --git a/tinyexpr.c b/tinyexpr.c index 064e482..115ea11 100755 --- a/tinyexpr.c +++ b/tinyexpr.c @@ -125,7 +125,7 @@ static double fac(double a) {/* simplest version of fac */ if (a > UINT_MAX) return INFINITY; unsigned int ua = (unsigned int)(a); - unsigned long int result = 1, i = 1; + unsigned long int result = 1, i; for (i = 1; i <= ua; i++) { if (i > ULONG_MAX / result) return INFINITY; @@ -133,6 +133,21 @@ static double fac(double a) {/* simplest version of fac */ } return (double)result; } +static double ncr(double n, double r) { + if (n < 0.0 || r < 0.0 || n < r) return NAN; + if (n > UINT_MAX || r > UINT_MAX) return INFINITY; + unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i; + unsigned long int result = 1; + if (ur > un / 2) ur = un - ur; + for (i = 1; i <= ur; i++) { + if (result > ULONG_MAX / (un - ur + i)) + return INFINITY; + result *= un - ur + i; + result /= i; + } + return result; +} +static double npr(double n, double r) {return ncr(n, r) * fac(r);} static const te_variable functions[] = { /* must be in alphabetical order */ @@ -155,6 +170,8 @@ static const te_variable functions[] = { {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, #endif {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, + {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, + {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0}, {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0}, {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0},