From 23f2db6d4d754350e5bf5c00958e2093d30d086e Mon Sep 17 00:00:00 2001 From: GUNJ JOSHI Date: Wed, 6 Mar 2024 17:21:14 +0530 Subject: [PATCH] feat: add C implementation for `math/base/special/ellipe` Closes: https://github.com/stdlib-js/stdlib/issues/772 PR-URL: https://github.com/stdlib-js/stdlib/pull/1452 Co-authored-by: Athan Reines Co-authored-by: Pranav Goswami Reviewed-by: Athan Reines Reviewed-by: Pranav Goswami Signed-off-by: GUNJ JOSHI Signed-off-by: Pranav Goswami --- .../math/base/special/ellipe/README.md | 90 +++++ .../ellipe/benchmark/benchmark.native.js | 58 +++ .../ellipe/benchmark/c/native/Makefile | 146 +++++++ .../ellipe/benchmark/c/native/benchmark.c | 136 +++++++ .../math/base/special/ellipe/binding.gyp | 170 ++++++++ .../base/special/ellipe/examples/c/Makefile | 146 +++++++ .../base/special/ellipe/examples/c/example.c | 33 ++ .../math/base/special/ellipe/include.gypi | 53 +++ .../include/stdlib/math/base/special/ellipe.h | 38 ++ .../math/base/special/ellipe/lib/native.js | 61 +++ .../math/base/special/ellipe/manifest.json | 81 ++++ .../base/special/ellipe/scripts/evalpoly.js | 92 +++++ .../math/base/special/ellipe/src/Makefile | 70 ++++ .../math/base/special/ellipe/src/addon.c | 23 ++ .../math/base/special/ellipe/src/main.c | 369 ++++++++++++++++++ .../base/special/ellipe/test/test.native.js | 155 ++++++++ 16 files changed, 1721 insertions(+) create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/benchmark.native.js create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/Makefile create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/benchmark.c create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/binding.gyp create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/Makefile create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/example.c create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/include.gypi create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/include/stdlib/math/base/special/ellipe.h create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/lib/native.js create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/manifest.json create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/src/Makefile create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/src/addon.c create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/src/main.c create mode 100644 lib/node_modules/@stdlib/math/base/special/ellipe/test/test.native.js diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/README.md b/lib/node_modules/@stdlib/math/base/special/ellipe/README.md index 8f8856b436d..b68857550bd 100644 --- a/lib/node_modules/@stdlib/math/base/special/ellipe/README.md +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/README.md @@ -114,6 +114,96 @@ for ( i = 0; i < 100; i++ ) { + + +* * * + +
+ +## C APIs + + + +
+ +
+ + + + + +
+ +### Usage + +```c +#include "stdlib/math/base/special/ellipe.h" +``` + +#### stdlib_base_ellipe( m ) + +Computes the [complete elliptic integral of the second kind][elliptic-integral]. + +```c +double out = stdlib_base_ellipe( 0.5 ); +// returns ~1.351 + +out = stdlib_base_ellipe( -1.0 ); +// returns ~1.910 +``` + +The function accepts the following arguments: + +- **x**: `[in] double` input value. + +```c +double stdlib_base_ellipe( const double m ); +``` + +
+ + + + + +
+ +
+ + + + + +
+ +### Examples + +```c +#include "stdlib/math/base/special/ellipe.h" +#include +#include + +int main( void ) { + double m; + double v; + int i; + + for ( i = 0; i < 100; i++ ) { + m = -1.0 + ( ( (double)rand() / (double)RAND_MAX ) * 2.0 ); + v = stdlib_base_ellipe( m ); + printf( "ellipe(%lf) = %lf\n", m, v ); + } +} +``` + +
+ + + +
+ + + * * *
diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/benchmark.native.js b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/benchmark.native.js new file mode 100644 index 00000000000..b079507c24a --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/benchmark.native.js @@ -0,0 +1,58 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var bench = require( '@stdlib/bench' ); +var randu = require( '@stdlib/random/base/randu' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var tryRequire = require( '@stdlib/utils/try-require' ); +var pkg = require( './../package.json' ).name; + + +// VARIABLES // + +var ellipe = tryRequire( resolve( __dirname, './../lib/native.js' ) ); +var opts = { + 'skip': ( ellipe instanceof Error ) +}; + + +// MAIN // + +bench( pkg+'::native', opts, function benchmark( b ) { + var y; + var i; + + b.tic(); + for ( i = 0; i < b.iterations; i++ ) { + y = ellipe( randu() ); + if ( isnan( y ) ) { + b.fail( 'should not return NaN' ); + } + } + b.toc(); + if ( isnan( y ) ) { + b.fail( 'should not return NaN' ); + } + b.pass( 'benchmark finished' ); + b.end(); +}); diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/Makefile b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/Makefile new file mode 100644 index 00000000000..f69e9da2b4d --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2024 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := benchmark.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled benchmarks. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/benchmark.c b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/benchmark.c new file mode 100644 index 00000000000..0552db4c3c1 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/benchmark/c/native/benchmark.c @@ -0,0 +1,136 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* Benchmark `ellipe`. +*/ +#include "stdlib/math/base/special/ellipe.h" +#include +#include +#include +#include +#include + +#define NAME "ellipe" +#define ITERATIONS 1000000 +#define REPEATS 3 + +/** +* Prints the TAP version. +*/ +void print_version() { + printf( "TAP version 13\n" ); +} + +/** +* Prints the TAP summary. +* +* @param total total number of tests +* @param passing total number of passing tests +*/ +void print_summary( int total, int passing ) { + printf( "#\n" ); + printf( "1..%d\n", total ); // TAP plan + printf( "# total %d\n", total ); + printf( "# pass %d\n", passing ); + printf( "#\n" ); + printf( "# ok\n" ); +} + +/** +* Prints benchmarks results. +* +* @param elapsed elapsed time in seconds +*/ +void print_results( double elapsed ) { + double rate = (double)ITERATIONS / elapsed; + printf( " ---\n" ); + printf( " iterations: %d\n", ITERATIONS ); + printf( " elapsed: %0.9f\n", elapsed ); + printf( " rate: %0.9f\n", rate ); + printf( " ...\n" ); +} + +/** +* Returns a clock time. +* +* @return clock time +*/ +double tic() { + struct timeval now; + gettimeofday( &now, NULL ); + return (double)now.tv_sec + (double)now.tv_usec/1.0e6; +} + +/** +* Generates a random number on the interval [0,1]. +* +* @return random number +*/ +double rand_double() { + int r = rand(); + return (double)r / ( (double)RAND_MAX + 1.0 ); +} + +/** +* Runs a benchmark. +* +* @return elapsed time in seconds +*/ +double benchmark() { + double elapsed; + double x; + double y; + double t; + int i; + + t = tic(); + for ( i = 0; i < ITERATIONS; i++ ) { + x = rand_double(); + y = stdlib_base_ellipe( x ); + if ( y != y ) { + printf( "should not return NaN\n" ); + break; + } + } + elapsed = tic() - t; + if ( y != y ) { + printf( "should not return NaN\n" ); + } + return elapsed; +} + +/** +* Main execution sequence. +*/ +int main( void ) { + double elapsed; + int i; + + // Use the current time to seed the random number generator: + srand( time( NULL ) ); + + print_version(); + for ( i = 0; i < REPEATS; i++ ) { + printf( "# c::native::%s\n", NAME ); + elapsed = benchmark(); + print_results( elapsed ); + printf( "ok %d benchmark finished\n", i+1 ); + } + print_summary( REPEATS, REPEATS ); +} diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/binding.gyp b/lib/node_modules/@stdlib/math/base/special/ellipe/binding.gyp new file mode 100644 index 00000000000..ec399223344 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/binding.gyp @@ -0,0 +1,170 @@ +# @license Apache-2.0 +# +# Copyright (c) 2024 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A `.gyp` file for building a Node.js native add-on. +# +# [1]: https://gyp.gsrc.io/docs/InputFormatReference.md +# [2]: https://gyp.gsrc.io/docs/UserDocumentation.md +{ + # List of files to include in this file: + 'includes': [ + './include.gypi', + ], + + # Define variables to be used throughout the configuration for all targets: + 'variables': { + # Target name should match the add-on export name: + 'addon_target_name%': 'addon', + + # Set variables based on the host OS: + 'conditions': [ + [ + 'OS=="win"', + { + # Define the object file suffix: + 'obj': 'obj', + }, + { + # Define the object file suffix: + 'obj': 'o', + } + ], # end condition (OS=="win") + ], # end conditions + }, # end variables + + # Define compile targets: + 'targets': [ + + # Target to generate an add-on: + { + # The target name should match the add-on export name: + 'target_name': '<(addon_target_name)', + + # Define dependencies: + 'dependencies': [], + + # Define directories which contain relevant include headers: + 'include_dirs': [ + # Local include directory: + '<@(include_dirs)', + ], + + # List of source files: + 'sources': [ + '<@(src_files)', + ], + + # Settings which should be applied when a target's object files are used as linker input: + 'link_settings': { + # Define libraries: + 'libraries': [ + '<@(libraries)', + ], + + # Define library directories: + 'library_dirs': [ + '<@(library_dirs)', + ], + }, + + # C/C++ compiler flags: + 'cflags': [ + # Enable commonly used warning options: + '-Wall', + + # Aggressive optimization: + '-O3', + ], + + # C specific compiler flags: + 'cflags_c': [ + # Specify the C standard to which a program is expected to conform: + '-std=c99', + ], + + # C++ specific compiler flags: + 'cflags_cpp': [ + # Specify the C++ standard to which a program is expected to conform: + '-std=c++11', + ], + + # Linker flags: + 'ldflags': [], + + # Apply conditions based on the host OS: + 'conditions': [ + [ + 'OS=="mac"', + { + # Linker flags: + 'ldflags': [ + '-undefined dynamic_lookup', + '-Wl,-no-pie', + '-Wl,-search_paths_first', + ], + }, + ], # end condition (OS=="mac") + [ + 'OS!="win"', + { + # C/C++ flags: + 'cflags': [ + # Generate platform-independent code: + '-fPIC', + ], + }, + ], # end condition (OS!="win") + ], # end conditions + }, # end target <(addon_target_name) + + # Target to copy a generated add-on to a standard location: + { + 'target_name': 'copy_addon', + + # Declare that the output of this target is not linked: + 'type': 'none', + + # Define dependencies: + 'dependencies': [ + # Require that the add-on be generated before building this target: + '<(addon_target_name)', + ], + + # Define a list of actions: + 'actions': [ + { + 'action_name': 'copy_addon', + 'message': 'Copying addon...', + + # Explicitly list the inputs in the command-line invocation below: + 'inputs': [], + + # Declare the expected outputs: + 'outputs': [ + '<(addon_output_dir)/<(addon_target_name).node', + ], + + # Define the command-line invocation: + 'action': [ + 'cp', + '<(PRODUCT_DIR)/<(addon_target_name).node', + '<(addon_output_dir)/<(addon_target_name).node', + ], + }, + ], # end actions + }, # end target copy_addon + ], # end targets +} diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/Makefile b/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/Makefile new file mode 100644 index 00000000000..6aed70daf16 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2024 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := example.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled examples. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/example.c b/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/example.c new file mode 100644 index 00000000000..8cbeb7c8f97 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/examples/c/example.c @@ -0,0 +1,33 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stdlib/math/base/special/ellipe.h" +#include +#include + +int main( void ) { + double m; + double v; + int i; + + for ( i = 0; i < 100; i++ ) { + m = -1.0 + ( ( (double)rand() / (double)RAND_MAX ) * 2.0 ); + v = stdlib_base_ellipe( m ); + printf( "ellipe(%lf) = %lf\n", m, v ); + } +} diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/include.gypi b/lib/node_modules/@stdlib/math/base/special/ellipe/include.gypi new file mode 100644 index 00000000000..575cb043c0b --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/include.gypi @@ -0,0 +1,53 @@ +# @license Apache-2.0 +# +# Copyright (c) 2024 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A GYP include file for building a Node.js native add-on. +# +# Main documentation: +# +# [1]: https://gyp.gsrc.io/docs/InputFormatReference.md +# [2]: https://gyp.gsrc.io/docs/UserDocumentation.md +{ + # Define variables to be used throughout the configuration for all targets: + 'variables': { + # Source directory: + 'src_dir': './src', + + # Include directories: + 'include_dirs': [ + ' + +/* Begin auto-generated functions. The following functions are auto-generated. Do not edit directly. */ + +// BEGIN: poly_p1 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p1( const double x ) { + return 1.5910034537907922 + (x * (0.41600074399178694 + (x * (0.24579151426410342 + (x * (0.17948148291490615 + (x * (0.14455605708755515 + (x * (0.12320099331242772 + (x * (0.10893881157429353 + (x * (0.09885340987159291 + (x * (0.09143962920174975 + (x * (0.0858425915954139 + (x * 0.08154111871830322))))))))))))))))))); +} + +// END: poly_p1 + +// BEGIN: poly_p2 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p2( const double x ) { + return 1.63525673226458 + (x * (0.4711906261487323 + (x * (0.3097284108314996 + (x * (0.2522083117731357 + (x * (0.22672562321968465 + (x * (0.21577444672958598 + (x * (0.21310877187734892 + (x * (0.21602912460518828 + (x * (0.2232558316330579 + (x * (0.23418050129420992 + (x * (0.24855768297226408 + (x * 0.26636380989261754))))))))))))))))))))); +} + +// END: poly_p2 + +// BEGIN: poly_p3 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p3( const double x ) { + return 1.685750354812596 + (x * (0.5417318486132803 + (x * (0.40152443839069024 + (x * (0.3696424734208891 + (x * (0.37606071535458363 + (x * (0.4052358870851259 + (x * (0.45329438175399905 + (x * (0.5205189476511842 + (x * (0.609426039204995 + (x * (0.7242635222829089 + (x * (0.8710138477098124 + (x * 1.057652872753547))))))))))))))))))))); +} + +// END: poly_p3 + +// BEGIN: poly_p4 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p4( const double x ) { + return 1.7443505972256133 + (x * (0.6348642753719353 + (x * (0.5398425641644455 + (x * (0.5718927051937874 + (x * (0.6702951362654062 + (x * (0.8325865900109772 + (x * (1.0738574482479333 + (x * (1.4220914606754977 + (x * (1.9203871834023047 + (x * (2.6325525483316543 + (x * (3.6521097473190394 + (x * (5.115867135558866 + (x * 7.224080007363877))))))))))))))))))))))); +} + +// END: poly_p4 + +// BEGIN: poly_p5 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p5( const double x ) { + return 1.8138839368169826 + (x * (0.7631632457005573 + (x * (0.7619286053215958 + (x * (0.9510746536684279 + (x * (1.315180671703161 + (x * (1.9285606934774109 + (x * (2.9375093425313787 + (x * (4.594894405442878 + (x * (7.33007122188172 + (x * (11.871512597425301 + (x * (19.45851374822938 + (x * (32.20638657246427 + (x * (53.73749198700555 + (x * 90.27388602941))))))))))))))))))))))))); +} + +// END: poly_p5 + +// BEGIN: poly_p6 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p6( const double x ) { + return 1.8989249102715535 + (x * (0.9505217946182445 + (x * (1.1510775899590158 + (x * (1.7502391069863006 + (x * (2.952676812636875 + (x * (5.285800396121451 + (x * (9.83248571665998 + (x * (18.787148683275596 + (x * (36.61468615273698 + (x * (72.45292395127771 + (x * (145.1079577347069 + (x * (293.4786396308497 + (x * (598.385181505501 + (x * (1228.4200130758634 + (x * 2536.5297553827645))))))))))))))))))))))))))); +} + +// END: poly_p6 + +// BEGIN: poly_p7 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p7( const double x ) { + return 2.0075983984243764 + (x * (1.2484572312123474 + (x * (1.9262346570764797 + (x * (3.7512896400875877 + (x * (8.119944554932045 + (x * (18.665721308735552 + (x * (44.603924842914374 + (x * (109.50920543094983 + (x * (274.2779548232414 + (x * (697.5598008606327 + (x * (1795.7160145002472 + (x * (4668.38171679039 + (x * (12235.762468136643 + (x * (32290.17809718321 + (x * (85713.07608195965 + (x * (228672.1890493117 + (x * 612757.2711915852))))))))))))))))))))))))))))))); +} + +// END: poly_p7 + +// BEGIN: poly_p8 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p8( const double x ) { + return 2.1565156474996434 + (x * (1.7918056418494632 + (x * (3.8267512874657132 + (x * (10.386724683637972 + (x * (31.403314054680703 + (x * (100.92370394986955 + (x * (337.3268282632273 + (x * (1158.7079305678278 + (x * (4060.9907421936323 + (x * (14454.001840343448 + (x * (52076.661075994045 + (x * (189493.65914621568 + (x * (695184.5762413896 + (x * (2567994.048255285 + (x * (9541921.966748387 + (x * (35634927.44218076 + (x * (133669298.46120408 + (x * (503352186.68662846 + (x * (1901975729.53866 + (x * 7208915015.330104))))))))))))))))))))))))))))))))))))); +} + +// END: poly_p8 + +// BEGIN: poly_p9 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p9( const double x ) { + return 2.3181226217125106 + (x * (2.6169201502912327 + (x * (7.897935075731356 + (x * (30.502397154466724 + (x * (131.48693655235286 + (x * (602.9847637356492 + (x * (2877.024617809973 + (x * (14110.519919151804 + (x * (70621.4408815654 + (x * (358977.266582531 + (x * (1847238.2637239718 + (x * (9600515.416049214 + (x * (50307677.08502367 + (x * (265444188.6527128 + (x * (1408862325.0287027 + (x * 7515687935.373775))))))))))))))))))))))))))))); +} + +// END: poly_p9 + +// BEGIN: poly_p10 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p10( const double x ) { + return 2.473596173751344 + (x * (3.727624244118099 + (x * (15.607393035549306 + (x * (84.12850842805888 + (x * (506.98181970406137 + (x * (3252.2770581451236 + (x * (21713.242419574344 + (x * (149037.04518909327 + (x * (1043999.3310899908 + (x * (7427974.817042039 + (x * (53503839.67558661 + (x * (389249886.99487084 + (x * (2855288351.1008105 + (x * (21090077038.76684 + (x * (156699833947.7902 + (x * (1170222242422.44 + (x * (8777948323668.9375 + (x * (66101242752484.95 + (x * (499488053713388.8 + (x * 37859743397240296.0))))))))))))))))))))))))))))))))))))); +} + +// END: poly_p10 + +// BEGIN: poly_p11 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p11( const double x ) { + return 0.0 + (x * (0.0625 + (x * (0.03125 + (x * (0.0205078125 + (x * (0.01513671875 + (x * (0.011934280395507812 + (x * (0.009816169738769531 + (x * (0.008315593004226685 + (x * (0.007199153304100037 + (x * (0.00633745662344154 + (x * (0.00565311038371874 + (x * (0.005097046040418718 + (x * (0.004636680381850056 + (x * (0.004249547423822886 + (x * 0.003919665602267974))))))))))))))))))))))))))); +} + +// END: poly_p11 + +// BEGIN: poly_p12 + +/** +* Evaluates a polynomial. +* +* ## Notes +* +* - The implementation uses [Horner's rule][horners-method] for efficient computation. +* +* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method +* +* @param x value at which to evaluate the polynomial +* @return evaluated polynomial +*/ +static double poly_p12( const double x ) { + return 1.5910034537907922 + (x * (0.41600074399178694 + (x * (0.24579151426410342 + (x * (0.17948148291490615 + (x * (0.14455605708755515 + (x * (0.12320099331242772 + (x * (0.10893881157429353 + (x * (0.09885340987159291 + (x * (0.09143962920174975 + (x * (0.0858425915954139 + (x * 0.08154111871830322))))))))))))))))))); +} + +// END: poly_p12 + +/* End auto-generated functions. */ + +/** +* Computes the complete elliptic integral of the second kind. +* +* @param x input value +* @return output value +* +* @example +* double out = stdlib_base_ellipe( 0.5 ); +* // returns ~1.351 +*/ +double stdlib_base_ellipe( const double m ) { + int8_t FLG; + double kdm; + double edm; + double td; + double km; + double t; + double x; + + FLG = 0; + x = m; + if ( m < 0.0 ) { + x = m / ( m - 1.0 ); + FLG += 1; + } + if ( x == 0.0 ) { + return STDLIB_CONSTANT_FLOAT64_HALF_PI; + } + if ( x == 1.0 ) { + return 1.0; + } + if ( x > 1.0 ) { + return 0.0 / 0.0; // NaN + } + if ( x < 0.1 ) { + t = poly_p1( x - 0.05 ); + } else if ( x < 0.2 ) { + t = poly_p2( x - 0.15 ); + } else if ( x < 0.3 ) { + t = poly_p3( x - 0.25 ); + } else if ( x < 0.4 ) { + t = poly_p4( x - 0.35 ); + } else if ( x < 0.5 ) { + t = poly_p5( x - 0.45 ); + } else if ( x < 0.6 ) { + t = poly_p6( x - 0.55 ); + } else if ( x < 0.7 ) { + t = poly_p7( x - 0.65 ); + } else if ( x < 0.8 ) { + t = poly_p8( x - 0.75 ); + } else if ( x < 0.85 ) { + t = poly_p9( x - 0.825 ); + } else if ( x < 0.9 ) { + t = poly_p10( x - 0.875 ); + } else { + td = 0.95 - x; + kdm = poly_p11( td ); + edm = poly_p12( td ); + km = ellipe( x ); + + // To avoid precision loss near 1, we use Eq. 33 from Fukushima (2009): + t = ( STDLIB_CONSTANT_FLOAT64_HALF_PI + ( km * (kdm - edm) ) ) / kdm; + } + if ( FLG == 1 ) { + // Complete the transformation mentioned above for m < 0: + return t * stdlib_base_sqrt( 1.0 - m ); + } + return t; +} diff --git a/lib/node_modules/@stdlib/math/base/special/ellipe/test/test.native.js b/lib/node_modules/@stdlib/math/base/special/ellipe/test/test.native.js new file mode 100644 index 00000000000..37328571025 --- /dev/null +++ b/lib/node_modules/@stdlib/math/base/special/ellipe/test/test.native.js @@ -0,0 +1,155 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2024 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +'use strict'; + +// MODULES // + +var resolve = require( 'path' ).resolve; +var tape = require( 'tape' ); +var isnan = require( '@stdlib/math/base/assert/is-nan' ); +var PINF = require( '@stdlib/constants/float64/pinf' ); +var NINF = require( '@stdlib/constants/float64/ninf' ); +var HALF_PI = require( '@stdlib/constants/float64/half-pi' ); +var EPS = require( '@stdlib/constants/float64/eps' ); +var abs = require( '@stdlib/math/base/special/abs' ); +var tryRequire = require( '@stdlib/utils/try-require' ); + + +// FIXTURES // + +var mediumPositive = require( './fixtures/cpp/medium_positive.json' ); +var closeToUnity = require( './fixtures/cpp/close_to_unity.json' ); +var negativeSpotChecks = require( './fixtures/wolframalpha/negative_spot_checks.json' ); + + +// VARIABLES // + +var ellipe = tryRequire( resolve( __dirname, './../lib/native.js' ) ); +var opts = { + 'skip': ( ellipe instanceof Error ) +}; + + +// TESTS // + +tape( 'main export is a function', opts, function test( t ) { + t.ok( true, __filename ); + t.strictEqual( typeof ellipe, 'function', 'main export is a function' ); + t.end(); +}); + +tape( 'the function evaluates the complete elliptic integral of the second kind (values close to positive unity)', opts, function test( t ) { + var expected; + var delta; + var tol; + var x; + var y; + var i; + + expected = closeToUnity.expected; + x = closeToUnity.x; + for ( i = 0; i < x.length; i++ ) { + y = ellipe( x[i] ); + if ( y === expected[i] ) { + t.equal( y, expected[i], 'x: '+x[i]+', y: '+y+', expected: '+expected[i] ); + } else { + delta = abs( y - expected[i] ); + tol = 4.0 * EPS * abs( expected[i] ); + t.equal( delta <= tol, true, 'within tolerance. x: '+x[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); + } + } + t.end(); +}); + +tape( 'the function evaluates the complete elliptic integral of the second kind (medium positive values)', opts, function test( t ) { + var expected; + var delta; + var tol; + var x; + var y; + var i; + + expected = mediumPositive.expected; + x = mediumPositive.x; + for ( i = 0; i < x.length; i++ ) { + y = ellipe( x[i] ); + if ( y === expected[i] ) { + t.equal( y, expected[i], 'x: '+x[i]+', y: '+y+', expected: '+expected[i] ); + } else { + delta = abs( y - expected[i] ); + tol = 5.0 * EPS * abs( expected[i] ); + t.equal( delta <= tol, true, 'within tolerance. x: '+x[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); + } + } + t.end(); +}); + +tape( 'the function evaluates the complete elliptic integral of the second kind (spot checked negative values)', opts, function test( t ) { + var expected; + var delta; + var tol; + var x; + var y; + var i; + + // The spot checked values are derived from Wolfram Alpha and cross-checked against Maxima. For example, to compute E(-0.1): https://www.wolframalpha.com/input/?i=EllipticE(-0.1) + expected = negativeSpotChecks.expected; + x = negativeSpotChecks.x; + for ( i = 0; i < x.length; i++ ) { + y = ellipe( x[i] ); + if ( y === expected[i] ) { + t.equal( y, expected[i], 'x: '+x[i]+', y: '+y+', expected: '+expected[i] ); + } else { + delta = abs( y - expected[i] ); + tol = 2.2 * EPS * abs( expected[i] ); + t.equal( delta <= tol, true, 'within tolerance. x: '+x[i]+'. y: '+y+'. E: '+expected[i]+'. Δ: '+delta+'. tol: '+tol+'.' ); + } + } + t.end(); +}); + +tape( 'the function returns `NaN` if provided values larger than `1.0`', opts, function test( t ) { + var v = ellipe( 1.01 ); + t.equal( isnan( v ), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `1.0` if provided `1.0`', opts, function test( t ) { + var v = ellipe( 1.0 ); + t.equal( v, 1.0, 'return expected value' ); + t.end(); +}); + +tape( 'the function returns `NaN` if provided `+infinity`', opts, function test( t ) { + var v = ellipe( PINF ); + t.equal( isnan( v ), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `NaN` if provided `-infinity`', opts, function test( t ) { + var v = ellipe( NINF ); + t.equal( isnan( v ), true, 'returns expected value' ); + t.end(); +}); + +tape( 'the function returns `π/2` if provided `0`', opts, function test( t ) { + var v = ellipe( 0 ); + t.equal( v, HALF_PI, 'returns expected value' ); + t.end(); +});