Redefine the trig functions to divide circles into 1.0 turns (#1060)

This makes their behavior consistent across Q settings

Fixes #1059
This commit is contained in:
Rangi
2022-09-29 04:57:29 -04:00
committed by GitHub
parent 3567faf395
commit 023884d2b0
6 changed files with 72 additions and 35 deletions

View File

@@ -57,7 +57,7 @@ and ending with
.Ql */ . .Ql */ .
It can be split across multiple lines, or occur in the middle of an expression: It can be split across multiple lines, or occur in the middle of an expression:
.Bd -literal -offset indent .Bd -literal -offset indent
X = /* the value of x DEF X = /* the value of x
should be 3 */ 3 should be 3 */ 3
.Ed .Ed
.Pp .Pp
@@ -169,19 +169,19 @@ Examples:
.Bd -literal -offset indent .Bd -literal -offset indent
SECTION "Test", ROM0[2] SECTION "Test", ROM0[2]
X: ;\ This works with labels **whose address is known** X: ;\ This works with labels **whose address is known**
Y = 3 ;\ This also works with variables DEF Y = 3 ;\ This also works with variables
SUM equ X + Y ;\ And likewise with numeric constants DEF SUM EQU X + Y ;\ And likewise with numeric constants
; Prints "%0010 + $3 == 5" ; Prints "%0010 + $3 == 5"
PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}" PRINTLN "{#05b:X} + {#x:Y} == {d:SUM}"
rsset 32 rsset 32
PERCENT rb 1 ;\ Same with offset constants DEF PERCENT rb 1 ;\ Same with offset constants
VALUE = 20 DEF VALUE = 20
RESULT = MUL(20.0, 0.32) DEF RESULT = MUL(20.0, 0.32)
; Prints "32% of 20 = 6.40" ; Prints "32% of 20 = 6.40"
PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}" PRINTLN "{d:PERCENT}% of {d:VALUE} = {f:RESULT}"
WHO equs STRLWR("WORLD") DEF WHO EQUS STRLWR("WORLD")
; Prints "Hello world!" ; Prints "Hello world!"
PRINTLN "Hello {s:WHO}!" PRINTLN "Hello {s:WHO}!"
.Ed .Ed
@@ -350,18 +350,18 @@ The trigonometry functions (
.Ic SIN , .Ic SIN ,
.Ic COS , .Ic COS ,
.Ic TAN , .Ic TAN ,
etc) are defined in terms of a circle divided into 65535.0 degrees. etc) are defined in terms of a circle divided into 1.0 "turns" (equal to 2pi radians or 360 degrees).
.Pp .Pp
These functions are useful for automatic generation of various tables. These functions are useful for automatic generation of various tables.
For example: For example:
.Bd -literal -offset indent .Bd -literal -offset indent
; Generate a 256-byte sine table with values in the range [0, 128] ; Generate a table of sine values from sin(0.0) to sin(1.0), with
; (shifted and scaled from the range [-1.0, 1.0]) ; amplitude scaled from [-1.0, 1.0] to [0.0, 128.0]
ANGLE = 0.0 DEF turns = 0.0
REPT 256 REPT 256
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16 db MUL(64.0, SIN(turns) + 1.0) >> 16
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries DEF turns += 1.0 / 256
ENDR ENDR
.Ed .Ed
.Ss String expressions .Ss String expressions
The most basic string expression is any number of characters contained in double quotes The most basic string expression is any number of characters contained in double quotes
@@ -1011,7 +1011,7 @@ DEF ARRAY_SIZE EQU 4
DEF COUNT = 2 DEF COUNT = 2
DEF COUNT = 3 DEF COUNT = 3
DEF COUNT = ARRAY_SIZE + COUNT DEF COUNT = ARRAY_SIZE + COUNT
COUNT = COUNT*2 DEF COUNT *= 2
;\ COUNT now has the value 14 ;\ COUNT now has the value 14
.Ed .Ed
.Pp .Pp
@@ -1753,13 +1753,12 @@ You can also use
.Ic REPT .Ic REPT
to generate tables on the fly: to generate tables on the fly:
.Bd -literal -offset indent .Bd -literal -offset indent
; Generate a 256-byte sine table with values in the range [0, 128] ; Generate a table of square values from 0**2 = 0 to 100**2 = 10000
; (shifted and scaled from the range [-1.0, 1.0]) DEF x = 0
ANGLE = 0.0 REPT 101
REPT 256 dw x * x
db (MUL(64.0, SIN(ANGLE)) + 64.0) >> 16 DEF x += 1
ANGLE = ANGLE + 256.0 ; 256.0 = 65536 degrees / 256 entries ENDR
ENDR
.Ed .Ed
.Pp .Pp
As in macros, you can also use the escape sequence As in macros, you can also use the escape sequence

View File

@@ -24,9 +24,9 @@
#define fix2double(i) ((double)((i) / fix_PrecisionFactor())) #define fix2double(i) ((double)((i) / fix_PrecisionFactor()))
#define double2fix(d) ((int32_t)round((d) * fix_PrecisionFactor())) #define double2fix(d) ((int32_t)round((d) * fix_PrecisionFactor()))
// pi*2 radians == 2**fixPrecision fixed-point "degrees" // 2*pi radians == 1 turn
#define fdeg2rad(f) ((f) * (M_PI * 2) / fix_PrecisionFactor()) #define turn2rad(f) ((f) * (M_PI * 2))
#define rad2fdeg(r) ((r) * fix_PrecisionFactor() / (M_PI * 2)) #define rad2turn(r) ((r) / (M_PI * 2))
uint8_t fixPrecision; uint8_t fixPrecision;
@@ -51,37 +51,37 @@ void fix_Print(int32_t i)
int32_t fix_Sin(int32_t i) int32_t fix_Sin(int32_t i)
{ {
return double2fix(sin(fdeg2rad(fix2double(i)))); return double2fix(sin(turn2rad(fix2double(i))));
} }
int32_t fix_Cos(int32_t i) int32_t fix_Cos(int32_t i)
{ {
return double2fix(cos(fdeg2rad(fix2double(i)))); return double2fix(cos(turn2rad(fix2double(i))));
} }
int32_t fix_Tan(int32_t i) int32_t fix_Tan(int32_t i)
{ {
return double2fix(tan(fdeg2rad(fix2double(i)))); return double2fix(tan(turn2rad(fix2double(i))));
} }
int32_t fix_ASin(int32_t i) int32_t fix_ASin(int32_t i)
{ {
return double2fix(rad2fdeg(asin(fix2double(i)))); return double2fix(rad2turn(asin(fix2double(i))));
} }
int32_t fix_ACos(int32_t i) int32_t fix_ACos(int32_t i)
{ {
return double2fix(rad2fdeg(acos(fix2double(i)))); return double2fix(rad2turn(acos(fix2double(i))));
} }
int32_t fix_ATan(int32_t i) int32_t fix_ATan(int32_t i)
{ {
return double2fix(rad2fdeg(atan(fix2double(i)))); return double2fix(rad2turn(atan(fix2double(i))));
} }
int32_t fix_ATan2(int32_t i, int32_t j) int32_t fix_ATan2(int32_t i, int32_t j)
{ {
return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j)))); return double2fix(rad2turn(atan2(fix2double(i), fix2double(j))));
} }
int32_t fix_Mul(int32_t i, int32_t j) int32_t fix_Mul(int32_t i, int32_t j)

38
test/asm/trigonometry.asm Normal file
View File

@@ -0,0 +1,38 @@
for Q, 2, 31
OPT Q.{d:Q}
assert sin(0.25) == 1.0
assert asin(1.0) == 0.25
assert sin(0.0) == 0.0
assert asin(0.0) == 0.0
assert cos(0.0) == 1.0
assert acos(1.0) == 0.0
if Q > 2 ; can't represent 0.125 in Q.2
assert tan(0.125) == 1.0
assert atan(1.0) == 0.125
else
assert tan(0.0) == 0.0
assert atan(0.0) == 0.0
endc
endr
SECTION "sine", ROM0[0]
OPT Q.16
; Generate a table of sine values from sin(0.0) to sin(1.0), with
; amplitude scaled from [-1.0, 1.0] to [0.0, 128.0]
DEF turns = 0.0
REPT 256
db MUL(64.0, SIN(turns) + 1.0) >> 16
DEF turns += 1.0 / 256
ENDR
SECTION "cosine", ROM0[256]
OPT Q.8
; 32 samples of cos(x) from x=0 to x=pi radians=0.5 turns
for x, 0.0, 0.5, 0.5 / 32
dw cos(x)
endr

View File

View File

Binary file not shown.