// File: PeterDenton[P]Nu-Pert/src/Linear_Fit.cpp
// Function: void Linear_Fit<double>(double (*)(double, double const*), double (*)(double, double const*), double, double, int, double*, double*, double*, double*)
void Linear_Fit(T (*x)(T t, const T *p), T (*y)(T t, const T *p), T t_min, T t_max, int n, T *p, T *m, T *b, T *rsq)
{
	T sum_x = 0;
	T sum_xsq = 0;
	T sum_y = 0;
	T sum_ysq = 0;
	T sum_xy = 0;

	T x_tmp, y_tmp;
	for (T t = t_min; t <= t_max; t += (t_max - t_min) / (n - 1))
	{
		x_tmp = x(t, p);
		y_tmp = y(t, p);
		sum_x += x_tmp;
		sum_xsq += pow(x_tmp, 2);
		sum_y += y_tmp;
		sum_ysq += pow(y_tmp, 2);
		sum_xy += x_tmp * y_tmp;
	}

	T x_bar = sum_x / n;
	T y_bar = sum_y / n;

	T ss_xx = sum_xsq - n * pow(x_bar, 2);
	T ss_yy = sum_ysq - n * pow(y_bar, 2);
	T ss_xy = sum_xy - n * x_bar * y_bar;

	*m = ss_xy / ss_xx;
	*b = y_bar - *m * x_bar;
	*rsq = pow(ss_xy, 2) / (ss_xx * ss_yy);
}

// Assembly:
subq $0xc8, %rsp
movq 0xd0(%rsp), %rax
movq %rdi, 0xc0(%rsp)
movq %rsi, 0xb8(%rsp)
movsd %xmm0, 0xb0(%rsp)
movsd %xmm1, 0xa8(%rsp)
movl %edx, 0xa4(%rsp)
movq %rcx, 0x98(%rsp)
movq %r8, 0x90(%rsp)
movq %r9, 0x88(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x80(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x78(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x70(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x68(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0xb0(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
movsd 0x48(%rsp), %xmm1
movsd 0xa8(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jb 0xc8a1
movq 0xc0(%rsp), %rax
movsd 0x48(%rsp), %xmm0
movq 0x98(%rsp), %rdi
callq *%rax
movsd %xmm0, 0x58(%rsp)
movq 0xb8(%rsp), %rax
movsd 0x48(%rsp), %xmm0
movq 0x98(%rsp), %rdi
callq *%rax
movsd %xmm0, 0x50(%rsp)
movsd 0x58(%rsp), %xmm0
addsd 0x80(%rsp), %xmm0
movsd %xmm0, 0x80(%rsp)
movsd 0x58(%rsp), %xmm0
movsd 0x57fe(%rip), %xmm1     # 0x12008
callq 0x22a0
addsd 0x78(%rsp), %xmm0
movsd %xmm0, 0x78(%rsp)
movsd 0x50(%rsp), %xmm0
addsd 0x70(%rsp), %xmm0
movsd %xmm0, 0x70(%rsp)
movsd 0x50(%rsp), %xmm0
movsd 0x57cd(%rip), %xmm1     # 0x12008
callq 0x22a0
addsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x68(%rsp)
movsd 0x58(%rsp), %xmm0
movsd 0x50(%rsp), %xmm2
movsd 0x60(%rsp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x60(%rsp)
movsd 0xa8(%rsp), %xmm0
subsd 0xb0(%rsp), %xmm0
movl 0xa4(%rsp), %eax
subl $0x1, %eax
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
addsd 0x48(%rsp), %xmm0
movsd %xmm0, 0x48(%rsp)
jmp 0xc78f
movsd 0x80(%rsp), %xmm0
cvtsi2sdl 0xa4(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x40(%rsp)
movsd 0x70(%rsp), %xmm0
cvtsi2sdl 0xa4(%rsp), %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x38(%rsp)
movsd 0x78(%rsp), %xmm0
movsd %xmm0, (%rsp)
cvtsi2sdl 0xa4(%rsp), %xmm0
movsd %xmm0, 0x8(%rsp)
movsd 0x40(%rsp), %xmm0
movsd 0x570a(%rip), %xmm1     # 0x12008
callq 0x22a0
movsd (%rsp), %xmm1
movaps %xmm0, %xmm2
movsd 0x8(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x30(%rsp)
movsd 0x68(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
cvtsi2sdl 0xa4(%rsp), %xmm0
movsd %xmm0, 0x18(%rsp)
movsd 0x38(%rsp), %xmm0
movsd 0x56a9(%rip), %xmm1     # 0x12008
callq 0x22a0
movsd 0x10(%rsp), %xmm1
movaps %xmm0, %xmm2
movsd 0x18(%rsp), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x28(%rsp)
movsd 0x60(%rsp), %xmm1
cvtsi2sdl 0xa4(%rsp), %xmm0
mulsd 0x40(%rsp), %xmm0
movsd 0x38(%rsp), %xmm2
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x20(%rsp)
movsd 0x20(%rsp), %xmm0
divsd 0x30(%rsp), %xmm0
movq 0x90(%rsp), %rax
movsd %xmm0, (%rax)
movsd 0x38(%rsp), %xmm1
movq 0x90(%rsp), %rax
movsd (%rax), %xmm0
movsd 0x40(%rsp), %xmm2
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movq 0x88(%rsp), %rax
movsd %xmm0, (%rax)
movsd 0x20(%rsp), %xmm0
movsd 0x55c7(%rip), %xmm1     # 0x12008
callq 0x22a0
movsd 0x30(%rsp), %xmm1
mulsd 0x28(%rsp), %xmm1
divsd %xmm1, %xmm0
movq 0xd0(%rsp), %rax
movsd %xmm0, (%rax)
addq $0xc8, %rsp
retq
nop
nopl (%rax)