diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 1afc5f4bbbd..4ae8873911b 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -757,6 +757,20 @@ class Math { } return p_target; } + + static _ALWAYS_INLINE_ double sigmoid_affine(double p_x, double p_amplitude, double p_y_translation) { + return p_amplitude / (1.0 + ::exp(-p_x)) + p_y_translation; + } + static _ALWAYS_INLINE_ float sigmoid_affine(float p_x, float p_amplitude, float p_y_translation) { + return p_amplitude / (1.0f + expf(-p_x)) + p_y_translation; + } + + static _ALWAYS_INLINE_ double sigmoid_affine_approx(double p_x, double p_amplitude, double p_y_translation) { + return p_amplitude * (0.5 + p_x / (4.0 + fabs(p_x))) + p_y_translation; + } + static _ALWAYS_INLINE_ float sigmoid_affine_approx(float p_x, float p_amplitude, float p_y_translation) { + return p_amplitude * (0.5f + p_x / (4.0f + fabsf(p_x))) + p_y_translation; + } }; #endif // MATH_FUNCS_H diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 384fe6c4a66..b6dbfab6af6 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -639,6 +639,22 @@ double VariantUtilityFunctions::pingpong(double value, double length) { return Math::pingpong(value, length); } +double VariantUtilityFunctions::sigmoid(double x) { + return Math::sigmoid_affine(x, 1.0, 0.0); +} + +double VariantUtilityFunctions::sigmoid_approx(double x) { + return Math::sigmoid_affine_approx(x, 1.0, 0.0); +} + +double VariantUtilityFunctions::sigmoid_affine(double x, double amplitude, double y_translation) { + return Math::sigmoid_affine(x, amplitude, y_translation); +} + +double VariantUtilityFunctions::sigmoid_affine_approx(double x, double amplitude, double y_translation) { + return Math::sigmoid_affine_approx(x, amplitude, y_translation); +} + Variant VariantUtilityFunctions::max(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 2) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -1787,6 +1803,11 @@ void Variant::_register_variant_utility_functions() { FUNCBINDR(nearest_po2, sarray("value"), Variant::UTILITY_FUNC_TYPE_MATH); FUNCBINDR(pingpong, sarray("value", "length"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sigmoid, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sigmoid_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sigmoid_affine, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH); + FUNCBINDR(sigmoid_affine_approx, sarray("x", "amplitude", "y_translation"), Variant::UTILITY_FUNC_TYPE_MATH); + // Random FUNCBIND(randomize, sarray(), Variant::UTILITY_FUNC_TYPE_RANDOM); diff --git a/core/variant/variant_utility.h b/core/variant/variant_utility.h index 75cde4942b5..f4dcbbfdf30 100644 --- a/core/variant/variant_utility.h +++ b/core/variant/variant_utility.h @@ -115,6 +115,10 @@ struct VariantUtilityFunctions { static double clampf(double x, double min, double max); static int64_t clampi(int64_t x, int64_t min, int64_t max); static int64_t nearest_po2(int64_t x); + static double sigmoid(double x); + static double sigmoid_approx(double x); + static double sigmoid_affine(double x, double amplitude, double y_translation); + static double sigmoid_affine_approx(double x, double amplitude, double y_translation); // Random static void randomize(); static int64_t randi(); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 55d00b6cf90..78611e8c64c 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1175,6 +1175,84 @@ [/codeblocks] + + + + + Computes the sigmoid for [param x], which maps the input value into the range (0, 1). + The sigmoid function is defined as: + [codeblock] + sigmoid(x) = 1 / (1 + exp(-x)) + [/codeblock] + This is the most accurate implementation of the sigmoid. + [codeblock] + var result = sigmoid(0.0) # result is 0.5 + var result = sigmoid(1.0) # result is approximately 0.88 + var result = sigmoid(-1.0) # result is approximately 0.27 + var result = sigmoid(5.0) # result is approximately 0.99 + [/codeblock] + [b]Note:[/b] For faster but less accurate approximation, see [method sigmoid_approx]. + + + + + + + + + Computes an affine-transformed sigmoid for [param x], which allows scaling by [param amplitude] and translation by [param y_translate]. + The affine sigmoid function is defined as: + [codeblock] + affine_sigmoid(x, amplitude, y_translation) = (amplitude / (1 + exp(-x))) + y_translate + [/codeblock] + This function modifies the standard sigmoid by introducing scaling and vertical translation. + [codeblock] + var result = affine_sigmoid(0.0, 1.0, 0.0) # result is 0.5 + var result = affine_sigmoid(1.0, 2.0, -1.0) # result is approximately 0.46 + var result = affine_sigmoid(-1.0, 3.0, 2.0) # result is approximately 2.81 + var result = affine_sigmoid(1.0, 2.0, 2.5) # result is approximately 3.96 + [/codeblock] + [b]Note:[/b] This is a more accurate but computationally heavier version of the affine sigmoid. For faster approximations, see [method sigmoid_affine_approx]. + + + + + + + + + Computes an approximation of the affine-transformed sigmoid function for [param x], allowing scaling by [param amplitude] and translation by [param y_translate]. + The approximation function is defined as: + [codeblock] + affine_sigmoid_approx(x, amplitude, y_translation) = amplitude * (0.5 + (x / (4 + abs(x)))) + y_translate + [/codeblock] + This function approximates the affine sigmoid, offering faster computation at the cost of some precision. It is useful in performance-sensitive environments where both transformation and speed are needed. + [codeblock] + var result = affine_sigmoid_approx(0.0, 1.0, 0.0) # result is 0.5 + var result = affine_sigmoid_approx(2.0, 2.0, 1.0) # result is approximately 2.67 + var result = affine_sigmoid_approx(-1.0, 3.0, 0.5) # result is approximately 1.4 + var result = affine_sigmoid_approx(1.0, 2.0, 2.5) # result is approximately 3.9 + [/codeblock] + + + + + + + Computes an approximation of the sigmoid function for [param x], which maps the input value into the range (0, 1). + The approximation function is defined as: + [codeblock] + sigmoid_approx(x) = 0.5 + (x / (4 + abs(x))) + [/codeblock] + This function is faster than the standard [method sigmoid], especially useful in performance-sensitive environments where a balance between accuracy and speed is desired. + [codeblock] + var result = sigmoid_approx(0.0) # result is 0.5 + var result = sigmoid_approx(2.0) # result is approximately 0.83 + var result = sigmoid_approx(-1.0) # result is approximately 0.3 + var result = sigmoid_approx(5.0) # result is approximately 1.05 + [/codeblock] + +