math.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import { StoreObject } from '../store/storeObject';
  2. import * as Commands from './../../ast/commands';
  3. import { Types } from './../../typeSystem/types';
  4. import { toReal } from "./../../typeSystem/parsers";
  5. import { Decimal } from 'decimal.js';
  6. import { MultiType } from '../../typeSystem/multiType';
  7. import { ArrayType } from '../../typeSystem/array_type';
  8. import { Modes } from '../modes';
  9. import { Config } from '../../util/config';
  10. /**
  11. * sin
  12. * cos
  13. * tan
  14. * sqrt
  15. * pow
  16. * log
  17. * abs
  18. * negate
  19. * invert
  20. * max
  21. * min
  22. */
  23. function convertToRadians (degrees) {
  24. return degrees.times(Decimal.acos(-1)).div(180);
  25. }
  26. export function createSinFun () {
  27. const sinFun = (sto, _) => {
  28. const x = sto.applyStore('x');
  29. const angle = x.value.mod(360);
  30. let result = null;
  31. if(angle.eq(90)) {
  32. result = new Decimal(1);
  33. } else if (angle.eq(180)) {
  34. result = new Decimal(0);
  35. } else if (angle.eq(270)) {
  36. result = new Decimal(-1);
  37. } else {
  38. result = Decimal.sin(convertToRadians(angle));
  39. }
  40. if(result.dp() > Config.decimalPlaces) {
  41. result = new Decimal(result.toFixed(Config.decimalPlaces));
  42. }
  43. const temp = new StoreObject(Types.REAL, result);
  44. sto.mode = Modes.RETURN;
  45. return Promise.resolve(sto.updateStore('$', temp));
  46. };
  47. const block = new Commands.CommandBlock([], [new Commands.SysCall(sinFun)]);
  48. const func = new Commands.Function('$sin', Types.REAL,
  49. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  50. block);
  51. return func;
  52. }
  53. export function createCosFun () {
  54. const cosFun = (sto, _) => {
  55. const x = sto.applyStore('x');
  56. const angle = x.value.mod(360);
  57. let result = null;
  58. if(angle.eq(90)) {
  59. result = new Decimal(0);
  60. } else if (angle.eq(180)) {
  61. result = new Decimal(-1);
  62. } else if (angle.eq(270)) {
  63. result = new Decimal(0)
  64. }
  65. result = Decimal.cos(convertToRadians(angle));
  66. if(result.dp() > Config.decimalPlaces) {
  67. result = new Decimal(result.toFixed(Config.decimalPlaces));
  68. }
  69. const temp = new StoreObject(Types.REAL, result);
  70. sto.mode = Modes.RETURN;
  71. return Promise.resolve(sto.updateStore('$', temp));
  72. };
  73. const block = new Commands.CommandBlock([], [new Commands.SysCall(cosFun)]);
  74. const func = new Commands.Function('$cos', Types.REAL,
  75. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  76. block);
  77. return func;
  78. }
  79. export function createTanFun () {
  80. const tanFun = (sto, _) => {
  81. const x = sto.applyStore('x');
  82. const angle = x.value.mod(360);
  83. if(angle.eq(90) || angle.eq(270)) {
  84. return Promise.reject("Tangent of "+x.value.toNumber()+"° is undefined.");
  85. }
  86. let result = Decimal.tan(convertToRadians(angle));
  87. if(result.dp() > Config.decimalPlaces) {
  88. result = new Decimal(result.toFixed(Config.decimalPlaces));
  89. }
  90. const temp = new StoreObject(Types.REAL, result);
  91. sto.mode = Modes.RETURN;
  92. return Promise.resolve(sto.updateStore('$', temp));
  93. };
  94. const block = new Commands.CommandBlock([], [new Commands.SysCall(tanFun)]);
  95. const func = new Commands.Function('$tan', Types.REAL,
  96. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  97. block);
  98. return func;
  99. }
  100. export function createSqrtFun () {
  101. const sqrtFun = (sto, _) => {
  102. const x = sto.applyStore('x');
  103. let result = x.value.sqrt();
  104. if(result.dp() > Config.decimalPlaces) {
  105. result = new Decimal(result.toFixed(Config.decimalPlaces));
  106. }
  107. const temp = new StoreObject(Types.REAL, result);
  108. sto.mode = Modes.RETURN;
  109. return Promise.resolve(sto.updateStore('$', temp));
  110. };
  111. const block = new Commands.CommandBlock([], [new Commands.SysCall(sqrtFun)]);
  112. const func = new Commands.Function('$sqrt', Types.REAL,
  113. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  114. block);
  115. return func;
  116. }
  117. export function createPowFun () {
  118. const powFun = (sto, _) => {
  119. const x = sto.applyStore('x');
  120. const y = sto.applyStore('y');
  121. let result = x.value.pow(y.value);
  122. if(result.dp() > Config.decimalPlaces) {
  123. result = new Decimal(result.toFixed(Config.decimalPlaces));
  124. }
  125. const temp = new StoreObject(Types.REAL, result);
  126. sto.mode = Modes.RETURN;
  127. return Promise.resolve(sto.updateStore('$', temp));
  128. };
  129. const block = new Commands.CommandBlock([], [new Commands.SysCall(powFun)]);
  130. const func = new Commands.Function('$pow', Types.REAL,
  131. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false),
  132. new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'y', false)],
  133. block);
  134. return func;
  135. }
  136. export function createLogFun () {
  137. const logFun = (sto, _) => {
  138. const x = sto.applyStore('x');
  139. if (x.value.isNegative()) {
  140. return Promise.reject(new Error("the value passed to log function cannot be negative"));
  141. }
  142. let result = Decimal.log10(x.value);
  143. if(result.dp() > Config.decimalPlaces) {
  144. result = new Decimal(result.toFixed(Config.decimalPlaces));
  145. }
  146. const temp = new StoreObject(Types.REAL, result);
  147. sto.mode = Modes.RETURN;
  148. return Promise.resolve(sto.updateStore('$', temp));
  149. };
  150. const block = new Commands.CommandBlock([], [new Commands.SysCall(logFun)]);
  151. const func = new Commands.Function('$log', Types.REAL,
  152. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  153. block);
  154. return func;
  155. }
  156. export function createAbsFun () {
  157. const absFun = (sto, _) => {
  158. const x = sto.applyStore('x');
  159. const result = x.value.abs();
  160. const temp = new StoreObject(x.type, result);
  161. sto.updateStore('$', temp)
  162. sto.mode = Modes.RETURN;
  163. return Promise.resolve(sto);
  164. };
  165. const block = new Commands.CommandBlock([], [new Commands.SysCall(absFun)]);
  166. const func = new Commands.Function('$abs', new MultiType([Types.INTEGER, Types.REAL]),
  167. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  168. block);
  169. return func;
  170. }
  171. export function createNegateFun () {
  172. const negateFun = (sto, _) => {
  173. const x = sto.applyStore('x');
  174. const result = x.value.negated();
  175. const temp = new StoreObject(x.type, result);
  176. sto.mode = Modes.RETURN;
  177. return Promise.resolve(sto.updateStore('$', temp));
  178. };
  179. const block = new Commands.CommandBlock([], [new Commands.SysCall(negateFun)]);
  180. const func = new Commands.Function('$negate', new MultiType([Types.INTEGER, Types.REAL]),
  181. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  182. block);
  183. return func;
  184. }
  185. export function createInvertFun () {
  186. const invertFun = (sto, _) => {
  187. const x = sto.applyStore('x');
  188. let result = toReal(1).dividedBy(x.value);
  189. if(result.dp() > Config.decimalPlaces) {
  190. result = new Decimal(result.toFixed(Config.decimalPlaces));
  191. }
  192. const temp = new StoreObject(Types.REAL, result);
  193. sto.mode = Modes.RETURN;
  194. return Promise.resolve(sto.updateStore('$', temp));
  195. };
  196. const block = new Commands.CommandBlock([], [new Commands.SysCall(invertFun)]);
  197. const func = new Commands.Function('$invert', Types.REAL,
  198. [new Commands.FormalParameter(new MultiType([Types.INTEGER, Types.REAL]), 'x', false)],
  199. block);
  200. return func;
  201. }
  202. export function createMaxFun () {
  203. const maxFun = (sto, _) => {
  204. const x = sto.applyStore('x');
  205. const numbers = x.value.map(stoObj => stoObj.value);
  206. const result = Decimal.max(...numbers);
  207. const temp = new StoreObject(x.type.innerType, result);
  208. sto.mode = Modes.RETURN;
  209. return Promise.resolve(sto.updateStore('$', temp));
  210. };
  211. const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  212. const block = new Commands.CommandBlock([], [new Commands.SysCall(maxFun)]);
  213. const func = new Commands.Function('$max', new MultiType([Types.INTEGER, Types.REAL]),
  214. [new Commands.FormalParameter(paramType, 'x', false)],
  215. block);
  216. return func;
  217. }
  218. export function createMinFun () {
  219. const minFun = (sto, _) => {
  220. const x = sto.applyStore('x');
  221. const numbers = x.value.map(stoObj => stoObj.value);
  222. const result = Decimal.min(...numbers);
  223. const temp = new StoreObject(x.type.innerType, result);
  224. sto.mode = Modes.RETURN;
  225. return Promise.resolve(sto.updateStore('$', temp));
  226. };
  227. const paramType = new ArrayType(new MultiType([Types.INTEGER, Types.REAL]), 1);
  228. const block = new Commands.CommandBlock([], [new Commands.SysCall(minFun)]);
  229. const func = new Commands.Function('$min', new MultiType([Types.INTEGER, Types.REAL]),
  230. [new Commands.FormalParameter(paramType, 'x', false)],
  231. block);
  232. return func;
  233. }
  234. export function createRandFun () {
  235. const randFun = (sto, _) => {
  236. const val = Math.random();
  237. const result = new StoreObject(Types.REAL, new Decimal(val));
  238. sto.mode = Modes.RETURN;
  239. return Promise.resolve(sto.updateStore("$", result));
  240. };
  241. const block = new Commands.CommandBlock([], [new Commands.SysCall(randFun)]);
  242. const func = new Commands.Function('$rand', Types.REAL, [], block);
  243. return func;
  244. }