jswrap_math.c 8.5 KB

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