mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-22 19:22:05 +00:00
Fixed-point functions can take specific precision (#1086)
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "asm/fixpoint.h"
|
||||
#include "asm/symbol.h"
|
||||
@@ -21,8 +20,8 @@
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define fix2double(i) ((double)((i) / fix_PrecisionFactor()))
|
||||
#define double2fix(d) ((int32_t)round((d) * fix_PrecisionFactor()))
|
||||
#define fix2double(i, q) ((double)((i) / pow(2.0, q)))
|
||||
#define double2fix(d, q) ((int32_t)round((d) * pow(2.0, q)))
|
||||
|
||||
// 2*pi radians == 1 turn
|
||||
#define turn2rad(f) ((f) * (M_PI * 2))
|
||||
@@ -30,96 +29,87 @@
|
||||
|
||||
uint8_t fixPrecision;
|
||||
|
||||
uint8_t fix_Precision(void)
|
||||
{
|
||||
return fixPrecision;
|
||||
}
|
||||
|
||||
double fix_PrecisionFactor(void)
|
||||
{
|
||||
return pow(2.0, fixPrecision);
|
||||
}
|
||||
|
||||
void fix_Print(int32_t i)
|
||||
int32_t fix_Sin(int32_t i, int32_t q)
|
||||
{
|
||||
uint32_t u = i;
|
||||
char const *sign = "";
|
||||
|
||||
if (i < 0) {
|
||||
u = -u;
|
||||
sign = "-";
|
||||
}
|
||||
|
||||
printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> fixPrecision,
|
||||
((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
|
||||
return double2fix(sin(turn2rad(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_Sin(int32_t i)
|
||||
int32_t fix_Cos(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(sin(turn2rad(fix2double(i))));
|
||||
return double2fix(cos(turn2rad(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_Cos(int32_t i)
|
||||
int32_t fix_Tan(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(cos(turn2rad(fix2double(i))));
|
||||
return double2fix(tan(turn2rad(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_Tan(int32_t i)
|
||||
int32_t fix_ASin(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(tan(turn2rad(fix2double(i))));
|
||||
return double2fix(rad2turn(asin(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_ASin(int32_t i)
|
||||
int32_t fix_ACos(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(rad2turn(asin(fix2double(i))));
|
||||
return double2fix(rad2turn(acos(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_ACos(int32_t i)
|
||||
int32_t fix_ATan(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(rad2turn(acos(fix2double(i))));
|
||||
return double2fix(rad2turn(atan(fix2double(i, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_ATan(int32_t i)
|
||||
int32_t fix_ATan2(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(rad2turn(atan(fix2double(i))));
|
||||
return double2fix(rad2turn(atan2(fix2double(i, q), fix2double(j, q))), q);
|
||||
}
|
||||
|
||||
int32_t fix_ATan2(int32_t i, int32_t j)
|
||||
int32_t fix_Mul(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(rad2turn(atan2(fix2double(i), fix2double(j))));
|
||||
return double2fix(fix2double(i, q) * fix2double(j, q), q);
|
||||
}
|
||||
|
||||
int32_t fix_Mul(int32_t i, int32_t j)
|
||||
int32_t fix_Div(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(fix2double(i) * fix2double(j));
|
||||
return double2fix(fix2double(i, q) / fix2double(j, q), q);
|
||||
}
|
||||
|
||||
int32_t fix_Div(int32_t i, int32_t j)
|
||||
int32_t fix_Mod(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(fix2double(i) / fix2double(j));
|
||||
return double2fix(fmod(fix2double(i, q), fix2double(j, q)), q);
|
||||
}
|
||||
|
||||
int32_t fix_Mod(int32_t i, int32_t j)
|
||||
int32_t fix_Pow(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(fmod(fix2double(i), fix2double(j)));
|
||||
return double2fix(pow(fix2double(i, q), fix2double(j, q)), q);
|
||||
}
|
||||
|
||||
int32_t fix_Pow(int32_t i, int32_t j)
|
||||
int32_t fix_Log(int32_t i, int32_t j, int32_t q)
|
||||
{
|
||||
return double2fix(pow(fix2double(i), fix2double(j)));
|
||||
return double2fix(log(fix2double(i, q)) / log(fix2double(j, q)), q);
|
||||
}
|
||||
|
||||
int32_t fix_Log(int32_t i, int32_t j)
|
||||
int32_t fix_Round(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(log(fix2double(i)) / log(fix2double(j)));
|
||||
return double2fix(round(fix2double(i, q)), q);
|
||||
}
|
||||
|
||||
int32_t fix_Round(int32_t i)
|
||||
int32_t fix_Ceil(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(round(fix2double(i)));
|
||||
return double2fix(ceil(fix2double(i, q)), q);
|
||||
}
|
||||
|
||||
int32_t fix_Ceil(int32_t i)
|
||||
int32_t fix_Floor(int32_t i, int32_t q)
|
||||
{
|
||||
return double2fix(ceil(fix2double(i)));
|
||||
}
|
||||
|
||||
int32_t fix_Floor(int32_t i)
|
||||
{
|
||||
return double2fix(floor(fix2double(i)));
|
||||
return double2fix(floor(fix2double(i, q)), q);
|
||||
}
|
||||
|
||||
@@ -550,6 +550,7 @@ enum {
|
||||
%token T_OP_BANK "BANK"
|
||||
%token T_OP_ALIGN "ALIGN"
|
||||
%token T_OP_SIZEOF "SIZEOF" T_OP_STARTOF "STARTOF"
|
||||
|
||||
%token T_OP_SIN "SIN" T_OP_COS "COS" T_OP_TAN "TAN"
|
||||
%token T_OP_ASIN "ASIN" T_OP_ACOS "ACOS" T_OP_ATAN "ATAN" T_OP_ATAN2 "ATAN2"
|
||||
%token T_OP_FDIV "FDIV"
|
||||
@@ -559,6 +560,7 @@ enum {
|
||||
%token T_OP_LOG "LOG"
|
||||
%token T_OP_ROUND "ROUND"
|
||||
%token T_OP_CEIL "CEIL" T_OP_FLOOR "FLOOR"
|
||||
%type <constValue> opt_q_arg
|
||||
|
||||
%token T_OP_HIGH "HIGH" T_OP_LOW "LOW"
|
||||
%token T_OP_ISCONST "ISCONST"
|
||||
@@ -1466,50 +1468,50 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
||||
|
||||
lexer_ToggleStringExpansion(true);
|
||||
}
|
||||
| T_OP_ROUND T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Round($3));
|
||||
| T_OP_ROUND T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Round($3, $4));
|
||||
}
|
||||
| T_OP_CEIL T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Ceil($3));
|
||||
| T_OP_CEIL T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Ceil($3, $4));
|
||||
}
|
||||
| T_OP_FLOOR T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Floor($3));
|
||||
| T_OP_FLOOR T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Floor($3, $4));
|
||||
}
|
||||
| T_OP_FDIV T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Div($3, $5));
|
||||
| T_OP_FDIV T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Div($3, $5, $6));
|
||||
}
|
||||
| T_OP_FMUL T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Mul($3, $5));
|
||||
| T_OP_FMUL T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Mul($3, $5, $6));
|
||||
}
|
||||
| T_OP_FMOD T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Mod($3, $5));
|
||||
| T_OP_FMOD T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Mod($3, $5, $6));
|
||||
}
|
||||
| T_OP_POW T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Pow($3, $5));
|
||||
| T_OP_POW T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Pow($3, $5, $6));
|
||||
}
|
||||
| T_OP_LOG T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Log($3, $5));
|
||||
| T_OP_LOG T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Log($3, $5, $6));
|
||||
}
|
||||
| T_OP_SIN T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Sin($3));
|
||||
| T_OP_SIN T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Sin($3, $4));
|
||||
}
|
||||
| T_OP_COS T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Cos($3));
|
||||
| T_OP_COS T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Cos($3, $4));
|
||||
}
|
||||
| T_OP_TAN T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_Tan($3));
|
||||
| T_OP_TAN T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_Tan($3, $4));
|
||||
}
|
||||
| T_OP_ASIN T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_ASin($3));
|
||||
| T_OP_ASIN T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_ASin($3, $4));
|
||||
}
|
||||
| T_OP_ACOS T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_ACos($3));
|
||||
| T_OP_ACOS T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_ACos($3, $4));
|
||||
}
|
||||
| T_OP_ATAN T_LPAREN const T_RPAREN {
|
||||
rpn_Number(&$$, fix_ATan($3));
|
||||
| T_OP_ATAN T_LPAREN const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_ATan($3, $4));
|
||||
}
|
||||
| T_OP_ATAN2 T_LPAREN const T_COMMA const T_RPAREN {
|
||||
rpn_Number(&$$, fix_ATan2($3, $5));
|
||||
| T_OP_ATAN2 T_LPAREN const T_COMMA const opt_q_arg T_RPAREN {
|
||||
rpn_Number(&$$, fix_ATan2($3, $5, $6));
|
||||
}
|
||||
| T_OP_STRCMP T_LPAREN string T_COMMA string T_RPAREN {
|
||||
rpn_Number(&$$, strcmp($3, $5));
|
||||
@@ -1536,7 +1538,7 @@ relocexpr_no_str : scoped_anon_id { rpn_Symbol(&$$, $1); }
|
||||
uconst : const {
|
||||
$$ = $1;
|
||||
if ($$ < 0)
|
||||
fatalerror("Constant mustn't be negative: %d\n", $1);
|
||||
fatalerror("Constant must not be negative: %d\n", $1);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -1549,6 +1551,17 @@ const_no_str : relocexpr_no_str { $$ = rpn_GetConstVal(&$1); }
|
||||
const_8bit : reloc_8bit { $$ = rpn_GetConstVal(&$1); }
|
||||
;
|
||||
|
||||
opt_q_arg : %empty { $$ = fix_Precision(); }
|
||||
| T_COMMA const {
|
||||
if ($2 >= 1 && $2 <= 31) {
|
||||
$$ = $2;
|
||||
} else {
|
||||
error("Fixed-point precision must be between 1 and 31\n");
|
||||
$$ = fix_Precision();
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
string : T_STRING
|
||||
| T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN {
|
||||
size_t len = strlenUTF8($3);
|
||||
|
||||
Reference in New Issue
Block a user