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