builtin_math.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. package goja
  2. import (
  3. "math"
  4. "math/bits"
  5. )
  6. func (r *Runtime) math_abs(call FunctionCall) Value {
  7. return floatToValue(math.Abs(call.Argument(0).ToFloat()))
  8. }
  9. func (r *Runtime) math_acos(call FunctionCall) Value {
  10. return floatToValue(math.Acos(call.Argument(0).ToFloat()))
  11. }
  12. func (r *Runtime) math_acosh(call FunctionCall) Value {
  13. return floatToValue(math.Acosh(call.Argument(0).ToFloat()))
  14. }
  15. func (r *Runtime) math_asin(call FunctionCall) Value {
  16. return floatToValue(math.Asin(call.Argument(0).ToFloat()))
  17. }
  18. func (r *Runtime) math_asinh(call FunctionCall) Value {
  19. return floatToValue(math.Asinh(call.Argument(0).ToFloat()))
  20. }
  21. func (r *Runtime) math_atan(call FunctionCall) Value {
  22. return floatToValue(math.Atan(call.Argument(0).ToFloat()))
  23. }
  24. func (r *Runtime) math_atanh(call FunctionCall) Value {
  25. return floatToValue(math.Atanh(call.Argument(0).ToFloat()))
  26. }
  27. func (r *Runtime) math_atan2(call FunctionCall) Value {
  28. y := call.Argument(0).ToFloat()
  29. x := call.Argument(1).ToFloat()
  30. return floatToValue(math.Atan2(y, x))
  31. }
  32. func (r *Runtime) math_cbrt(call FunctionCall) Value {
  33. return floatToValue(math.Cbrt(call.Argument(0).ToFloat()))
  34. }
  35. func (r *Runtime) math_ceil(call FunctionCall) Value {
  36. return floatToValue(math.Ceil(call.Argument(0).ToFloat()))
  37. }
  38. func (r *Runtime) math_clz32(call FunctionCall) Value {
  39. return intToValue(int64(bits.LeadingZeros32(toUint32(call.Argument(0)))))
  40. }
  41. func (r *Runtime) math_cos(call FunctionCall) Value {
  42. return floatToValue(math.Cos(call.Argument(0).ToFloat()))
  43. }
  44. func (r *Runtime) math_cosh(call FunctionCall) Value {
  45. return floatToValue(math.Cosh(call.Argument(0).ToFloat()))
  46. }
  47. func (r *Runtime) math_exp(call FunctionCall) Value {
  48. return floatToValue(math.Exp(call.Argument(0).ToFloat()))
  49. }
  50. func (r *Runtime) math_expm1(call FunctionCall) Value {
  51. return floatToValue(math.Expm1(call.Argument(0).ToFloat()))
  52. }
  53. func (r *Runtime) math_floor(call FunctionCall) Value {
  54. return floatToValue(math.Floor(call.Argument(0).ToFloat()))
  55. }
  56. func (r *Runtime) math_fround(call FunctionCall) Value {
  57. return floatToValue(float64(float32(call.Argument(0).ToFloat())))
  58. }
  59. func (r *Runtime) math_hypot(call FunctionCall) Value {
  60. var max float64
  61. var hasNaN bool
  62. absValues := make([]float64, 0, len(call.Arguments))
  63. for _, v := range call.Arguments {
  64. arg := nilSafe(v).ToFloat()
  65. if math.IsNaN(arg) {
  66. hasNaN = true
  67. } else {
  68. abs := math.Abs(arg)
  69. if abs > max {
  70. max = abs
  71. }
  72. absValues = append(absValues, abs)
  73. }
  74. }
  75. if math.IsInf(max, 1) {
  76. return _positiveInf
  77. }
  78. if hasNaN {
  79. return _NaN
  80. }
  81. if max == 0 {
  82. return _positiveZero
  83. }
  84. // Kahan summation to avoid rounding errors.
  85. // Normalize the numbers to the largest one to avoid overflow.
  86. var sum, compensation float64
  87. for _, n := range absValues {
  88. n /= max
  89. summand := n*n - compensation
  90. preliminary := sum + summand
  91. compensation = (preliminary - sum) - summand
  92. sum = preliminary
  93. }
  94. return floatToValue(math.Sqrt(sum) * max)
  95. }
  96. func (r *Runtime) math_imul(call FunctionCall) Value {
  97. x := toUint32(call.Argument(0))
  98. y := toUint32(call.Argument(1))
  99. return intToValue(int64(int32(x * y)))
  100. }
  101. func (r *Runtime) math_log(call FunctionCall) Value {
  102. return floatToValue(math.Log(call.Argument(0).ToFloat()))
  103. }
  104. func (r *Runtime) math_log1p(call FunctionCall) Value {
  105. return floatToValue(math.Log1p(call.Argument(0).ToFloat()))
  106. }
  107. func (r *Runtime) math_log10(call FunctionCall) Value {
  108. return floatToValue(math.Log10(call.Argument(0).ToFloat()))
  109. }
  110. func (r *Runtime) math_log2(call FunctionCall) Value {
  111. return floatToValue(math.Log2(call.Argument(0).ToFloat()))
  112. }
  113. func (r *Runtime) math_max(call FunctionCall) Value {
  114. result := math.Inf(-1)
  115. args := call.Arguments
  116. for i, arg := range args {
  117. n := nilSafe(arg).ToFloat()
  118. if math.IsNaN(n) {
  119. args = args[i+1:]
  120. goto NaNLoop
  121. }
  122. result = math.Max(result, n)
  123. }
  124. return floatToValue(result)
  125. NaNLoop:
  126. // All arguments still need to be coerced to number according to the specs.
  127. for _, arg := range args {
  128. nilSafe(arg).ToFloat()
  129. }
  130. return _NaN
  131. }
  132. func (r *Runtime) math_min(call FunctionCall) Value {
  133. result := math.Inf(1)
  134. args := call.Arguments
  135. for i, arg := range args {
  136. n := nilSafe(arg).ToFloat()
  137. if math.IsNaN(n) {
  138. args = args[i+1:]
  139. goto NaNLoop
  140. }
  141. result = math.Min(result, n)
  142. }
  143. return floatToValue(result)
  144. NaNLoop:
  145. // All arguments still need to be coerced to number according to the specs.
  146. for _, arg := range args {
  147. nilSafe(arg).ToFloat()
  148. }
  149. return _NaN
  150. }
  151. func (r *Runtime) math_pow(call FunctionCall) Value {
  152. x := call.Argument(0)
  153. y := call.Argument(1)
  154. if x, ok := x.(valueInt); ok {
  155. if y, ok := y.(valueInt); ok && y >= 0 && y < 64 {
  156. if y == 0 {
  157. return intToValue(1)
  158. }
  159. if x == 0 {
  160. return intToValue(0)
  161. }
  162. ip := ipow(int64(x), int64(y))
  163. if ip != 0 {
  164. return intToValue(ip)
  165. }
  166. }
  167. }
  168. xf := x.ToFloat()
  169. yf := y.ToFloat()
  170. if math.Abs(xf) == 1 && math.IsInf(yf, 0) {
  171. return _NaN
  172. }
  173. if xf == 1 && math.IsNaN(yf) {
  174. return _NaN
  175. }
  176. return floatToValue(math.Pow(xf, yf))
  177. }
  178. func (r *Runtime) math_random(call FunctionCall) Value {
  179. return floatToValue(r.rand())
  180. }
  181. func (r *Runtime) math_round(call FunctionCall) Value {
  182. f := call.Argument(0).ToFloat()
  183. if math.IsNaN(f) {
  184. return _NaN
  185. }
  186. if f == 0 && math.Signbit(f) {
  187. return _negativeZero
  188. }
  189. t := math.Trunc(f)
  190. if f >= 0 {
  191. if f-t >= 0.5 {
  192. return floatToValue(t + 1)
  193. }
  194. } else {
  195. if t-f > 0.5 {
  196. return floatToValue(t - 1)
  197. }
  198. }
  199. return floatToValue(t)
  200. }
  201. func (r *Runtime) math_sign(call FunctionCall) Value {
  202. arg := call.Argument(0)
  203. num := arg.ToFloat()
  204. if math.IsNaN(num) || num == 0 { // this will match -0 too
  205. return arg
  206. }
  207. if num > 0 {
  208. return intToValue(1)
  209. }
  210. return intToValue(-1)
  211. }
  212. func (r *Runtime) math_sin(call FunctionCall) Value {
  213. return floatToValue(math.Sin(call.Argument(0).ToFloat()))
  214. }
  215. func (r *Runtime) math_sinh(call FunctionCall) Value {
  216. return floatToValue(math.Sinh(call.Argument(0).ToFloat()))
  217. }
  218. func (r *Runtime) math_sqrt(call FunctionCall) Value {
  219. return floatToValue(math.Sqrt(call.Argument(0).ToFloat()))
  220. }
  221. func (r *Runtime) math_tan(call FunctionCall) Value {
  222. return floatToValue(math.Tan(call.Argument(0).ToFloat()))
  223. }
  224. func (r *Runtime) math_tanh(call FunctionCall) Value {
  225. return floatToValue(math.Tanh(call.Argument(0).ToFloat()))
  226. }
  227. func (r *Runtime) math_trunc(call FunctionCall) Value {
  228. arg := call.Argument(0)
  229. if i, ok := arg.(valueInt); ok {
  230. return i
  231. }
  232. return floatToValue(math.Trunc(arg.ToFloat()))
  233. }
  234. func (r *Runtime) createMath(val *Object) objectImpl {
  235. m := &baseObject{
  236. class: classMath,
  237. val: val,
  238. extensible: true,
  239. prototype: r.global.ObjectPrototype,
  240. }
  241. m.init()
  242. m._putProp("E", valueFloat(math.E), false, false, false)
  243. m._putProp("LN10", valueFloat(math.Ln10), false, false, false)
  244. m._putProp("LN2", valueFloat(math.Ln2), false, false, false)
  245. m._putProp("LOG10E", valueFloat(math.Log10E), false, false, false)
  246. m._putProp("LOG2E", valueFloat(math.Log2E), false, false, false)
  247. m._putProp("PI", valueFloat(math.Pi), false, false, false)
  248. m._putProp("SQRT1_2", valueFloat(sqrt1_2), false, false, false)
  249. m._putProp("SQRT2", valueFloat(math.Sqrt2), false, false, false)
  250. m._putSym(SymToStringTag, valueProp(asciiString(classMath), false, false, true))
  251. m._putProp("abs", r.newNativeFunc(r.math_abs, nil, "abs", nil, 1), true, false, true)
  252. m._putProp("acos", r.newNativeFunc(r.math_acos, nil, "acos", nil, 1), true, false, true)
  253. m._putProp("acosh", r.newNativeFunc(r.math_acosh, nil, "acosh", nil, 1), true, false, true)
  254. m._putProp("asin", r.newNativeFunc(r.math_asin, nil, "asin", nil, 1), true, false, true)
  255. m._putProp("asinh", r.newNativeFunc(r.math_asinh, nil, "asinh", nil, 1), true, false, true)
  256. m._putProp("atan", r.newNativeFunc(r.math_atan, nil, "atan", nil, 1), true, false, true)
  257. m._putProp("atanh", r.newNativeFunc(r.math_atanh, nil, "atanh", nil, 1), true, false, true)
  258. m._putProp("atan2", r.newNativeFunc(r.math_atan2, nil, "atan2", nil, 2), true, false, true)
  259. m._putProp("cbrt", r.newNativeFunc(r.math_cbrt, nil, "cbrt", nil, 1), true, false, true)
  260. m._putProp("ceil", r.newNativeFunc(r.math_ceil, nil, "ceil", nil, 1), true, false, true)
  261. m._putProp("clz32", r.newNativeFunc(r.math_clz32, nil, "clz32", nil, 1), true, false, true)
  262. m._putProp("cos", r.newNativeFunc(r.math_cos, nil, "cos", nil, 1), true, false, true)
  263. m._putProp("cosh", r.newNativeFunc(r.math_cosh, nil, "cosh", nil, 1), true, false, true)
  264. m._putProp("exp", r.newNativeFunc(r.math_exp, nil, "exp", nil, 1), true, false, true)
  265. m._putProp("expm1", r.newNativeFunc(r.math_expm1, nil, "expm1", nil, 1), true, false, true)
  266. m._putProp("floor", r.newNativeFunc(r.math_floor, nil, "floor", nil, 1), true, false, true)
  267. m._putProp("fround", r.newNativeFunc(r.math_fround, nil, "fround", nil, 1), true, false, true)
  268. m._putProp("hypot", r.newNativeFunc(r.math_hypot, nil, "hypot", nil, 2), true, false, true)
  269. m._putProp("imul", r.newNativeFunc(r.math_imul, nil, "imul", nil, 2), true, false, true)
  270. m._putProp("log", r.newNativeFunc(r.math_log, nil, "log", nil, 1), true, false, true)
  271. m._putProp("log1p", r.newNativeFunc(r.math_log1p, nil, "log1p", nil, 1), true, false, true)
  272. m._putProp("log10", r.newNativeFunc(r.math_log10, nil, "log10", nil, 1), true, false, true)
  273. m._putProp("log2", r.newNativeFunc(r.math_log2, nil, "log2", nil, 1), true, false, true)
  274. m._putProp("max", r.newNativeFunc(r.math_max, nil, "max", nil, 2), true, false, true)
  275. m._putProp("min", r.newNativeFunc(r.math_min, nil, "min", nil, 2), true, false, true)
  276. m._putProp("pow", r.newNativeFunc(r.math_pow, nil, "pow", nil, 2), true, false, true)
  277. m._putProp("random", r.newNativeFunc(r.math_random, nil, "random", nil, 0), true, false, true)
  278. m._putProp("round", r.newNativeFunc(r.math_round, nil, "round", nil, 1), true, false, true)
  279. m._putProp("sign", r.newNativeFunc(r.math_sign, nil, "sign", nil, 1), true, false, true)
  280. m._putProp("sin", r.newNativeFunc(r.math_sin, nil, "sin", nil, 1), true, false, true)
  281. m._putProp("sinh", r.newNativeFunc(r.math_sinh, nil, "sinh", nil, 1), true, false, true)
  282. m._putProp("sqrt", r.newNativeFunc(r.math_sqrt, nil, "sqrt", nil, 1), true, false, true)
  283. m._putProp("tan", r.newNativeFunc(r.math_tan, nil, "tan", nil, 1), true, false, true)
  284. m._putProp("tanh", r.newNativeFunc(r.math_tanh, nil, "tanh", nil, 1), true, false, true)
  285. m._putProp("trunc", r.newNativeFunc(r.math_trunc, nil, "trunc", nil, 1), true, false, true)
  286. return m
  287. }
  288. func (r *Runtime) initMath() {
  289. r.addToGlobal("Math", r.newLazyObject(r.createMath))
  290. }