math.js 8.3 KB

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