builtin_math.go 11 KB

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