The complete source code of IdealIRC http://www.idealirc.org/
 
 
 
 
idealirc/Script/Builtin/Mathematics.cpp

445 lines
12 KiB

/*
* IdealIRC Script Engine - Scripting tailored for IRC clients.
* Copyright (C) 2021 Tom-Andre Barstad.
* This software is licensed under the Software Attribution License.
* See LICENSE for more information.
*/
#include "Mathematics.h"
#include "Error.h"
#include "Script/ValueExtract.h"
#include "Script/ScriptException.h"
#include <random>
#include <math.h>
using namespace Builtin::Error;
namespace Builtin::Mathematics {
ValueHolder pow(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 2)
throwInsufficientParameters("pow", args.size(), 2);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("pow", 1);
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
throwNotANumber("pow", 2);
if (args[0] == 0 && args[1] == 0)
throw ScriptException("pow: 0^0 is undefined");
if (args[1] < 0)
throw ScriptException("pow: Cannot represent negative exponents");
if (args[0].getType() == ValueHolder::Type::Real
|| args[1].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
auto P = ValueExtract(args[1]).toReal();
return std::pow(N, P);
}
else {
auto N = ValueExtract(args[0]).toInt();
auto P = ValueExtract(args[1]).toInt();
return static_cast<int>(std::pow(N, P));
}
}
ValueHolder sqrt(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("sqrt", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("sqrt", 1);
if (args[0] < 0)
throw ScriptException("sqrt: Root of " + args[0].toStdString() + " is an imaginary number, not supported.");
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::sqrt(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::sqrt(N);
}
}
ValueHolder cbrt(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("cbrt", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("cbrt", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::cbrt(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::cbrt(N);
}
}
ValueHolder floor(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("floor", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("floor", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return static_cast<int>(std::floor(N));
}
else {
return args[0];
}
}
ValueHolder ceil(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("ceil", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("ceil", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return static_cast<int>(std::ceil(N));
}
else {
return args[0];
}
}
ValueHolder round(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("round", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("round", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return static_cast<int>(std::round(N));
}
else {
return args[0];
}
}
ValueHolder abs(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("abs", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("abs", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return static_cast<int>(std::abs(N));
}
else {
auto N = ValueExtract(args[0]).toInt();
return static_cast<int>(std::abs(N));
}
}
ValueHolder clamp(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 3)
throwInsufficientParameters("clamp", args.size(), 3);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("clamp", 1);
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
throwNotANumber("clamp", 2);
if (args[2].getType() != ValueHolder::Type::Integer && args[2].getType() != ValueHolder::Type::Real)
throwNotANumber("clamp", 3);
if (args[0].getType() == ValueHolder::Type::Real
|| args[1].getType() == ValueHolder::Type::Real
|| args[2].getType() == ValueHolder::Type::Real) {
auto low = ValueExtract(args[1]).toReal();
auto high = ValueExtract(args[2]).toReal();
if (low > high)
throw ScriptException("clamp: low > high");
auto N = ValueExtract(args[0]).toReal();
if (N < low)
return low;
else if (N > high)
return high;
else
return N;
}
else {
auto low = ValueExtract(args[1]).toInt();
auto high = ValueExtract(args[2]).toInt();
if (low > high)
throw ScriptException("clamp: low > high");
auto N = ValueExtract(args[0]).toInt();
if (N < low)
return low;
else if (N > high)
return high;
else
return N;
}
}
ValueHolder clamp01(Script& script, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("clamp01", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("clamp01", 1);
std::vector<ValueHolder> clampArgs { args[0], 0, 1 };
return clamp(script, clampArgs);
}
ValueHolder rand(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 2)
throwInsufficientParameters("rand", args.size(), 2);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("rand", 1);
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
throwNotANumber("rand", 2);
std::random_device rd;
std::mt19937 mt(rd());
if (args[0].getType() == ValueHolder::Type::Real || args[1].getType() == ValueHolder::Type::Real) {
auto low = ValueExtract(args[0]).toReal();
auto high = ValueExtract(args[1]).toReal();
if (low > high)
throw ScriptException("rand: low > high");
std::uniform_real_distribution<double> uniform_dist(low, high);
return uniform_dist(mt);
}
else {
auto low = ValueExtract(args[0]).toInt();
auto high = ValueExtract(args[1]).toInt();
if (low > high)
throw ScriptException("rand: low > high");
std::uniform_int_distribution<int> uniform_dist(low, high);
return uniform_dist(mt);
}
}
ValueHolder scale(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 5)
throwInsufficientParameters("scale", args.size(), 5);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("scale", 1);
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
throwNotANumber("scale", 2);
if (args[2].getType() != ValueHolder::Type::Integer && args[2].getType() != ValueHolder::Type::Real)
throwNotANumber("scale", 3);
if (args[3].getType() != ValueHolder::Type::Integer && args[3].getType() != ValueHolder::Type::Real)
throwNotANumber("scale", 4);
if (args[4].getType() != ValueHolder::Type::Integer && args[4].getType() != ValueHolder::Type::Real)
throwNotANumber("scale", 5);
if (args[0].getType() == ValueHolder::Type::Real
|| args[1].getType() == ValueHolder::Type::Real
|| args[2].getType() == ValueHolder::Type::Real
|| args[3].getType() == ValueHolder::Type::Real
|| args[4].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
auto oldMin = ValueExtract(args[1]).toReal();
auto oldMax = ValueExtract(args[2]).toReal();
auto newMin = ValueExtract(args[3]).toReal();
auto newMax = ValueExtract(args[4]).toReal();
return newMin + (N - oldMin) * (newMax - newMin) / (oldMax - oldMin);
}
else {
auto N = ValueExtract(args[0]).toInt();
auto oldMin = ValueExtract(args[1]).toInt();
auto oldMax = ValueExtract(args[2]).toInt();
auto newMin = ValueExtract(args[3]).toInt();
auto newMax = ValueExtract(args[4]).toInt();
return newMin + (N - oldMin) * (newMax - newMin) / (oldMax - oldMin);
}
}
ValueHolder log(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("log", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("log", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
if (N < 0)
throwNegativeInputUndefined("log");
return std::log(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
if (N < 0)
throwNegativeInputUndefined("log");
return std::log(N);
}
}
ValueHolder log10(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("log10", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("log10", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
if (N < 0)
throwNegativeInputUndefined("log10");
return std::log10(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
if (N < 0)
throwNegativeInputUndefined("log10");
return std::log10(N);
}
}
ValueHolder sin(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("sin", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("sin", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::sin(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::sin(N);
}
}
ValueHolder asin(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("asin", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("asin", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::asin(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::asin(N);
}
}
ValueHolder cos(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("cos", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("cos", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::cos(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::cos(N);
}
}
ValueHolder acos(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("acos", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("acos", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::acos(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::acos(N);
}
}
ValueHolder tan(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("tan", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("tan", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::tan(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::tan(N);
}
}
ValueHolder atan(Script&, std::vector<ValueHolder>& args)
{
if (args.size() != 1)
throwInsufficientParameters("atan", args.size(), 1);
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
throwNotANumber("atan", 1);
if (args[0].getType() == ValueHolder::Type::Real) {
auto N = ValueExtract(args[0]).toReal();
return std::atan(N);
}
else {
auto N = ValueExtract(args[0]).toInt();
return std::atan(N);
}
}
} // namespace Builtin::Mathematics