//===-- flang/unittests/RuntimeGTest/Random.cpp -----------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "../../runtime/random.h"
#include "gtest/gtest.h"
#include "../../runtime/descriptor.h"
#include "../../runtime/type-code.h"
#include <cmath>

using namespace Fortran::runtime;

TEST(RandomNumber, Real4) {
  StaticDescriptor<1> statDesc;
  Descriptor &harvest{statDesc.descriptor()};
  static constexpr int n{10000};
  float xs[n]{};
  SubscriptValue extent[1]{n};
  harvest.Establish(TypeCategory::Real, 4, xs, 1, extent);
  RTNAME(RandomNumber)(harvest, __FILE__, __LINE__);
  double sum{0};
  for (int j{0}; j < n; ++j) {
    sum += xs[j];
  }
  double mean{sum / n};
  std::fprintf(stderr, "mean of %d random numbers: %g\n", n, mean);
  EXPECT_GE(mean, 0.95 * 0.5); // mean of uniform dist [0..1] is of course 0.5
  EXPECT_LE(mean, 1.05 * 0.5);
  double sumsq{0};
  for (int j{0}; j < n; ++j) {
    double diff{xs[j] - mean};
    sumsq += diff * diff;
  }
  double sdev{std::sqrt(sumsq / n)};
  std::fprintf(stderr, "stddev of %d random numbers: %g\n", n, sdev);
  double expect{1.0 / std::sqrt(12.0)}; // stddev of uniform dist [0..1]
  EXPECT_GE(sdev, 0.95 * expect);
  EXPECT_LT(sdev, 1.05 * expect);
}

TEST(RandomNumber, RandomSeed) {
  StaticDescriptor<1> statDesc[2];
  Descriptor &desc{statDesc[0].descriptor()};
  std::int32_t n;
  desc.Establish(TypeCategory::Integer, 4, &n, 0, nullptr);
  RTNAME(RandomSeedSize)(desc, __FILE__, __LINE__);
  EXPECT_EQ(n, 1);
  SubscriptValue extent[1]{1};
  desc.Establish(TypeCategory::Integer, 4, &n, 1, extent);
  RTNAME(RandomSeedGet)(desc, __FILE__, __LINE__);
  Descriptor &harvest{statDesc[1].descriptor()};
  float x;
  harvest.Establish(TypeCategory::Real, 4, &x, 1, extent);
  RTNAME(RandomNumber)(harvest, __FILE__, __LINE__);
  float got{x};
  RTNAME(RandomSeedPut)(desc, __FILE__, __LINE__); // n from RandomSeedGet()
  RTNAME(RandomNumber)(harvest, __FILE__, __LINE__);
  EXPECT_EQ(x, got);
}
