Interval
 acos(Interval interval) {
     if (interval.isEmpty() || interval.lowerBound() > 1.0 || interval.upperBound() < -1.0) {
         return Interval::EMPTY();
     } else {
         return Interval(
             acos(min(interval.upperBound(), 1.0)),
             acos(max(interval.lowerBound(), -1.0))
         );
     }
 }
 Interval
 log(Interval interval) {
     if (interval.isEmpty() || interval.upperBound() < 0.0) {
         return Interval::EMPTY();
     } else if (interval.lowerBound() > 0.0) {
         return Interval(log(interval.lowerBound()), log(interval.upperBound()));
     } else if (interval.upperBound() > 0.0) {
         return Interval(-std::numeric_limits<double>::infinity(), log(interval.upperBound()));
     } else {
         return -std::numeric_limits<double>::infinity();
     }
 }
 Interval
 atan2(Interval yInterval, Interval xInterval) {
     if (yInterval.isEmpty() || xInterval.isEmpty()) {
         return Interval::EMPTY();
     } else if (xInterval.lowerBound() > 0.0) {
         return atan(yInterval / xInterval);
     } else if (yInterval.lowerBound() > 0.0) {
         return atan(-xInterval / yInterval) + M_PI / 2;
     } else if (yInterval.upperBound() < 0.0) {
         return atan(-xInterval / yInterval) - M_PI / 2;
     } else {
         return Interval(-M_PI, M_PI);
     }
 }
 Interval
 exp(Interval interval) {
     if (interval.isEmpty()) {
         return Interval::EMPTY();
     } else {
         return Interval(exp(interval.lowerBound()), exp(interval.upperBound()));
     }
 }
 Interval
 tan(Interval interval) {
     Interval absolute = abs(interval);
     bool hasSingularity = std::fmod(absolute.upperBound() + M_PI / 2, M_PI) <= absolute.width();
     if (hasSingularity) {
         return Interval::WHOLE();
     } else {
         return Interval(std::tan(interval.lowerBound()), std::tan(interval.upperBound()));
     }
 }
 Interval
 cos(Interval interval) { 
     Interval absolute = abs(interval);
     double width = absolute.width();
     bool hasMin = std::fmod(absolute.upperBound() + M_PI, 2 * M_PI) <= width;
     bool hasMax = std::fmod(absolute.upperBound(), 2 * M_PI) <= width;
     if (hasMin && hasMax) {
         return Interval(-1.0, 1.0);
     } else {
         double cosLower = std::cos(absolute.lowerBound());
         double cosUpper = std::cos(absolute.upperBound());
         auto sorted = std::minmax(cosLower, cosUpper);
         return Interval(hasMin ? -1.0 : sorted.first, hasMax ? 1.0 : sorted.second);
     }
 }
 Interval
 atan(Interval interval) {
     return Interval(atan(interval.lowerBound()), atan(interval.upperBound()));
 }