github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/math/math.go (about)

     1  package math
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  
     7  	"github.com/hirochachacha/plua/internal/arith"
     8  	"github.com/hirochachacha/plua/object"
     9  	"github.com/hirochachacha/plua/object/fnutil"
    10  )
    11  
    12  func abs(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    13  	ap := fnutil.NewArgParser(th, args)
    14  
    15  	f, err := ap.ToGoFloat64(0)
    16  	if err != nil {
    17  		return nil, err
    18  	}
    19  
    20  	if i, ok := args[0].(object.Integer); ok {
    21  		if i < 0 {
    22  			return []object.Value{-i}, nil
    23  		}
    24  
    25  		return []object.Value{i}, nil
    26  	}
    27  
    28  	return []object.Value{object.Number(math.Abs(f))}, nil
    29  }
    30  
    31  func acos(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    32  	ap := fnutil.NewArgParser(th, args)
    33  
    34  	f, err := ap.ToGoFloat64(0)
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	return []object.Value{object.Number(math.Acos(f))}, nil
    40  }
    41  
    42  func asin(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    43  	ap := fnutil.NewArgParser(th, args)
    44  
    45  	f, err := ap.ToGoFloat64(0)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	return []object.Value{object.Number(math.Asin(f))}, nil
    51  }
    52  
    53  func atan(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    54  	ap := fnutil.NewArgParser(th, args)
    55  
    56  	y, err := ap.ToGoFloat64(0)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	x, err := ap.OptGoFloat64(1, 1)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  
    66  	return []object.Value{object.Number(math.Atan2(y, x))}, nil
    67  }
    68  
    69  func ceil(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    70  	ap := fnutil.NewArgParser(th, args)
    71  
    72  	if i, err := ap.ToInteger(0); err == nil {
    73  		return []object.Value{i}, nil
    74  	}
    75  
    76  	f, err := ap.ToGoFloat64(0)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	f = math.Ceil(f)
    82  
    83  	fval := object.Number(f)
    84  
    85  	if ival, ok := object.ToInteger(fval); ok {
    86  		return []object.Value{ival}, nil
    87  	}
    88  
    89  	return []object.Value{fval}, nil
    90  }
    91  
    92  func cos(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    93  	ap := fnutil.NewArgParser(th, args)
    94  
    95  	f, err := ap.ToGoFloat64(0)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	return []object.Value{object.Number(math.Cos(f))}, nil
   101  }
   102  
   103  func deg(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   104  	ap := fnutil.NewArgParser(th, args)
   105  
   106  	f, err := ap.ToGoFloat64(0)
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  
   111  	return []object.Value{object.Number((f * 180) / math.Pi)}, nil
   112  }
   113  
   114  func exp(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   115  	ap := fnutil.NewArgParser(th, args)
   116  
   117  	f, err := ap.ToGoFloat64(0)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	return []object.Value{object.Number(math.Exp(f))}, nil
   123  }
   124  
   125  func floor(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   126  	ap := fnutil.NewArgParser(th, args)
   127  
   128  	if i, err := ap.ToInteger(0); err == nil {
   129  		return []object.Value{i}, nil
   130  	}
   131  
   132  	f, err := ap.ToGoFloat64(0)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	f = math.Floor(f)
   138  
   139  	fval := object.Number(f)
   140  
   141  	if ival, ok := object.ToInteger(fval); ok {
   142  		return []object.Value{ival}, nil
   143  	}
   144  
   145  	return []object.Value{fval}, nil
   146  }
   147  
   148  func fmod(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   149  	ap := fnutil.NewArgParser(th, args)
   150  
   151  	if len(args) >= 2 {
   152  		if x, ok := args[0].(object.Integer); ok {
   153  			if y, ok := args[1].(object.Integer); ok {
   154  				if y == 0 {
   155  					return nil, ap.ArgError(1, "zero")
   156  				}
   157  
   158  				if x == object.MinInteger && y == -1 {
   159  					return []object.Value{object.Integer(0)}, nil
   160  				}
   161  
   162  				return []object.Value{x % y}, nil
   163  			}
   164  		}
   165  	}
   166  
   167  	x, err := ap.ToGoFloat64(0)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	y, err := ap.ToGoFloat64(1)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	return []object.Value{object.Number(math.Mod(x, y))}, nil
   178  }
   179  
   180  // log(x, [, base])
   181  func log(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   182  	ap := fnutil.NewArgParser(th, args)
   183  
   184  	f, err := ap.ToGoFloat64(0)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  
   189  	if len(args) == 1 {
   190  		return []object.Value{object.Number(math.Log(f))}, nil
   191  	}
   192  
   193  	base, err := ap.ToGoInt64(1)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  
   198  	switch base {
   199  	case 2:
   200  		return []object.Value{object.Number(math.Log2(f))}, nil
   201  	case 10:
   202  		return []object.Value{object.Number(math.Log10(f))}, nil
   203  	default:
   204  		return []object.Value{object.Number(math.Log(f) / math.Log(float64(base)))}, nil
   205  	}
   206  }
   207  
   208  func max(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   209  	ap := fnutil.NewArgParser(th, args)
   210  
   211  	max, err := ap.ToValue(0)
   212  	if err != nil {
   213  		return nil, err
   214  	}
   215  
   216  	for _, arg := range args[1:] {
   217  		b, err := arith.CallLessThan(th, false, max, arg)
   218  		if err != nil {
   219  			return nil, err
   220  		}
   221  		if b {
   222  			max = arg
   223  		}
   224  	}
   225  
   226  	return []object.Value{max}, nil
   227  }
   228  
   229  func min(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   230  	ap := fnutil.NewArgParser(th, args)
   231  
   232  	min, err := ap.ToValue(0)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  
   237  	for _, arg := range args[1:] {
   238  		b, err := arith.CallLessThan(th, false, arg, min)
   239  		if err != nil {
   240  			return nil, err
   241  		}
   242  		if b {
   243  			min = arg
   244  		}
   245  	}
   246  
   247  	return []object.Value{min}, nil
   248  }
   249  
   250  func modf(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   251  	ap := fnutil.NewArgParser(th, args)
   252  
   253  	f, err := ap.ToGoFloat64(0)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	int, frac := math.Modf(f)
   259  
   260  	if math.IsNaN(frac) && !math.IsNaN(int) {
   261  		frac = 0
   262  	}
   263  
   264  	fval := object.Number(int)
   265  
   266  	if ival, ok := object.ToInteger(fval); ok {
   267  		return []object.Value{ival, object.Number(frac)}, nil
   268  	}
   269  
   270  	return []object.Value{fval, object.Number(frac)}, nil
   271  }
   272  
   273  func rad(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   274  	ap := fnutil.NewArgParser(th, args)
   275  
   276  	f, err := ap.ToGoFloat64(0)
   277  	if err != nil {
   278  		return nil, err
   279  	}
   280  
   281  	return []object.Value{object.Number((math.Pi * f) / 180)}, nil
   282  }
   283  
   284  // random([m, [, n]])
   285  func random(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   286  	ap := fnutil.NewArgParser(th, args)
   287  
   288  	r := rand.Float64()
   289  
   290  	switch len(args) {
   291  	case 0:
   292  		return []object.Value{object.Number(r)}, nil
   293  	case 1:
   294  		m := object.Integer(1)
   295  
   296  		n, err := ap.ToInteger(0)
   297  		if err != nil {
   298  			return nil, err
   299  		}
   300  
   301  		if m > n {
   302  			return nil, ap.ArgError(1, "interval is empty")
   303  		}
   304  
   305  		r *= float64(n-m) + 1.0
   306  
   307  		return []object.Value{object.Integer(r) + m}, nil
   308  	case 2:
   309  		m, err := ap.ToInteger(0)
   310  		if err != nil {
   311  			return nil, err
   312  		}
   313  
   314  		n, err := ap.ToInteger(1)
   315  		if err != nil {
   316  			return nil, err
   317  		}
   318  
   319  		if m > n {
   320  			return nil, ap.ArgError(1, "interval is empty")
   321  		}
   322  		if m < 0 && n > math.MaxInt64+m {
   323  			return nil, ap.ArgError(1, "interval too large")
   324  		}
   325  
   326  		r *= float64(n-m) + 1.0
   327  
   328  		return []object.Value{object.Integer(r) + m}, nil
   329  	default:
   330  		return nil, object.NewRuntimeError("wrong number of arguments")
   331  	}
   332  }
   333  
   334  func randomseed(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   335  	ap := fnutil.NewArgParser(th, args)
   336  
   337  	i, err := ap.ToGoInt64(0)
   338  	if err != nil {
   339  		return nil, err
   340  	}
   341  
   342  	rand.Seed(i)
   343  
   344  	return nil, nil
   345  }
   346  
   347  func sin(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   348  	ap := fnutil.NewArgParser(th, args)
   349  
   350  	f, err := ap.ToGoFloat64(0)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	return []object.Value{object.Number(math.Sin(f))}, nil
   356  }
   357  
   358  func sqrt(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   359  	ap := fnutil.NewArgParser(th, args)
   360  
   361  	f, err := ap.ToGoFloat64(0)
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	return []object.Value{object.Number(math.Sqrt(f))}, nil
   367  }
   368  
   369  func tan(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   370  	ap := fnutil.NewArgParser(th, args)
   371  
   372  	f, err := ap.ToGoFloat64(0)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  
   377  	return []object.Value{object.Number(math.Tan(f))}, nil
   378  }
   379  
   380  func tointeger(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   381  	ap := fnutil.NewArgParser(th, args)
   382  
   383  	i, err := ap.ToInteger(0)
   384  	if err != nil {
   385  		if len(args) != 0 {
   386  			return []object.Value{nil}, nil
   387  		}
   388  		return nil, err
   389  	}
   390  
   391  	return []object.Value{i}, nil
   392  }
   393  
   394  func _type(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   395  	ap := fnutil.NewArgParser(th, args)
   396  
   397  	val, err := ap.ToTypes(0, object.TNUMBER)
   398  	if err != nil {
   399  		if len(args) != 0 {
   400  			return []object.Value{nil}, nil
   401  		}
   402  
   403  		return nil, err
   404  	}
   405  
   406  	switch val.(type) {
   407  	case object.Integer:
   408  		return []object.Value{object.String("integer")}, nil
   409  	case object.Number:
   410  		return []object.Value{object.String("float")}, nil
   411  	}
   412  
   413  	return nil, nil
   414  }
   415  
   416  func ult(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   417  	ap := fnutil.NewArgParser(th, args)
   418  
   419  	x, err := ap.ToGoInt64(0)
   420  	if err != nil {
   421  		return nil, err
   422  	}
   423  
   424  	y, err := ap.ToGoInt64(1)
   425  	if err != nil {
   426  		return nil, err
   427  	}
   428  
   429  	return []object.Value{object.Boolean(uint64(x) < uint64(y))}, nil
   430  }
   431  
   432  func Open(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   433  	m := th.NewTableSize(0, 27)
   434  
   435  	m.Set(object.String("huge"), object.Number(math.Inf(1)))
   436  	m.Set(object.String("pi"), object.Number(math.Pi))
   437  	m.Set(object.String("mininteger"), object.MinInteger)
   438  	m.Set(object.String("maxinteger"), object.MaxInteger)
   439  
   440  	m.Set(object.String("abs"), object.GoFunction(abs))
   441  	m.Set(object.String("acos"), object.GoFunction(acos))
   442  	m.Set(object.String("asin"), object.GoFunction(asin))
   443  	m.Set(object.String("atan"), object.GoFunction(atan))
   444  	m.Set(object.String("ceil"), object.GoFunction(ceil))
   445  	m.Set(object.String("cos"), object.GoFunction(cos))
   446  	m.Set(object.String("deg"), object.GoFunction(deg))
   447  	m.Set(object.String("exp"), object.GoFunction(exp))
   448  	m.Set(object.String("floor"), object.GoFunction(floor))
   449  	m.Set(object.String("fmod"), object.GoFunction(fmod))
   450  	m.Set(object.String("log"), object.GoFunction(log))
   451  	m.Set(object.String("max"), object.GoFunction(max))
   452  	m.Set(object.String("min"), object.GoFunction(min))
   453  	m.Set(object.String("modf"), object.GoFunction(modf))
   454  	m.Set(object.String("rad"), object.GoFunction(rad))
   455  	m.Set(object.String("random"), object.GoFunction(random))
   456  	m.Set(object.String("randomseed"), object.GoFunction(randomseed))
   457  	m.Set(object.String("sin"), object.GoFunction(sin))
   458  	m.Set(object.String("sqrt"), object.GoFunction(sqrt))
   459  	m.Set(object.String("tan"), object.GoFunction(tan))
   460  	m.Set(object.String("tointeger"), object.GoFunction(tointeger))
   461  	m.Set(object.String("type"), object.GoFunction(_type))
   462  	m.Set(object.String("ult"), object.GoFunction(ult))
   463  
   464  	return []object.Value{m}, nil
   465  }