// Copyright 2011 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/numbers/ieee754.h"

#include <cmath>

#include "src/base/ieee754.h"
#include "src/flags/flags.h"

namespace v8::internal::math {

double pow(double x, double y) {
  if (v8_flags.use_std_math_pow) {
    if (std::isnan(y)) {
      // 1. If exponent is NaN, return NaN.
      return std::numeric_limits<double>::quiet_NaN();
    }
    if (std::isinf(y) && (x == 1 || x == -1)) {
      // 9. If exponent is +∞𝔽, then
      //   b. If abs(ℝ(base)) = 1, return NaN.
      // and
      // 10. If exponent is -∞𝔽, then
      //   b. If abs(ℝ(base)) = 1, return NaN.
      return std::numeric_limits<double>::quiet_NaN();
    }
    if (std::isnan(x)) {
      // std::pow distinguishes between quiet and signaling NaN; JS doesn't.
      x = std::numeric_limits<double>::quiet_NaN();
    }

    // The following special cases just exist to match the optimizing compilers'
    // behavior, which avoid calls to `pow` in those cases.
    if (y == 2) {
      // x ** 2   ==>   x * x
      return x * x;
    } else if (y == 0.5) {
      // x ** 0.5   ==>  sqrt(x), except if x is -Infinity
      if (std::isinf(x)) {
        return std::numeric_limits<double>::infinity();
      } else {
        // Note the +0 so that we get +0 for -0**0.5 rather than -0.
        return std::sqrt(x + 0);
      }
    }

    return std::pow(x, y);
  }
  return base::ieee754::legacy::pow(x, y);
}

}  // namespace v8::internal::math