// File: /workspace/github_cpp_makefile_star2_O2/millanek[P]Dsuite/kstest.cpp
// Function: ks_test(std::__cxx11::list<long, std::allocator<long>>, std::__cxx11::list<long, std::allocator<long>>, std::ostream&, bool)
double ks_test (std::list<int64_t> sample1, std::list<int64_t> sample2,
        std::ostream& outfile, bool printDebug) {

  unsigned int n1, n2, n_approx;
    // sample sizes
  float d;
    // the value of Kolmogorov's statistic
    // for the particular values of sample1 and sample2
  int D, Dmin, Dmax, s;
    // used in computing this value d

  std::list<int64_t>::iterator it1, it2;

  // Determine sample sizes
  n1 = sample1.size();
  n2 = sample2.size();

  // Calculate a conservative n approximation
  n_approx = (unsigned) ceil(float(n1*n2)/(n1+n2));
  if (printDebug) outfile << "n_approx=" << n_approx << std::endl;

  // Sort samples
  sample1.sort(); //outfile << "sorted sample1: " << sample1 << std::endl;
  sample2.sort(); //outfile << "sorted sample2: " << sample2 << std::endl;

  // We divide the range 0..1 into n1*n2 intervals of equal size 1/(n1*n2).
  //
  // Each item in sample1 makes the sample c.d.f of sample1
  // jump by a step of n2 intervals.
  // Each item in sample2 makes the sample c.d.f of sample2
  // jump by a step of n1 intervals.
  //
  // For each item we compute D, related to the distance between the two
  // sample c.d.f., s_cdf_1 - s_cdf_2, by:
  //
  //    D/(n1*n2) = s_cdf_1 - s_cdf_2
  //
  // We want to determine:
  //
  //    Dmin/(n1*n2) = min [s_cdf_1 - s_cdf_2] <= 0
  //    Dmax/(n1*n2) = max [s_cdf_1 - s_cdf_2] >= 0
  //
  // And then the value of Kolmorogov's statistic D_n1n2 is just:
  //
  //    D_n1n2 = sup |s_cdf_1 - s_cdf_2|
  //           = max [ |Dmin/(n1*n2)| ; |Dmax/(n1*n2)| ]

  D = 0; Dmin = 0; Dmax = 0;
  it1 = sample1.begin();
  it2 = sample2.begin();

  while ( (it1 != sample1.end()) && (it2 != sample2.end()) ) {

    if (*it1 == *it2) {

        if (printDebug) outfile << *it1 << " tie!";
      // steps in both sample c.d.f., we need to perform all steps
      // in this point before comparing D to Dmin and Dmax

      s = *it1;
      // perform all steps in s_cdf_1 first
      do {
    D += n2;
    it1++;
      }
      while ( (*it1 == s) && (it1 != sample1.end()) );
      // perform all steps in s_cdf_2 now
      do {
    D -= n1;
    it2++;
      }
      while ( (*it2 == s) && (it2 != sample2.end()) );

      // now adapt Dmin, Dmax if necessary
      if (D > Dmax)
    Dmax = D;
      else if (D < Dmin)
    Dmin = D;

    }

    else if (*it1 < *it2) {

    if (printDebug) outfile << *it1;
      // step in s_cdf_1, increase D by n2
      D += n2;
      it1++;

      if (D > Dmax)
    Dmax = D;

    }

    else {

      if (printDebug) outfile << *it2;
      // step in F2, decrease D by n1
      D -= n1;
      it2++;

      if (D < Dmin)
    Dmin = D;

    }

      if (printDebug) outfile << " D=" << D << " Dmin=" << Dmin << " Dmax=" << Dmax << std::endl;

  }

  // For two-sided test, take D = max (|Dmax|, |Dmin|) and compute
  // the value d of Kolmogorov's statistic (two-sided only)

  if (-Dmin > Dmax)
    D = -Dmin;
  else
    D = Dmax;

  // Hence the observed value of Kolmogorov's statistic:
  d = float(D)/(n1*n2);

  // Return p-value
  return 1 - K(n_approx,d);

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rsi, %rbx
movq %rdi, %r14
movl 0x10(%rdi), %esi
movl 0x10(%rbx), %r12d
movl %r12d, %eax
imull %esi, %eax
cvtsi2ss %rax, %xmm0
movq %rsi, 0x20(%rsp)
leal (%r12,%rsi), %eax
cvtsi2ss %rax, %xmm1
movl %ecx, %ebp
movq %rdx, 0x18(%rsp)
movss %xmm0, 0x2c(%rsp)
divss %xmm1, %xmm0
callq 0x7260
cvttss2si %xmm0, %r15
movl %ebp, 0x14(%rsp)
testl %ebp, %ebp
je 0x3393b
leaq 0x7ac6(%rip), %rsi      # 0x3b3e4
movq 0x18(%rsp), %rdi
callq 0x7400
movl %r15d, %esi
movq %rax, %rdi
callq 0x72f0
movq %rax, %rdi
callq 0x71e0
movq %r15, 0x30(%rsp)
movq %r14, %rdi
callq 0x33c3a
movq %rbx, %rdi
callq 0x33c3a
movq (%r14), %r15
movq (%rbx), %rbp
movl $0x0, 0x10(%rsp)
movl $0x0, 0xc(%rsp)
xorl %r13d, %r13d
movq 0x20(%rsp), %rcx
cmpq %r14, %r15
je 0x33ab2
cmpq %rbx, %rbp
je 0x33ab2
movq 0x10(%r15), %rsi
movq 0x10(%rbp), %rax
cmpq %rax, %rsi
jne 0x339ea
cmpb $0x0, 0x14(%rsp)
je 0x339b6
movq 0x18(%rsp), %rdi
callq 0x73f0
movq %rax, %rdi
leaq 0x7a46(%rip), %rsi      # 0x3b3ee
callq 0x7400
movq 0x20(%rsp), %rcx
movq 0x10(%r15), %rsi
movslq %esi, %rax
addl %r12d, %r13d
movq (%r15), %r15
cmpq %r14, %r15
je 0x339ca
cmpq %rax, 0x10(%r15)
je 0x339b9
subl %ecx, %r13d
movq (%rbp), %rbp
cmpq %rbx, %rbp
je 0x339dc
cmpq %rax, 0x10(%rbp)
je 0x339ca
cmpl 0x10(%rsp), %r13d
jle 0x33a39
movl %r13d, 0x10(%rsp)
jmp 0x33a48
jge 0x33a19
cmpb $0x0, 0x14(%rsp)
je 0x33a02
movq 0x18(%rsp), %rdi
callq 0x73f0
movq 0x20(%rsp), %rcx
addl %r12d, %r13d
movq (%r15), %r15
movl 0x10(%rsp), %eax
cmpl %eax, %r13d
cmovgl %r13d, %eax
movl %eax, 0x10(%rsp)
jmp 0x33a48
cmpb $0x0, 0x14(%rsp)
je 0x33a32
movq 0x18(%rsp), %rdi
movq %rax, %rsi
callq 0x73f0
movq 0x20(%rsp), %rcx
subl %ecx, %r13d
movq (%rbp), %rbp
movl 0xc(%rsp), %eax
cmpl %eax, %r13d
cmovll %r13d, %eax
movl %eax, 0xc(%rsp)
cmpb $0x0, 0x14(%rsp)
je 0x3396e
movq 0x18(%rsp), %rdi
leaq 0x7995(%rip), %rsi      # 0x3b3f4
callq 0x7400
movq %rax, %rdi
movl %r13d, %esi
callq 0x7710
movq %rax, %rdi
leaq 0x797f(%rip), %rsi      # 0x3b3f8
callq 0x7400
movq %rax, %rdi
movl 0xc(%rsp), %esi
callq 0x7710
movq %rax, %rdi
leaq 0x796b(%rip), %rsi      # 0x3b3ff
callq 0x7400
movq %rax, %rdi
movl 0x10(%rsp), %esi
callq 0x7710
movq %rax, %rdi
callq 0x71e0
jmp 0x33969
movl 0xc(%rsp), %ecx
negl %ecx
movl 0x10(%rsp), %eax
cmpl %ecx, %eax
cmovgl %eax, %ecx
cvtsi2ss %ecx, %xmm0
divss 0x2c(%rsp), %xmm0
cvtss2sd %xmm0, %xmm0
movq 0x30(%rsp), %rdi
callq 0x334c7
movsd 0x298f(%rip), %xmm1     # 0x36470
subsd %xmm0, %xmm1
movapd %xmm1, %xmm0
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq