Ancient
view release on metacpan or search on metacpan
t/7027-nvec-arithmetic-edge.t view on Meta::CPAN
my $is_quad = is_quadmath();
if ($is_quad) {
diag("Testing with quadmath (128-bit precision)");
} else {
diag("Testing with standard double precision (64-bit)");
}
my $tol = get_tolerance();
# Helper for special values
my $nan = 9**9**9 - 9**9**9;
my $inf = 9**9**9;
my $ninf = -9**9**9;
# ============================================
# Addition edge cases
# ============================================
subtest 'add: vector + vector' => sub {
my $a = nvec::new([1, 2, 3]);
my $b = nvec::new([4, 5, 6]);
my $c = $a->add($b);
is_deeply($c->to_array, [5, 7, 9], 'basic vector addition');
};
subtest 'add: vector + scalar' => sub {
my $v = nvec::new([1, 2, 3]);
my $c = $v->add_scalar(10);
is_deeply($c->to_array, [11, 12, 13], 'vector + scalar');
};
subtest 'add: with zeros' => sub {
my $a = nvec::new([1, 2, 3]);
my $zeros = nvec::zeros(3);
my $c = $a->add($zeros);
ok(vec_approx_eq($a, $c), 'v + 0 = v');
};
subtest 'add: with negative values' => sub {
my $a = nvec::new([1, -2, 3, -4]);
my $b = nvec::new([-1, 2, -3, 4]);
my $c = $a->add($b);
my $expected = nvec::zeros(4);
ok(vec_approx_eq($c, $expected), 'v + (-v) = 0');
};
subtest 'add: infinity handling' => sub {
my $v = nvec::new([1, 2, 3]);
my $c = $v->add_scalar($inf);
my @vals = @{$c->to_array};
ok($c->isinf->get(0), 'finite + inf = inf');
ok($c->isinf->get(1), 'finite + inf = inf');
ok($c->isinf->get(2), 'finite + inf = inf');
};
subtest 'add: inf + (-inf) = NaN' => sub {
my $a = nvec::new([$inf]);
my $b = nvec::new([$ninf]);
my $c = $a->add($b);
ok($c->isnan->get(0), 'inf + (-inf) = NaN');
};
# ============================================
# Subtraction edge cases
# ============================================
subtest 'sub: vector - vector' => sub {
my $a = nvec::new([5, 7, 9]);
my $b = nvec::new([1, 2, 3]);
my $c = $a->sub($b);
is_deeply($c->to_array, [4, 5, 6], 'basic vector subtraction');
};
subtest 'sub: vector - scalar' => sub {
my $v = nvec::new([10, 20, 30]);
# No sub_scalar method - use add_scalar with negative value
my $c = $v->add_scalar(-5);
is_deeply($c->to_array, [5, 15, 25], 'vector - scalar');
};
subtest 'sub: v - v = 0' => sub {
my $v = nvec::new([1.5, 2.5, 3.5]);
my $c = $v->sub($v);
my $zeros = nvec::zeros(3);
ok(vec_approx_eq($c, $zeros), 'v - v = 0');
};
subtest 'sub: inf - inf = NaN' => sub {
my $a = nvec::new([$inf]);
my $c = $a->sub($a);
ok($c->isnan->get(0), 'inf - inf = NaN');
};
# ============================================
# Multiplication edge cases
# ============================================
subtest 'mul: vector * vector' => sub {
my $a = nvec::new([2, 3, 4]);
my $b = nvec::new([5, 6, 7]);
my $c = $a->mul($b);
is_deeply($c->to_array, [10, 18, 28], 'element-wise multiplication');
};
subtest 'mul: vector * scalar' => sub {
my $v = nvec::new([1, 2, 3]);
my $c = $v->scale(2);
is_deeply($c->to_array, [2, 4, 6], 'vector * scalar');
};
subtest 'mul: with zeros' => sub {
my $v = nvec::new([1, 2, 3]);
my $zeros = nvec::zeros(3);
my $c = $v->mul($zeros);
ok(vec_approx_eq($c, $zeros), 'v * 0 = 0');
};
subtest 'mul: with ones' => sub {
my $v = nvec::new([1, 2, 3]);
my $ones = nvec::ones(3);
my $c = $v->mul($ones);
ok(vec_approx_eq($c, $v), 'v * 1 = v');
};
subtest 'mul: 0 * inf = NaN' => sub {
my $a = nvec::new([0]);
my $b = nvec::new([$inf]);
my $c = $a->mul($b);
ok($c->isnan->get(0), '0 * inf = NaN');
};
subtest 'mul: negative * negative = positive' => sub {
my $a = nvec::new([-2, -3, -4]);
my $b = nvec::new([-5, -6, -7]);
my $c = $a->mul($b);
my @vals = @{$c->to_array};
ok($vals[0] > 0, 'negative * negative > 0');
ok($vals[1] > 0, 'negative * negative > 0');
ok($vals[2] > 0, 'negative * negative > 0');
};
# ============================================
# Division edge cases
# ============================================
subtest 'div: vector / vector' => sub {
my $a = nvec::new([10, 18, 28]);
my $b = nvec::new([2, 3, 4]);
my $c = $a->div($b);
is_deeply($c->to_array, [5, 6, 7], 'element-wise division');
};
subtest 'div: vector / scalar' => sub {
my $v = nvec::new([10, 20, 30]);
my $c = $v->scale(0.5);
is_deeply($c->to_array, [5, 10, 15], 'vector / 2 via scale(0.5)');
};
subtest 'div: by one' => sub {
my $v = nvec::new([1, 2, 3]);
my $ones = nvec::ones(3);
my $c = $v->div($ones);
ok(vec_approx_eq($c, $v), 'v / 1 = v');
};
subtest 'div: by zero produces infinity' => sub {
my $a = nvec::new([1, -1, 0]);
my $b = nvec::new([0, 0, 0]);
my $c = $a->div($b);
ok($c->isinf->get(0), '1/0 = inf');
ok($c->isinf->get(1), '-1/0 = -inf');
ok($c->isnan->get(2), '0/0 = NaN');
};
subtest 'div: inf / inf = NaN' => sub {
my $a = nvec::new([$inf]);
my $b = nvec::new([$inf]);
my $c = $a->div($b);
ok($c->isnan->get(0), 'inf / inf = NaN');
};
subtest 'div: finite / inf = 0' => sub {
my $a = nvec::new([1, 100, -50]);
my $b = nvec::new([$inf, $inf, $inf]);
my $c = $a->div($b);
my @vals = @{$c->to_array};
ok(approx_eq($vals[0], 0, $tol), 'finite / inf = 0');
ok(approx_eq($vals[1], 0, $tol), 'finite / inf = 0');
ok(approx_eq($vals[2], 0, $tol), 'finite / inf = 0');
};
# ============================================
# Power edge cases
# ============================================
subtest 'pow: basic powers' => sub {
my $v = nvec::new([2, 3, 4]);
my $sq = $v->pow(2);
is_deeply($sq->to_array, [4, 9, 16], 'squared');
my $cb = $v->pow(3);
is_deeply($cb->to_array, [8, 27, 64], 'cubed');
};
subtest 'pow: power of 0' => sub {
my $v = nvec::new([1, 2, 3, 0, -1]);
my $c = $v->pow(0);
# x^0 = 1 for all x (including 0^0 = 1 by convention)
my $ones = nvec::ones(5);
ok(vec_approx_eq($c, $ones), 'x^0 = 1');
};
subtest 'pow: power of 1' => sub {
my $v = nvec::new([1, 2, 3, -4]);
my $c = $v->pow(1);
ok(vec_approx_eq($c, $v), 'x^1 = x');
};
subtest 'pow: negative base with integer exponent' => sub {
my $v = nvec::new([-2, -2, -2]);
my $c = $v->pow(2); # (-2)^2 = 4
my @vals = @{$c->to_array};
is($vals[0], 4, '(-2)^2 = 4');
};
subtest 'pow: fractional exponent (sqrt)' => sub {
my $v = nvec::new([4, 9, 16, 25]);
my $c = $v->pow(0.5);
my @vals = @{$c->to_array};
ok(approx_eq($vals[0], 2, $tol), '4^0.5 = 2');
ok(approx_eq($vals[1], 3, $tol), '9^0.5 = 3');
ok(approx_eq($vals[2], 4, $tol), '16^0.5 = 4');
ok(approx_eq($vals[3], 5, $tol), '25^0.5 = 5');
( run in 0.538 second using v1.01-cache-2.11-cpan-df04353d9ac )