Making diagonal and permutation matrices special matrix objects in their own right and the consequent usage of smarter algorithms for certain operations implies, as a side effect, small differences in treating zeros. The contents of this section applies also to sparse matrices, discussed in the following chapter.
The IEEE standard defines the result of the expressions
NaN, as it has been generally agreed that this is the
Numerical software dealing with structured and sparse matrices (including
Octave) however, almost always makes a distinction between a "numerical zero"
and an "assumed zero".
A "numerical zero" is a zero value occurring in a place where any floating-point
value could occur. It is normally stored somewhere in memory as an explicit
An "assumed zero", on the contrary, is a zero matrix element implied by the
matrix structure (diagonal, triangular) or a sparsity pattern; its value is
usually not stored explicitly anywhere, but is implied by the underlying
The primary distinction is that an assumed zero, when multiplied
by any number, or divided by any nonzero number,
yields *always* a zero, even when, e.g., multiplied by
or divided by
The reason for this behavior is that the numerical multiplication is not
actually performed anywhere by the underlying algorithm; the result is
just assumed to be zero. Equivalently, one can say that the part of the
computation involving assumed zeros is performed symbolically, not numerically.
This behavior not only facilitates the most straightforward and efficient implementation of algorithms, but also preserves certain useful invariants, like:
Note that matlab does not strictly follow this principle and converts assumed zeros to numerical zeros in certain cases, while not doing so in other cases. As of today, there are no intentions to mimic such behavior in Octave.
Examples of effects of assumed zeros vs. numerical zeros:
Inf * eye (3) ⇒ Inf 0 0 0 Inf 0 0 0 Inf Inf * speye (3) ⇒ Compressed Column Sparse (rows = 3, cols = 3, nnz = 3 [33%]) (1, 1) -> Inf (2, 2) -> Inf (3, 3) -> Inf Inf * full (eye (3)) ⇒ Inf NaN NaN NaN Inf NaN NaN NaN Inf
diag(1:3) * [NaN; 1; 1] ⇒ NaN 2 3 sparse(1:3,1:3,1:3) * [NaN; 1; 1] ⇒ NaN 2 3 [1,0,0;0,2,0;0,0,3] * [NaN; 1; 1] ⇒ NaN NaN NaN