public static Quaternion cosh(Quaternion q) {
   Double3Vector imag = q.imag();
   final double imagNorm = imag.norm();
   return new Quaternion(
       ExtraMath.cosh(q.re) * Math.cos(imagNorm),
       (Double3Vector) imag.normalize().scalarMultiply(ExtraMath.sinh(q.re) * Math.sin(imagNorm)));
 }
 public static Quaternion exp(Quaternion q) {
   final double k = Math.exp(q.re);
   Double3Vector imag = q.imag();
   final double imagNorm = imag.norm();
   return new Quaternion(
       k * Math.cos(imagNorm),
       (Double3Vector) imag.normalize().scalarMultiply(k * Math.sin(imagNorm)));
 }
 /**
  * Returns the division of this quaternion by another.
  *
  * @param q a quaternion
  * @exception ArithmeticException If divide by zero.
  */
 public Quaternion divide(final Quaternion q) {
   final double qSumSqr = q.sumSquares();
   return new Quaternion(
       (re * q.re + imi * q.imi + imj * q.imj + imk * q.imk) / qSumSqr,
       (q.re * imi - re * q.imi - (imj * q.imk - q.imj * imk)) / qSumSqr,
       (q.re * imj - re * q.imj - (imk * q.imi - q.imk * imi)) / qSumSqr,
       (q.re * imk - re * q.imk - (imi * q.imj - q.imi * imj)) / qSumSqr);
 }
 public static Quaternion log(Quaternion q) {
   final double norm = q.norm();
   return new Quaternion(
       Math.log(norm),
       (Double3Vector) q.imag().normalize().scalarMultiply(Math.acos(q.re / norm)));
 }