mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-22 03:02:06 +00:00
Update mathematical functions (#675)
Document the existing `ROUND`, `CEIL`, and `FLOOR` functions Also update the trig function docs for searchability Implement `POW` and `LOG` Addresses part of #675 Implement ** for integer exponents ** has higher precedence than -, like Python, so -3**4 == -(3**4) == 81
This commit is contained in:
@@ -182,6 +182,8 @@ static struct KeywordMapping {
|
||||
{"FLOOR", T_OP_FLOOR},
|
||||
{"DIV", T_OP_FDIV},
|
||||
{"MUL", T_OP_FMUL},
|
||||
{"POW", T_OP_POW},
|
||||
{"LOG", T_OP_LOG},
|
||||
{"SIN", T_OP_SIN},
|
||||
{"COS", T_OP_COS},
|
||||
{"TAN", T_OP_TAN},
|
||||
@@ -488,7 +490,7 @@ struct KeywordDictNode {
|
||||
uint16_t children[0x60 - ' '];
|
||||
struct KeywordMapping const *keyword;
|
||||
/* Since the keyword structure is invariant, the min number of nodes is known at compile time */
|
||||
} keywordDict[350] = {0}; /* Make sure to keep this correct when adding keywords! */
|
||||
} keywordDict[352] = {0}; /* Make sure to keep this correct when adding keywords! */
|
||||
|
||||
/* Convert a char into its index into the dict */
|
||||
static inline uint8_t dictIndex(char c)
|
||||
@@ -1606,13 +1608,20 @@ static int yylex_NORMAL(void)
|
||||
lexer_GetLineNo(), lexer_GetColNo());
|
||||
for (;;) {
|
||||
int c = nextChar();
|
||||
char secondChar;
|
||||
|
||||
switch (c) {
|
||||
/* Ignore whitespace and comments */
|
||||
|
||||
case '*':
|
||||
if (!lexerState->atLineStart)
|
||||
if (!lexerState->atLineStart) { /* Either MUL or EXP */
|
||||
secondChar = peek(0);
|
||||
if (secondChar == '*') {
|
||||
shiftChars(1);
|
||||
return T_OP_EXP;
|
||||
}
|
||||
return T_OP_MUL;
|
||||
}
|
||||
warning(WARNING_OBSOLETE,
|
||||
"'*' is deprecated for comments, please use ';' instead\n");
|
||||
/* fallthrough */
|
||||
@@ -1651,7 +1660,6 @@ static int yylex_NORMAL(void)
|
||||
return T_COMMA;
|
||||
|
||||
/* Handle ambiguous 1- or 2-char tokens */
|
||||
char secondChar;
|
||||
case '/': /* Either division or a block comment */
|
||||
secondChar = peek(0);
|
||||
if (secondChar == '*') {
|
||||
|
||||
@@ -125,6 +125,22 @@ int32_t math_Div(int32_t i, int32_t j)
|
||||
return double2fx(fx2double(i) / fx2double(j));
|
||||
}
|
||||
|
||||
/*
|
||||
* Power
|
||||
*/
|
||||
int32_t math_Pow(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fx(pow(fx2double(i), fx2double(j)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Logarithm
|
||||
*/
|
||||
int32_t math_Log(int32_t i, int32_t j)
|
||||
{
|
||||
return double2fx(log(fx2double(i)) / log(fx2double(j)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Round
|
||||
*/
|
||||
|
||||
@@ -353,6 +353,11 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
|
||||
%left T_OP_SHL T_OP_SHR
|
||||
%left T_OP_MUL T_OP_DIV T_OP_MOD
|
||||
%left T_OP_NOT
|
||||
|
||||
%left NEG /* negation -- unary minus */
|
||||
|
||||
%left T_OP_EXP
|
||||
|
||||
%left T_OP_DEF
|
||||
%left T_OP_BANK T_OP_ALIGN
|
||||
%left T_OP_SIN
|
||||
@@ -364,6 +369,8 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
|
||||
%left T_OP_ATAN2
|
||||
%left T_OP_FDIV
|
||||
%left T_OP_FMUL
|
||||
%left T_OP_POW
|
||||
%left T_OP_LOG
|
||||
%left T_OP_ROUND
|
||||
%left T_OP_CEIL
|
||||
%left T_OP_FLOOR
|
||||
@@ -381,8 +388,6 @@ static inline void failAssertMsg(enum AssertionType type, char const *msg)
|
||||
%left T_OP_STRLWR
|
||||
%left T_OP_STRFMT
|
||||
|
||||
%left NEG /* negation -- unary minus */
|
||||
|
||||
%token <tzSym> T_LABEL
|
||||
%token <tzSym> T_ID
|
||||
%token <tzSym> T_LOCAL_ID
|
||||
@@ -1131,6 +1136,9 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
||||
| relocexpr T_OP_MOD relocexpr {
|
||||
rpn_BinaryOp(RPN_MOD, &$$, &$1, &$3);
|
||||
}
|
||||
| relocexpr T_OP_EXP relocexpr {
|
||||
rpn_BinaryOp(RPN_EXP, &$$, &$1, &$3);
|
||||
}
|
||||
| T_OP_ADD relocexpr %prec NEG { $$ = $2; }
|
||||
| T_OP_SUB relocexpr %prec NEG { rpn_UNNEG(&$$, &$2); }
|
||||
| T_OP_NOT relocexpr %prec NEG { rpn_UNNOT(&$$, &$2); }
|
||||
@@ -1166,6 +1174,12 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
||||
| T_OP_FMUL T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, math_Mul($3, $5));
|
||||
}
|
||||
| T_OP_POW T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, math_Pow($3, $5));
|
||||
}
|
||||
| T_OP_LOG T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, math_Log($3, $5));
|
||||
}
|
||||
| T_OP_SIN T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, math_Sin($3));
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ A great number of operators you can use in expressions are available (listed fro
|
||||
.It Sy Operator Ta Sy Meaning
|
||||
.It Li \&( \&) Ta Precedence override
|
||||
.It Li FUNC() Ta Built-in function call
|
||||
.It Li ** Ta Exponent
|
||||
.It Li ~ + - Ta Unary complement/plus/minus
|
||||
.It Li * / % Ta Multiply/divide/modulo
|
||||
.It Li << >> Ta Shift left/right
|
||||
@@ -190,12 +191,17 @@ delim $$
|
||||
.It Sy Name Ta Sy Operation
|
||||
.It Fn DIV x y Ta $x \[di] y$
|
||||
.It Fn MUL x y Ta $x \[mu] y$
|
||||
.It Fn SIN x Ta $sin ( x )$
|
||||
.It Fn COS x Ta $cos ( x )$
|
||||
.It Fn TAN x Ta $tan ( x )$
|
||||
.It Fn ASIN x Ta $asin ( x )$
|
||||
.It Fn ACOS x Ta $acos ( x )$
|
||||
.It Fn ATAN x Ta $atan ( x )$
|
||||
.It Fn POW x y Ta $x$ to the $y$ power
|
||||
.It Fn LOG x y Ta Logarithm of $x$ to the base $y$
|
||||
.It Fn ROUND x Ta Round $x$ to the nearest integer
|
||||
.It Fn CEIL x Ta Round $x$ up to an integer
|
||||
.It Fn FLOOR x Ta Round $x$ down to an integer
|
||||
.It Fn SIN x Ta Sine of $x$
|
||||
.It Fn COS x Ta Cosine of $x$
|
||||
.It Fn TAN x Ta Tangent of $x$
|
||||
.It Fn ASIN x Ta Inverse sine of $x$
|
||||
.It Fn ACOS x Ta Inverse cosine of $x$
|
||||
.It Fn ATAN x Ta Inverse tangent of $x$
|
||||
.It Fn ATAN2 x y Ta Angle between $( x , y )$ and $( 1 , 0 )$
|
||||
.El
|
||||
.EQ
|
||||
|
||||
@@ -292,6 +292,20 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t exponent(int32_t base, int32_t power)
|
||||
{
|
||||
int32_t result = 1;
|
||||
|
||||
while (power) {
|
||||
if (power % 2)
|
||||
result *= base;
|
||||
power /= 2;
|
||||
base *= base;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
|
||||
{
|
||||
if (!rpn_isSymbol(expr))
|
||||
@@ -415,6 +429,15 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||
else
|
||||
expr->nVal = src1->nVal % src2->nVal;
|
||||
break;
|
||||
case RPN_EXP:
|
||||
if (src2->nVal < 0)
|
||||
fatalerror("Exponentiation by negative power\n");
|
||||
|
||||
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||
expr->nVal = 0;
|
||||
else
|
||||
expr->nVal = exponent(src1->nVal, src2->nVal);
|
||||
break;
|
||||
|
||||
case RPN_UNSUB:
|
||||
case RPN_UNNOT:
|
||||
|
||||
Reference in New Issue
Block a user