1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
|
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <[email protected]>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* Contains built-in functions for Maths
* ----------------------------------------------------------------------------
*/
#include "jswrap_math.h"
/*JSON{ "type":"class",
"class" : "Math",
"description" : "This is a standard JavaScript class that contains useful Maths routines"
}*/
// -------------------------------------------------------------------- Integer
/*JSON{ "type":"staticmethod",
"class" : "Integer", "name" : "valueOf",
"generate" : "jswrap_integer_valueOf",
"description" : "Given a string containing a single character, return the numeric value of it",
"params" : [ [ "character" ,"JsVar", "A string containing a single character"] ],
"return" : ["int", "The integer value of char"]
}*/
JsVarInt jswrap_integer_valueOf(JsVar *v) {
if (!jsvIsString(v) || jsvGetStringLength(v)!=1)
return 0;
return (int)v->varData.str[0];
}
/*JSON{ "type":"variable", "name" : "NaN",
"generate_full" : "NAN",
"return" : ["float", "Not a Number"]
}*/
// -------------------------------------------------------------------- Double
/*JSON{ "type":"staticmethod",
"class" : "Double", "name" : "doubleToIntBits",
"generate_full" : "*(JsVarInt*)&x",
"description" : " Convert the floating point value given into an integer representing the bits contained in it",
"params" : [ [ "x", "float", "A floating point number"] ],
"return" : ["int", "The integer representation of x"]
}*/
// -------------------------------------------------------------------- Math
/*JSON{ "type":"staticproperty",
"class" : "Math", "name" : "E",
"generate_full" : "2.71828182846",
"return" : ["float", "The value of E - 2.71828182846"]
}*/
/*JSON{ "type":"staticproperty",
"class" : "Math", "name" : "PI",
"generate_full" : "3.14159265359",
"return" : ["float", "The value of PI - 3.14159265359"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "abs",
"generate" : "jswrap_math_abs",
"params" : [ [ "x", "float", "A floating point value"] ],
"return" : ["float", "The absolute value of x (eg, ```Math.abs(2)==2```, but also ```Math.abs(-2)==2```)"]
}*/
JsVarFloat jswrap_math_abs(JsVarFloat x) {
return (x<0)?-x:x;
}
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "acos",
"generate" : "acos",
"params" : [ [ "x", "float", "The value to get the arc cosine of"] ],
"return" : ["float", "The arc cosine of x, between 0 and PI"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "asin",
"generate" : "asin",
"params" : [ [ "x", "float", "The value to get the arc sine of"] ],
"return" : ["float", "The arc sine of x, between -PI/2 and PI/2"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "atan",
"generate" : "atan",
"params" : [ [ "x", "float", "The value to get the arc tangent of"] ],
"return" : ["float", "The arc tangent of x, between -PI/2 and PI/2"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "atan2",
"generate" : "atan2",
"params" : [ [ "y", "float", "The Y-part of the angle to get the arc tangent of"],
[ "x", "float", "The X-part of the angle to get the arc tangent of"] ],
"return" : ["float", "The arctangent of Y/X, between -PI and PI"]
}*/
/* we use sin here, not cos, to try and save a bit of code space */
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "cos",
"generate_full" : "sin(jsvGetFloat(theta) + (3.14159265359/2.0))",
"params" : [ [ "theta", "float", "The angle to get the cosine of"] ],
"return" : ["float", "The cosine of theta"]
}*/
#define DBL_MAX 1.7976931348623157E+308
double fs_fmod(double x, double y)
{
double a, b;
const double c = x;
if (0 > c) {
x = -x;
}
if (0 > y) {
y = -y;
}
if (y != 0 && DBL_MAX >= y && DBL_MAX >= x) {
while (x >= y) {
a = x / 2;
b = y;
while (a >= b) {
b *= 2;
}
x -= b;
}
} else {
x = 0;
}
return 0 > c ? -x : x;
}
double jswrap_math_pow(double x, double y)
{
double p;
if (0 > x && fs_fmod(y, 1) == 0) {
if (fs_fmod(y, 2) == 0) {
p = exp(log(-x) * y);
} else {
p = -exp(log(-x) * y);
}
} else {
if (x != 0 || 0 >= y) {
p = exp(log( x) * y);
} else {
p = 0;
}
}
return p;
}
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "pow",
"generate" : "jswrap_math_pow",
"params" : [ [ "x", "float", "The value to raise to the power"],
[ "y", "float", "The power x should be raised to"] ],
"return" : ["float", "x raised to the power y (x^y)"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "random",
"generate_full" : "(JsVarFloat)rand() / (JsVarFloat)RAND_MAX",
"return" : ["float", "A random number between 0 and 1"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "round",
"generate" : "(JsVarInt)round",
"params" : [ [ "x", "float", "The value to round"] ],
"return" : ["int", "x, rounded to the nearest integer"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "sin",
"generate" : "sin",
"params" : [ [ "theta", "float", "The angle to get the sine of"] ],
"return" : ["float", "The sine of theta"]
}*/
/* we could use the real sqrt - but re-use pow to save on code space */
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "sqrt",
"generate_full" : "jswrap_math_pow(jsvGetFloat(x),0.5)",
"params" : [ [ "x", "float", "The value to take the square root of"] ],
"return" : ["float", "The square root of x"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "ceil",
"generate" : "ceil",
"params" : [ [ "x", "float", "The value to round up"] ],
"return" : ["float", "x, rounded upwards to the nearest integer"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "floor",
"generate" : "floor",
"params" : [ [ "x", "float", "The value to round down"] ],
"return" : ["float", "x, rounded downwards to the nearest integer"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "exp",
"generate" : "exp",
"params" : [ [ "x", "float", "The value raise E to the power of"] ],
"return" : ["float", "E^x"]
}*/
/*JSON{ "type":"staticmethod",
"class" : "Math", "name" : "log",
"generate" : "log",
"params" : [ [ "x", "float", "The value to take the logarithm (base E) root of"] ],
"return" : ["float", "The log (base E) of x"]
}*/
/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH",
"class" : "Math", "name" : "clip",
"generate" : "jswrap_math_clip",
"description" : "Clip a number to be between min and max (inclusive)",
"params" : [ [ "x", "float", "A floating point value to clip"],
[ "min", "float", "The smallest the value should be"],
[ "max", "float", "The largest the value should be"] ],
"return" : ["float", "The value of x, clipped so as not to be below min or above max."]
}*/
JsVarFloat jswrap_math_clip(JsVarFloat x, JsVarFloat min, JsVarFloat max) {
if (x<min) x=min;
if (x>max) x=max;
return x;
}
/*JSON{ "type":"staticmethod", "ifndef" : "SAVE_ON_FLASH",
"class" : "Math", "name" : "wrap",
"generate" : "wrapAround",
"description" : "Wrap a number around if it is less than 0 or greater than or equal to max. For instance you might do: ```Math.wrap(angleInDegrees, 360)```",
"params" : [ [ "x", "float", "A floating point value to wrap"],
[ "max", "float", "The largest the value should be"] ],
"return" : ["float", "The value of x, wrapped so as not to be below min or above max."]
}*/
|