diff --git a/samples/distro-examples/tests/all.bas b/samples/distro-examples/tests/all.bas index cc656336..203931c0 100644 --- a/samples/distro-examples/tests/all.bas +++ b/samples/distro-examples/tests/all.bas @@ -99,7 +99,7 @@ print "TSAVE:" ':TSAVE file, var print "VIEW:" ':VIEW [x1,y1,x2,y2 [,color [,border-color]]] print "WINDOW:" ':WINDOW [x1,y1,x2,y2] print "WRITE:" ':WRITE #fileN; var1 [, ...] -print "ABS:" + ABS (12.2222) +print "ABS:" + ABS (-12.2222) print "ABSMAX:" + ABSMAX (1,2,3,4,5,6,7,8,9) print "ABSMIN:" + ABSMIN (1,2,3,4,5,6,7,8,9) print "ACOS:" + ACOS (x) @@ -217,6 +217,7 @@ print "SQR:" + SQR (x) print "SQUEEZE:" + SQUEEZE (s) print "STATMEAN:" + STATMEAN (1,2,3,4,5,6,7,8,9) print "STATMEANDEV:" + STATMEANDEV (1,2,3,4,5,6,7,8,9) +print "STATMEDIAN:" + STATMEDIAN(1,2,3,4,5,6,7,8,9) print "STATSPREADP:" + STATSPREADP (1,2,3,4,5,6,7,8,9) print "STATSPREADS:" + STATSPREADS (1,2,3,4,5,6,7,8,9) print "STATSTD:" + STATSTD (1,2,3,4,5,6,7,8,9) diff --git a/samples/distro-examples/tests/output/all.out b/samples/distro-examples/tests/output/all.out index d4b49a47..f6f13563 100644 --- a/samples/distro-examples/tests/output/all.out +++ b/samples/distro-examples/tests/output/all.out @@ -103,7 +103,7 @@ ATANH:nan ATN:1.489673934694 BCS:catsanddogs BGETC: -BIN:00000000000000000000000000001100 +BIN:1100 CAT: CBS:catsanddogs CEIL:13 @@ -200,6 +200,7 @@ SQR:3.50713558335004 SQUEEZE:catsanddogs STATMEAN:5 STATMEANDEV:2.22222222222222 +STATMEDIAN:5 STATSPREADP:6.66666666666667 STATSPREADS:7.5 STATSTD:2.73861278752583 diff --git a/samples/distro-examples/tests/strings.bas b/samples/distro-examples/tests/strings.bas index d9a34aa3..dbf0fb9a 100644 --- a/samples/distro-examples/tests/strings.bas +++ b/samples/distro-examples/tests/strings.bas @@ -202,3 +202,11 @@ REM Only TRIM Strings if (trim(10) != 10) then throw "err" if (trim(10.1) != 10.1) then throw "err" if (trim([1,2,3]) != [1,2,3]) then throw "err" + +REM test for integer-to-string conversion +number_test=[[, "0", "0", "0"], [0, "0", "0", "0"], [7, "111", "7", "7"], [14, "1110", "16", "E"], [2090, "100000101010", "4052", "82A"]] +for t in number_test + if (t[1] != bin(t[0])) then throw "err: bin(" + str(t[0]) + ") <> " + t[1] + if (t[2] != oct(t[0])) then throw "err: oct(" + str(t[0]) + ") <> " + t[2] + if (t[3] != hex(t[0])) then throw "err: hex(" + str(t[0]) + ") <> " + t[3] +next \ No newline at end of file diff --git a/src/common/blib_func.c b/src/common/blib_func.c index 3ff7b691..4a30511a 100644 --- a/src/common/blib_func.c +++ b/src/common/blib_func.c @@ -31,6 +31,7 @@ static char *date_m3_table[] = TABLE_MONTH_3C; static char *date_mN_table[] = TABLE_MONTH_FULL; #define BUF_LEN 64 +#define BIN_LEN 32 // Number of max bits (digits) kwBIN creates /* */ @@ -957,19 +958,33 @@ void cmd_str1(long funcCode, var_t *arg, var_t *r) { // case kwBIN: l = v_getint(arg); - IF_ERR_RETURN; - tb = malloc(33); - memset(tb, 0, 33); - for (int i = 0; i < 32; i++) { + IF_ERR_RETURN; + + if (l == 0) { + v_createstr(r, "0"); + break; + } + + tb = malloc(BIN_LEN + 1); + memset(tb, 0, BIN_LEN + 1); + + for (int i = 0; i < BIN_LEN; i++) { if (l & (1 << i)) { - tb[31 - i] = '1'; + tb[BIN_LEN - 1 - i] = '1'; } else { - tb[31 - i] = '0'; + tb[BIN_LEN - 1 - i] = '0'; } } + + // remove preceding zeros + p = tb; + while (*p == '0') { + p++; + } - r->v.p.ptr = tb; - r->v.p.length = strlen(r->v.p.ptr) + 1; + v_createstr(r, p); + free(tb); + break; case kwHEX: // @@ -2307,7 +2322,7 @@ void cmd_genfunc(long funcCode, var_t *r) { for (int i = 0; i < count - 1; i++) { r->v.n = r->v.n + (poly[i].x - poly[i + 1].x) * (poly[i].y + poly[i + 1].y); } - r->v.n = fabs(r->v.n / 2); + r->v.n = r->v.n / 2; free(poly); } @@ -2327,17 +2342,21 @@ void cmd_genfunc(long funcCode, var_t *r) { IF_ERR_RETURN; err = geo_polycentroid(poly, count, &x, &y, &area); - v_toarray1(r, 2); - v_setreal(v_elem(r, 0), x); - v_setreal(v_elem(r, 1), y); if (err == 1) { rt_raise(ERR_WRONG_POLY); } if (err == 2) { - rt_raise(ERR_CENTROID); - } + // return empty array insead of "rt_raise(ERR_CENTROID);" + v_toarray1(r, 0); + free(poly); + break; + } + v_toarray1(r, 2); + v_setreal(v_elem(r, 0), x); + v_setreal(v_elem(r, 1), y); + free(poly); } break; @@ -2600,6 +2619,7 @@ void cmd_genfunc(long funcCode, var_t *r) { // // case kwSTATMEANDEV: + case kwSTATMEDIAN: case kwSTATSTD: case kwSTATSPREADS: case kwSTATSPREADP: @@ -2670,6 +2690,9 @@ void cmd_genfunc(long funcCode, var_t *r) { case kwSTATMEANDEV: r->v.n = statmeandev(dar, tcount); break; + case kwSTATMEDIAN: + r->v.n = statmedian(dar, tcount); + break; case kwSTATSTD: r->v.n = statstd(dar, tcount); break; diff --git a/src/common/blib_math.c b/src/common/blib_math.c index 1c3d96c5..5c2ba7c1 100644 --- a/src/common/blib_math.c +++ b/src/common/blib_math.c @@ -232,6 +232,36 @@ var_num_t statmeandev(var_num_t *e, int count) { return sum / count; } +// +// compare function for median calculation +// +int median_compare(const void * a, const void * b) { + var_num_t fa = *(var_num_t*) a; + var_num_t fb = *(var_num_t*) b; + return (fa > fb) - (fa < fb); +} + +// +// Median +// +// Median is calculated using quicksort with a complexity of O(n log n). +// Faster approch would be to implement i.e. quickselect with a +// complexity of O(n). +// +var_num_t statmedian(var_num_t *e, int count) { + if (count == 0) { + return 0; + } + + qsort(e, count, sizeof(var_num_t), median_compare); + + if (count % 2 == 0) { + return (e[count/2] + e[count/2 - 1]) / 2; + } else { + return e[count/2]; + } +} + // // Standard deviation // diff --git a/src/common/blib_math.h b/src/common/blib_math.h index 38ae21b5..dd5f45e9 100644 --- a/src/common/blib_math.h +++ b/src/common/blib_math.h @@ -75,6 +75,17 @@ var_num_t mat_determ(var_num_t *a, int n, double toler); */ var_num_t statmeandev(var_num_t *e, int count); +/** + * @ingroup math + * + * Median + * + * @param e array with numbers + * @param count number of elements of e + * @return the median + */ +var_num_t statmedian(var_num_t *e, int count); + /** * @ingroup math * diff --git a/src/common/eval.c b/src/common/eval.c index d48dcc92..b746ae95 100644 --- a/src/common/eval.c +++ b/src/common/eval.c @@ -1175,6 +1175,7 @@ static inline void eval_callf(var_t *r) { case kwSUMSV: case kwSTATMEAN: case kwSTATMEANDEV: + case kwSTATMEDIAN: case kwSTATSTD: case kwSTATSPREADS: case kwSTATSPREADP: diff --git a/src/common/kw.h b/src/common/kw.h index bb004e1c..0d2e598b 100644 --- a/src/common/kw.h +++ b/src/common/kw.h @@ -348,6 +348,7 @@ enum func_keywords { kwSUM, kwSUMSV, kwSTATMEAN, + kwSTATMEDIAN, kwSTATSTD, kwSTATMEANDEV, kwSTATSPREADS, diff --git a/src/languages/keywords.en.c b/src/languages/keywords.en.c index 2f858c71..4265e1ee 100644 --- a/src/languages/keywords.en.c +++ b/src/languages/keywords.en.c @@ -288,6 +288,7 @@ struct func_keyword_s func_table[] = { { "SUM", kwSUM }, { "SUMSQ", kwSUMSV }, { "STATMEAN", kwSTATMEAN }, +{ "STATMEDIAN", kwSTATMEDIAN}, { "STATSTD", kwSTATSTD}, { "STATMEANDEV", kwSTATMEANDEV }, { "STATSPREADS", kwSTATSPREADS },