core: fix wrong results with the unary minus in calc expressions

This commit is contained in:
Sébastien Helleu 2019-09-24 20:49:48 +02:00
parent dc5e334f5c
commit 7d795c4d53
2 changed files with 57 additions and 5 deletions

View File

@ -33,6 +33,15 @@
#include "wee-arraylist.h"
#include "wee-string.h"
enum t_calc_symbol
{
CALC_SYMBOL_NONE = 0,
CALC_SYMBOL_PARENTHESIS_OPEN,
CALC_SYMBOL_PARENTHESIS_CLOSE,
CALC_SYMBOL_VALUE,
CALC_SYMBOL_OPERATOR,
};
/*
* Callback called to free a value or op in the arraylist.
@ -178,7 +187,10 @@ calc_format_result (double value, char *result, int max_size)
* used (instead of a comma in French for example)
*/
setlocale (LC_ALL, "C");
snprintf (result, max_size, "%.10f", value);
snprintf (result, max_size,
"%.10f",
/* ensure result is not "-0" */
(value == -0.0) ? 0.0 : value);
setlocale (LC_ALL, "");
pos_point = strchr (result, '.');
@ -225,7 +237,8 @@ calc_expression (const char *expr)
struct t_arraylist *list_values, *list_ops;
char str_result[64], *ptr_operator, *operator;
int i, i2, index_op, decimals;
double value, *ptr_value;
enum t_calc_symbol last_symbol;
double value, factor, *ptr_value;
list_values = NULL;
list_ops = NULL;
@ -250,6 +263,7 @@ calc_expression (const char *expr)
if (!list_ops)
goto end;
last_symbol = CALC_SYMBOL_NONE;
for (i = 0; expr[i]; i++)
{
if (expr[i] == ' ')
@ -261,11 +275,22 @@ calc_expression (const char *expr)
{
ptr_operator = string_strndup (expr + i, 1);
arraylist_add (list_ops, ptr_operator);
last_symbol = CALC_SYMBOL_PARENTHESIS_OPEN;
}
else if (isdigit (expr[i]) || (expr[i] == '.'))
else if (isdigit (expr[i]) || (expr[i] == '.')
|| ((expr[i] == '-')
&& ((last_symbol == CALC_SYMBOL_NONE)
|| (last_symbol == CALC_SYMBOL_PARENTHESIS_OPEN)
|| (last_symbol == CALC_SYMBOL_OPERATOR))))
{
value = 0;
decimals = 0;
factor = 1;
if (expr[i] == '-')
{
factor = -1;
i++;
}
while (expr[i] && (isdigit (expr[i]) || (expr[i] == '.')))
{
if (expr[i] == '.')
@ -288,9 +313,11 @@ calc_expression (const char *expr)
i++;
}
i--;
value *= factor;
ptr_value = malloc (sizeof (value));
*ptr_value = value;
arraylist_add (list_values, ptr_value);
last_symbol = CALC_SYMBOL_VALUE;
}
else if (expr[i] == ')')
{
@ -307,6 +334,7 @@ calc_expression (const char *expr)
index_op = arraylist_size (list_ops) - 1;
if (index_op >= 0)
arraylist_remove (list_ops, index_op);
last_symbol = CALC_SYMBOL_PARENTHESIS_CLOSE;
}
else
{
@ -314,7 +342,7 @@ calc_expression (const char *expr)
i2 = i + 1;
while (expr[i2] && (expr[i2] != ' ') && (expr[i2] != '(')
&& (expr[i2] != ')') && (expr[i2] != '.')
&& !isdigit (expr[i2]))
&& (expr[i2] != '-') && !isdigit (expr[i2]))
{
i2++;
}
@ -334,6 +362,7 @@ calc_expression (const char *expr)
}
arraylist_add (list_ops, operator);
}
last_symbol = CALC_SYMBOL_OPERATOR;
}
}

View File

@ -53,13 +53,13 @@ TEST(CoreCalc, Expression)
WEE_CHECK_CALC("0", "-");
WEE_CHECK_CALC("0", "*");
WEE_CHECK_CALC("0", "/");
WEE_CHECK_CALC("0", "%");
WEE_CHECK_CALC("0", "0/0");
WEE_CHECK_CALC("0", "0//0");
WEE_CHECK_CALC("0", "0%0");
/* no operator */
WEE_CHECK_CALC("123", "123");
WEE_CHECK_CALC("-2", "-2");
WEE_CHECK_CALC("1.5", "1.5");
/* addition */
@ -71,6 +71,25 @@ TEST(CoreCalc, Expression)
WEE_CHECK_CALC("5", "8-3");
WEE_CHECK_CALC("-5", "3-8");
/* unary minus */
WEE_CHECK_CALC("0", "-0");
WEE_CHECK_CALC("-0.001", "-0.001");
WEE_CHECK_CALC("0", "(-0)");
WEE_CHECK_CALC("0", "0-0");
WEE_CHECK_CALC("-1", "-1");
WEE_CHECK_CALC("-2", "-1+-1");
WEE_CHECK_CALC("0", "-1+1");
WEE_CHECK_CALC("-2", "-3+1");
WEE_CHECK_CALC("-3", "1+-4");
WEE_CHECK_CALC("-4", "2*-2");
WEE_CHECK_CALC("-6", "-3*2");
WEE_CHECK_CALC("9", "-3*-3");
WEE_CHECK_CALC("-6", "3*(-2)");
WEE_CHECK_CALC("6", "-3*(-2)");
WEE_CHECK_CALC("12", "(-3)*(-4)");
WEE_CHECK_CALC("15", "(-3)*-5");
WEE_CHECK_CALC("9", "(-3)*(-4+1)");
/* multiplication */
WEE_CHECK_CALC("20", "10*2");
WEE_CHECK_CALC("-8", "-2*4");
@ -86,6 +105,8 @@ TEST(CoreCalc, Expression)
/* modulo */
WEE_CHECK_CALC("4", "9%5");
WEE_CHECK_CALC("0.2", "9.2%3");
WEE_CHECK_CALC("-2", "-2%4");
WEE_CHECK_CALC("0", "-2%2");
/* multiple operators */
WEE_CHECK_CALC("11", "5+2*3");
@ -105,6 +126,8 @@ TEST(CoreCalc, Expression)
WEE_CHECK_CALC("0", "1/123456789012");
/* expressions with parentheses */
WEE_CHECK_CALC("6", "((6))");
WEE_CHECK_CALC("-7.234", "((-7.234))");
WEE_CHECK_CALC("21", "(5+2)*3");
WEE_CHECK_CALC("3.15", "(1.5+2)*(1.8/2)");
WEE_CHECK_CALC("-1.26", "(1.5+2)*(1.8/(2-7))");