docs: public static double angleSparse(SparseNumberVector v1, SparseNumberVector v2) {
      // TODO: exploit precomputed length, when available?
      double l1 = 0., l2 = 0., cross = 0.;
      int i1 = v1.iter(), i2 = v2.iter();
      while(v1.iterValid(i1) && v2.iterValid(i2)) {
        final int d1 = v1.iterDim(i1), d2 = v2.iterDim(i2);
        if(d1 < d2) {
          final double val = v1.iterDoubleValue(i1);
          l1 += val * val;
          i1 = v1.iterAdvance(i1);
        }
        else if(d2 < d1) {
          final double val = v2.iterDoubleValue(i2);
          l2 += val * val;
          i2 = v2.iterAdvance(i2);
        }
        else { // d1 == d2
          final double val1 = v1.iterDoubleValue(i1);
          final double val2 = v2.iterDoubleValue(i2);
          l1 += val1 * val1;
          l2 += val2 * val2;
          cross += val1 * val2;
          i1 = v1.iterAdvance(i1);
          i2 = v2.iterAdvance(i2);
        }
      }
      while(v1.iterValid(i1)) {
        final double val = v1.iterDoubleValue(i1);
        l1 += val * val;
        i1 = v1.iterAdvance(i1);
      }
      while(v2.iterValid(i2)) {
        final double val = v2.iterDoubleValue(i2);
        l2 += val * val;
        i2 = v2.iterAdvance(i2);
      }
      final double a = (cross == 0.) ? 0. : //
          (l1 == 0. || l2 == 0.) ? 1. : //
              FastMath.sqrt((cross / l1) * (cross / l2));
      return (a < 1.) ? a : 1.;
    }