stdlib icon indicating copy to clipboard operation
stdlib copied to clipboard

feat: add `math/base/special/cinvf`

Open aayush0325 opened this issue 1 year ago • 21 comments

Resolves a part of #649

Description

What is the purpose of this pull request?

This pull request:

  • resolves part of #649

Related Issues

Does this pull request have any related issues?

This pull request:

  • resolves a part of #649

Questions

Any questions for reviewers of this pull request?

No.

Other

Any other information relevant to this pull request? This may include screenshots, references, and/or implementation notes.

Need help with overflow case.

Checklist

Please ensure the following tasks are completed before submitting this pull request.


@stdlib-js/reviewers

aayush0325 avatar Nov 12 '24 08:11 aayush0325

tape( 'the function may overflow', function test( t ) {
	var v;

	v = cinvf( new Complex64( 5.0e-324, 5.0e-324 ) );
	t.strictEqual( real( v ), PINF, 'real component is +infinity' );
	t.strictEqual( imag( v ), NINF, 'imaginary component is -infinity' );

	v = cinvf( new Complex64( -5.0e-324, 5.0e-324 ) );
	t.strictEqual( real( v ), NINF, 'real component is -infinity' );
	t.strictEqual( imag( v ), NINF, 'imaginary component is -infinity' );

	v = cinvf( new Complex64( -5.0e-324, -5.0e-324 ) );
	t.strictEqual( real( v ), NINF, 'real component is -infinity' );
	t.strictEqual( imag( v ), PINF, 'imaginary component is +infinity' );

	v = cinvf( new Complex64( 5.0e-324, -5.0e-324 ) );
	t.strictEqual( real( v ), PINF, 'real component is +infinity' );
	t.strictEqual( imag( v ), PINF, 'imaginary component is +infinity' );

	v = cinvf( new Complex64( 0.0, 5.0e-324 ) );
	t.strictEqual( real( v ), 0.0, 'real component is 0' );
	t.strictEqual( imag( v ), NINF, 'imaginary component is -infinity' );

	v = cinvf( new Complex64( 0.0, -5.0e-324 ) );
	t.strictEqual( real( v ), 0.0, 'real component is 0' );
	t.strictEqual( imag( v ), PINF, 'imaginary component is +infinity' );

	v = cinvf( new Complex64( 5.0e-324, 0.0 ) );
	t.strictEqual( real( v ), PINF, 'real component is +infinity' );
	t.strictEqual( imag( v ), 0.0, 'imaginary component is 0' );

	v = cinvf( new Complex64( -5.0e-324, 0.0 ) );
	t.strictEqual( real( v ), NINF, 'real component is -infinity' );
	t.strictEqual( imag( v ), 0.0, 'imaginary component is 0' );

	t.end();
});

Good Afternoon, @gunjjoshi can you please help me out in adding the overflow testcase in test.js and test.native.js as it is not there in this PR right now, i tried various values for this but the complex number real( v ) imag( v ) turns out to be NaN NaN and not Infinity or -Infinity as expected. how did you arrive at the number 5.0e-324?

aayush0325 avatar Nov 12 '24 09:11 aayush0325

@aayush0325 Tried the following test on your branch, and it works:

tape( 'the function may produce very large values for very small inputs', function test( t ) {
    var v;

    v = cinvf( new Complex64( FLOAT32_SMALLEST_NORMAL, FLOAT32_SMALLEST_NORMAL ) );
    t.ok( real( v ) > 1e37, 'real component is very large' );
    t.ok( imag( v ) < -1e37, 'imaginary component is very large and negative' );

    v = cinvf( new Complex64( -FLOAT32_SMALLEST_NORMAL, FLOAT32_SMALLEST_NORMAL ) );
    t.ok( real( v ) < -1e37, 'real component is very large and negative' );
    t.ok( imag( v ) < -1e37, 'imaginary component is very large and negative' );

    v = cinvf( new Complex64( -FLOAT32_SMALLEST_NORMAL, -FLOAT32_SMALLEST_NORMAL ) );
    t.ok( real( v ) < -1e37, 'real component is very large and negative' );
    t.ok( imag( v ) > 1e37, 'imaginary component is very large and positive' );

    v = cinvf( new Complex64( FLOAT32_SMALLEST_NORMAL, -FLOAT32_SMALLEST_NORMAL ) );
    t.ok( real( v ) > 1e37, 'real component is very large and positive' );
    t.ok( imag( v ) > 1e37, 'imaginary component is very large and positive' );

    v = cinvf( new Complex64( 0.0, FLOAT32_SMALLEST_NORMAL ) );
    t.strictEqual( real( v ), 0.0, 'real component is 0' );
    t.ok( imag( v ) < -1e37, 'imaginary component is very large and negative' );

    v = cinvf( new Complex64( 0.0, -FLOAT32_SMALLEST_NORMAL ) );
    t.strictEqual( real( v ), 0.0, 'real component is 0' );
    t.ok( imag( v ) > 1e37, 'imaginary component is very large and positive' );

    v = cinvf( new Complex64( FLOAT32_SMALLEST_NORMAL, 0.0 ) );
    t.ok( real( v ) > 1e37, 'real component is very large and positive' );
    t.strictEqual( imag( v ), 0.0, 'imaginary component is 0' );

    v = cinvf( new Complex64( -FLOAT32_SMALLEST_NORMAL, 0.0 ) );
    t.ok( real( v ) < -1e37, 'real component is very large and negative' );
    t.strictEqual( imag( v ), 0.0, 'imaginary component is 0' );

    t.end();
});

You can try this. I think there might be a loss of precision as we are handling single-precision floating-point numbers and as we are not explicitly returning PINF or NINF in our implementation, so, we are not comparing with exactly PINF and NINF here.

gunjjoshi avatar Nov 12 '24 14:11 gunjjoshi

You can declare separate variables for tiny and huge, such as:

var tiny = -1e37;
var huge = 1e37;

and then use them in the tests.

gunjjoshi avatar Nov 12 '24 14:11 gunjjoshi

thanks @gunjjoshi! i'll push these changes soon, anything else to add? i'll make all the changes together then.

aayush0325 avatar Nov 12 '24 14:11 aayush0325

thanks @gunjjoshi! i'll push these changes soon, anything else to add? i'll make all the changes together then.

Nothing for now, once you've added these tests in both test.js and test.native.js, we can review it.

gunjjoshi avatar Nov 12 '24 14:11 gunjjoshi

updated the tests, kindly review @gunjjoshi.

aayush0325 avatar Nov 12 '24 15:11 aayush0325

@gunjjoshi even after using stdlib_base_maxf from math/base/special/maxf the tests are failing for C files. i think we should try to write runner.jl to have more accurate data for single-precision floating-point numbers and then see if the same tolerance is working. how should i proceed with this?

aayush0325 avatar Nov 13 '24 18:11 aayush0325

@aayush0325 As mentioned above, you should make sure that the fixtures generated fall within the range of single-precision floating-point numbers. For example, compare the range of fixtures in math/base/special/ln, with that in its single-precision equivalent, i.e., math/base/special/lnf. Notice that we scale down from ~308 to ~38, when we go from double to single-precision. Something similar needs to be followed here as well.

gunjjoshi avatar Nov 13 '24 19:11 gunjjoshi

I have updated the tests with new tolerances and matching data, is this alright @gunjjoshi ?

aayush0325 avatar Nov 14 '24 08:11 aayush0325

Coverage Report

Package Statements Branches Functions Lines
math/base/special/cinvf $\color{green}213/213$
$\color{green}+100.00\%$
$\color{green}10/10$
$\color{green}+100.00\%$
$\color{green}2/2$
$\color{green}+100.00\%$
$\color{green}213/213$
$\color{green}+100.00\%$

The above coverage report was generated for the changes in this PR.

stdlib-bot avatar Nov 17 '24 02:11 stdlib-bot

I've updated the benchmarks with the pre-computation as requested, not sure as to why the tests are failing.

aayush0325 avatar Nov 17 '24 02:11 aayush0325

The failing tests might be originating from https://github.com/stdlib-js/stdlib/blob/1b6e72293a7bb85803ce5f66ae705f9476fc7cb0/.github/workflows/run_tests_coverage.yml#L213 as we're not declaring botComment, if it is a bot comment.

cc: @Planeshifter

gunjjoshi avatar Nov 17 '24 03:11 gunjjoshi

I see, anything else I can do in this PR @gunjjoshi?

aayush0325 avatar Nov 17 '24 04:11 aayush0325

The tests seem to be running fine locally for both test.js and test.native.js, not sure why there's an error here.

aayush0325 avatar Nov 18 '24 02:11 aayush0325

/stdlib merge

kgryte avatar Nov 18 '24 04:11 kgryte

not sure why there's an error here

Test coverage build errors should be resolved now, given recent fixes by @Planeshifter to our CI.

kgryte avatar Nov 18 '24 04:11 kgryte

/stdlib merge

aayush0325 avatar Nov 28 '24 04:11 aayush0325

@gunjjoshi kindly give this a review!

aayush0325 avatar Dec 07 '24 19:12 aayush0325

good morning, i've added a test with hardcoded values where magnitude of the real and imaginary component exceeds LARGE_THRESHOLD so that the code reaches the mentioned block, i have taken these values from the numpy implementation using the following code:

import numpy as np

# Function to compute the inverse of a complex number using single-precision floating-point numbers
def compute_inverse_single_precision(real, imag):
    complex_number = np.complex64(real + imag * 1j)
    inverse = 1 / complex_number
    return inverse

# Given complex numbers
complex_numbers = [
    (2e+38, 200),
    (-2e+38, 200),
    (200, 2e+38),
    (200, -2e+38)
]

# Compute inverses
for real, imag in complex_numbers:
    inverse = compute_inverse_single_precision(real, imag)
    print(f"The inverse of {real} + {imag}I is {inverse}")

which gave me the output:

The inverse of 2e+38 + 200I is (4.999999675228202e-39-0j)
The inverse of -2e+38 + 200I is (-4.999999675228202e-39-0j)
The inverse of 200 + 2e+38I is -4.999999675228202e-39j
The inverse of 200 + -2e+38I is 4.999999675228202e-39j

if there's anything else that i should do then please let me know!

aayush0325 avatar Dec 11 '24 08:12 aayush0325

hey is this implementation complete, I was trying to do this one as I did not find it in the source code?

AadishJ avatar Jan 11 '25 07:01 AadishJ

Sorry @kgryte and @aayush0325, I moved on to create a fresh PR for this: https://github.com/stdlib-js/stdlib/pull/7007. I thought that would be more appropriate here.

anandkaranubc avatar Jun 01 '25 15:06 anandkaranubc

Thank you for working on this pull request. However, we cannot accept your contribution as the issue this pull request seeks to resolve has already been addressed in a different pull request or commit.

Thank you again for your interest in stdlib, and we look forward to reviewing your future contributions.

stdlib-bot avatar Aug 12 '25 07:08 stdlib-bot